summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2009-04-06 10:19:36 -0700
committerGabe Black <gblack@eecs.umich.edu>2009-04-06 10:19:36 -0700
commitd080581db1f9ee4e1e6d07d2b01c13c67908a391 (patch)
treecc484b289fa5a30c4631f9faa1d8b456bffeebfc /src
parent7a7c4c5fca83a8d47c7e71c9c080a882ebe204a9 (diff)
parent639cb0a42d953ee32bc7e96b0cdfa96cd40e9fc1 (diff)
downloadgem5-d080581db1f9ee4e1e6d07d2b01c13c67908a391.tar.xz
Merge ARM into the head. ARM will compile but may not actually work.
Diffstat (limited to 'src')
-rw-r--r--src/SConscript809
-rw-r--r--src/arch/SConscript7
-rw-r--r--src/arch/alpha/AlphaInterrupts.py33
-rw-r--r--src/arch/alpha/AlphaTLB.py13
-rw-r--r--src/arch/alpha/SConscript2
-rw-r--r--src/arch/alpha/SConsopts2
-rw-r--r--src/arch/alpha/aout_machdep.h42
-rw-r--r--src/arch/alpha/ev5.cc383
-rw-r--r--src/arch/alpha/ev5.hh25
-rw-r--r--src/arch/alpha/faults.cc60
-rw-r--r--src/arch/alpha/faults.hh75
-rw-r--r--src/arch/alpha/floatregfile.cc30
-rw-r--r--src/arch/alpha/floatregfile.hh41
-rw-r--r--src/arch/alpha/freebsd/system.cc8
-rw-r--r--src/arch/alpha/freebsd/system.hh1
-rw-r--r--src/arch/alpha/idle_event.cc9
-rw-r--r--[-rwxr-xr-x]src/arch/alpha/interrupts.cc (renamed from src/cpu/o3/sparc/thread_context.cc)12
-rw-r--r--src/arch/alpha/interrupts.hh239
-rw-r--r--src/arch/alpha/intregfile.cc53
-rw-r--r--src/arch/alpha/intregfile.hh57
-rw-r--r--src/arch/alpha/ipr.cc210
-rw-r--r--src/arch/alpha/ipr.hh402
-rw-r--r--src/arch/alpha/isa/decoder.isa122
-rw-r--r--src/arch/alpha/isa/fp.isa4
-rw-r--r--src/arch/alpha/isa/main.isa9
-rw-r--r--src/arch/alpha/isa/mem.isa5
-rw-r--r--src/arch/alpha/isa/pal.isa10
-rw-r--r--src/arch/alpha/isa_traits.hh254
-rw-r--r--src/arch/alpha/kernel_stats.cc6
-rw-r--r--src/arch/alpha/kernel_stats.hh16
-rw-r--r--src/arch/alpha/linux/linux.cc49
-rw-r--r--src/arch/alpha/linux/linux.hh50
-rw-r--r--src/arch/alpha/linux/process.cc36
-rw-r--r--src/arch/alpha/linux/process.hh1
-rw-r--r--src/arch/alpha/linux/system.cc3
-rw-r--r--src/arch/alpha/linux/system.hh12
-rw-r--r--src/arch/alpha/linux/threadinfo.hh6
-rw-r--r--src/arch/alpha/locked_mem.hh10
-rw-r--r--src/arch/alpha/microcode_rom.hh41
-rw-r--r--src/arch/alpha/miscregfile.cc208
-rw-r--r--src/arch/alpha/miscregfile.hh116
-rw-r--r--src/arch/alpha/mmaped_ipr.hh5
-rw-r--r--src/arch/alpha/osfpal.cc522
-rw-r--r--src/arch/alpha/osfpal.hh6
-rw-r--r--src/arch/alpha/pagetable.cc55
-rw-r--r--src/arch/alpha/pagetable.hh186
-rw-r--r--src/arch/alpha/predecoder.hh114
-rw-r--r--src/arch/alpha/process.cc165
-rw-r--r--src/arch/alpha/process.hh22
-rw-r--r--src/arch/alpha/regfile.cc103
-rw-r--r--src/arch/alpha/regfile.hh270
-rw-r--r--src/arch/alpha/remote_gdb.cc101
-rw-r--r--src/arch/alpha/remote_gdb.hh40
-rw-r--r--src/arch/alpha/stacktrace.cc516
-rw-r--r--src/arch/alpha/stacktrace.hh128
-rw-r--r--src/arch/alpha/system.cc25
-rw-r--r--src/arch/alpha/system.hh16
-rw-r--r--src/arch/alpha/tlb.cc102
-rw-r--r--src/arch/alpha/tlb.hh212
-rw-r--r--src/arch/alpha/tru64/process.cc68
-rw-r--r--src/arch/alpha/tru64/process.hh9
-rw-r--r--src/arch/alpha/tru64/tru64.cc40
-rw-r--r--src/arch/alpha/tru64/tru64.hh53
-rw-r--r--src/arch/alpha/types.hh62
-rw-r--r--src/arch/alpha/utility.cc16
-rw-r--r--src/arch/alpha/utility.hh232
-rw-r--r--src/arch/alpha/vtophys.cc36
-rw-r--r--src/arch/alpha/vtophys.hh11
-rw-r--r--src/arch/arm/ArmTLB.py12
-rw-r--r--src/arch/arm/isa_traits.hh3
-rw-r--r--src/arch/arm/linux/process.cc6
-rw-r--r--src/arch/arm/process.cc36
-rw-r--r--src/arch/arm/process.hh3
-rw-r--r--src/arch/arm/regfile/regfile.cc4
-rw-r--r--src/arch/arm/regfile/regfile.hh9
-rw-r--r--src/arch/arm/tlb.cc24
-rw-r--r--src/arch/arm/tlb.hh39
-rwxr-xr-xsrc/arch/isa_parser.py10
-rw-r--r--src/arch/isa_specific.hh2
-rw-r--r--src/arch/micro_asm.py7
-rw-r--r--src/arch/mips/MipsInterrupts.py33
-rw-r--r--src/arch/mips/MipsTLB.py17
-rw-r--r--src/arch/mips/SConscript1
-rwxr-xr-xsrc/arch/mips/bare_iron/system.hh2
-rwxr-xr-xsrc/arch/mips/dsp.cc989
-rwxr-xr-xsrc/arch/mips/dsp.hh285
-rw-r--r--src/arch/mips/idle_event.cc2
-rwxr-xr-xsrc/arch/mips/interrupts.cc18
-rwxr-xr-xsrc/arch/mips/interrupts.hh32
-rw-r--r--src/arch/mips/isa/decoder.isa32
-rw-r--r--src/arch/mips/isa/formats/mem.isa6
-rw-r--r--src/arch/mips/isa/formats/mt.isa4
-rw-r--r--src/arch/mips/isa/formats/util.isa1
-rw-r--r--src/arch/mips/isa_traits.hh28
-rw-r--r--src/arch/mips/linux/linux.cc40
-rw-r--r--src/arch/mips/linux/linux.hh61
-rw-r--r--src/arch/mips/linux/process.cc32
-rw-r--r--src/arch/mips/linux/system.cc1
-rw-r--r--src/arch/mips/linux/system.hh5
-rw-r--r--src/arch/mips/linux/threadinfo.hh4
-rw-r--r--src/arch/mips/locked_mem.hh23
-rw-r--r--src/arch/mips/microcode_rom.hh41
-rwxr-xr-xsrc/arch/mips/mips_core_specific.cc4
-rwxr-xr-xsrc/arch/mips/mt.hh13
-rwxr-xr-xsrc/arch/mips/pagetable.hh4
-rw-r--r--src/arch/mips/process.cc34
-rw-r--r--src/arch/mips/process.hh4
-rw-r--r--src/arch/mips/regfile.cc12
-rw-r--r--src/arch/mips/regfile/float_regfile.hh5
-rw-r--r--src/arch/mips/regfile/int_regfile.cc51
-rw-r--r--src/arch/mips/regfile/int_regfile.hh8
-rw-r--r--[-rwxr-xr-x]src/arch/mips/regfile/misc_regfile.cc261
-rw-r--r--src/arch/mips/regfile/misc_regfile.hh8
-rw-r--r--src/arch/mips/regfile/regfile.cc5
-rw-r--r--src/arch/mips/regfile/regfile.hh24
-rw-r--r--src/arch/mips/stacktrace.cc6
-rw-r--r--src/arch/mips/stacktrace.hh2
-rwxr-xr-xsrc/arch/mips/system.cc8
-rw-r--r--src/arch/mips/tlb.cc54
-rw-r--r--src/arch/mips/tlb.hh36
-rw-r--r--src/arch/mips/types.hh3
-rw-r--r--src/arch/mips/utility.cc7
-rw-r--r--src/arch/sparc/SConscript5
-rw-r--r--src/arch/sparc/SparcInterrupts.py33
-rw-r--r--src/arch/sparc/SparcTLB.py13
-rw-r--r--src/arch/sparc/faults.cc2
-rw-r--r--src/arch/sparc/floatregfile.cc38
-rw-r--r--src/arch/sparc/floatregfile.hh2
-rw-r--r--[-rwxr-xr-x]src/arch/sparc/interrupts.cc (renamed from src/cpu/o3/mips/thread_context.cc)17
-rw-r--r--src/arch/sparc/interrupts.hh59
-rw-r--r--src/arch/sparc/intregfile.cc102
-rw-r--r--src/arch/sparc/intregfile.hh44
-rw-r--r--src/arch/sparc/isa/decoder.isa18
-rw-r--r--src/arch/sparc/isa/formats/mem/basicmem.isa10
-rw-r--r--src/arch/sparc/isa/formats/mem/swap.isa3
-rw-r--r--src/arch/sparc/isa/formats/mem/util.isa23
-rw-r--r--src/arch/sparc/isa_traits.hh10
-rw-r--r--src/arch/sparc/linux/linux.cc40
-rw-r--r--src/arch/sparc/linux/linux.hh30
-rw-r--r--src/arch/sparc/linux/process.cc4
-rw-r--r--src/arch/sparc/linux/process.hh1
-rw-r--r--src/arch/sparc/linux/syscalls.cc27
-rw-r--r--src/arch/sparc/microcode_rom.hh41
-rw-r--r--src/arch/sparc/miscregfile.cc57
-rw-r--r--src/arch/sparc/miscregfile.hh64
-rw-r--r--src/arch/sparc/pagetable.hh127
-rw-r--r--src/arch/sparc/process.cc145
-rw-r--r--src/arch/sparc/process.hh27
-rw-r--r--src/arch/sparc/regfile.cc33
-rw-r--r--src/arch/sparc/regfile.hh19
-rw-r--r--src/arch/sparc/remote_gdb.cc28
-rw-r--r--src/arch/sparc/solaris/process.cc10
-rw-r--r--src/arch/sparc/solaris/solaris.cc52
-rw-r--r--src/arch/sparc/solaris/solaris.hh20
-rw-r--r--src/arch/sparc/sparc_traits.hh4
-rw-r--r--src/arch/sparc/stacktrace.cc6
-rw-r--r--src/arch/sparc/stacktrace.hh2
-rw-r--r--src/arch/sparc/syscallreturn.hh64
-rw-r--r--src/arch/sparc/tlb.cc165
-rw-r--r--src/arch/sparc/tlb.hh15
-rw-r--r--src/arch/sparc/tlb_map.hh3
-rw-r--r--src/arch/sparc/types.hh8
-rw-r--r--src/arch/sparc/ua2005.cc115
-rw-r--r--src/arch/sparc/utility.cc6
-rw-r--r--src/arch/sparc/vtophys.cc162
-rw-r--r--src/arch/x86/SConscript16
-rw-r--r--src/arch/x86/SConsopts45
-rw-r--r--src/arch/x86/X86LocalApic.py36
-rw-r--r--src/arch/x86/X86System.py19
-rw-r--r--src/arch/x86/X86TLB.py17
-rw-r--r--src/arch/x86/apicregs.hh (renamed from src/cpu/o3/sparc/thread_context.hh)85
-rw-r--r--src/arch/x86/bios/ACPI.py99
-rw-r--r--src/arch/x86/bios/E820.py71
-rw-r--r--src/arch/x86/bios/IntelMP.py242
-rw-r--r--src/arch/x86/bios/SConscript77
-rw-r--r--src/arch/x86/bios/SMBios.py140
-rw-r--r--src/arch/x86/bios/acpi.cc109
-rw-r--r--src/arch/x86/bios/acpi.hh147
-rw-r--r--src/arch/x86/bios/e820.cc103
-rw-r--r--src/arch/x86/bios/e820.hh (renamed from src/arch/x86/syscallreturn.hh)48
-rw-r--r--src/arch/x86/bios/intelmp.cc476
-rw-r--r--src/arch/x86/bios/intelmp.hh330
-rw-r--r--src/arch/x86/bios/smbios.cc (renamed from src/arch/x86/smbios.cc)154
-rw-r--r--src/arch/x86/bios/smbios.hh (renamed from src/arch/x86/smbios.hh)118
-rw-r--r--src/arch/x86/cpuid.cc160
-rw-r--r--src/arch/x86/cpuid.hh61
-rw-r--r--src/arch/x86/emulenv.cc12
-rw-r--r--src/arch/x86/emulenv.hh1
-rw-r--r--src/arch/x86/faults.cc112
-rw-r--r--src/arch/x86/faults.hh168
-rw-r--r--src/arch/x86/floatregfile.cc17
-rw-r--r--src/arch/x86/floatregfile.hh2
-rw-r--r--src/arch/x86/insts/macroop.hh121
-rw-r--r--src/arch/x86/insts/microldstop.cc29
-rw-r--r--src/arch/x86/insts/microldstop.hh33
-rw-r--r--src/arch/x86/insts/microop.cc4
-rw-r--r--src/arch/x86/insts/microregop.cc3
-rw-r--r--src/arch/x86/insts/static_inst.cc42
-rw-r--r--src/arch/x86/insts/static_inst.hh3
-rw-r--r--src/arch/x86/interrupts.cc569
-rw-r--r--src/arch/x86/interrupts.hh253
-rw-r--r--src/arch/x86/intmessage.hh110
-rw-r--r--src/arch/x86/intregfile.cc17
-rw-r--r--src/arch/x86/intregfile.hh3
-rw-r--r--src/arch/x86/isa/decoder/one_byte_opcodes.isa23
-rw-r--r--src/arch/x86/isa/decoder/two_byte_opcodes.isa187
-rw-r--r--src/arch/x86/isa/formats/basic.isa8
-rw-r--r--src/arch/x86/isa/formats/cpuid.isa110
-rw-r--r--src/arch/x86/isa/formats/formats.isa3
-rw-r--r--src/arch/x86/isa/includes.isa9
-rw-r--r--src/arch/x86/isa/insts/__init__.py3
-rw-r--r--src/arch/x86/isa/insts/general_purpose/__init__.py1
-rw-r--r--src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py24
-rw-r--r--src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py40
-rw-r--r--src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py153
-rw-r--r--src/arch/x86/isa/insts/general_purpose/control_transfer/call.py2
-rw-r--r--src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py198
-rw-r--r--src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py23
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py8
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py4
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py22
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py4
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py2
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_transfer/move.py148
-rw-r--r--src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py106
-rw-r--r--src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py14
-rw-r--r--src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py22
-rw-r--r--src/arch/x86/isa/insts/general_purpose/input_output/general_io.py18
-rw-r--r--src/arch/x86/isa/insts/general_purpose/input_output/string_io.py32
-rw-r--r--src/arch/x86/isa/insts/general_purpose/load_segment_registers.py14
-rw-r--r--src/arch/x86/isa/insts/general_purpose/processor_information.py405
-rw-r--r--src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py89
-rw-r--r--src/arch/x86/isa/insts/general_purpose/semaphores.py26
-rw-r--r--src/arch/x86/isa/insts/general_purpose/string/compare_strings.py16
-rw-r--r--src/arch/x86/isa/insts/general_purpose/string/load_string.py15
-rw-r--r--src/arch/x86/isa/insts/general_purpose/string/move_string.py7
-rw-r--r--src/arch/x86/isa/insts/general_purpose/string/scan_string.py16
-rw-r--r--src/arch/x86/isa/insts/general_purpose/string/store_string.py7
-rw-r--r--src/arch/x86/isa/insts/general_purpose/system_calls.py183
-rw-r--r--src/arch/x86/isa/insts/romutil.py212
-rw-r--r--src/arch/x86/isa/insts/system/__init__.py3
-rw-r--r--src/arch/x86/isa/insts/system/control_registers.py35
-rw-r--r--src/arch/x86/isa/insts/system/msrs.py16
-rw-r--r--src/arch/x86/isa/insts/system/segmentation.py131
-rw-r--r--src/arch/x86/isa/macroop.isa122
-rw-r--r--src/arch/x86/isa/microasm.isa49
-rw-r--r--src/arch/x86/isa/microops/base.isa31
-rw-r--r--src/arch/x86/isa/microops/debug.isa229
-rw-r--r--src/arch/x86/isa/microops/fpop.isa2
-rw-r--r--src/arch/x86/isa/microops/ldstop.isa145
-rw-r--r--src/arch/x86/isa/microops/limmop.isa2
-rw-r--r--src/arch/x86/isa/microops/microops.isa8
-rw-r--r--src/arch/x86/isa/microops/regop.isa323
-rw-r--r--src/arch/x86/isa/microops/seqop.isa251
-rw-r--r--src/arch/x86/isa/microops/specop.isa19
-rw-r--r--src/arch/x86/isa/operands.isa54
-rw-r--r--src/arch/x86/isa/rom.isa90
-rw-r--r--src/arch/x86/isa/specialize.isa46
-rw-r--r--src/arch/x86/isa_traits.hh12
-rw-r--r--src/arch/x86/linux/linux.cc39
-rw-r--r--src/arch/x86/linux/linux.hh81
-rw-r--r--src/arch/x86/linux/process.cc30
-rw-r--r--src/arch/x86/linux/process.hh22
-rw-r--r--src/arch/x86/linux/syscalls.cc444
-rw-r--r--src/arch/x86/linux/system.cc61
-rw-r--r--src/arch/x86/linux/system.hh4
-rw-r--r--src/arch/x86/microcode_rom.hh74
-rw-r--r--src/arch/x86/miscregfile.cc289
-rw-r--r--src/arch/x86/miscregfile.hh13
-rw-r--r--src/arch/x86/miscregs.hh117
-rw-r--r--src/arch/x86/mmaped_ipr.hh30
-rw-r--r--src/arch/x86/pagetable.hh6
-rw-r--r--src/arch/x86/pagetable_walker.cc249
-rw-r--r--src/arch/x86/pagetable_walker.hh31
-rw-r--r--src/arch/x86/predecoder.cc45
-rw-r--r--src/arch/x86/predecoder.hh2
-rw-r--r--src/arch/x86/predecoder_tables.cc6
-rw-r--r--src/arch/x86/process.cc324
-rw-r--r--src/arch/x86/process.hh72
-rw-r--r--src/arch/x86/regfile.cc21
-rw-r--r--src/arch/x86/regfile.hh10
-rw-r--r--src/arch/x86/remote_gdb.cc18
-rw-r--r--src/arch/x86/stacktrace.cc4
-rw-r--r--src/arch/x86/system.cc78
-rw-r--r--src/arch/x86/system.hh14
-rw-r--r--src/arch/x86/tlb.cc355
-rw-r--r--src/arch/x86/tlb.hh21
-rw-r--r--src/arch/x86/types.hh11
-rw-r--r--src/arch/x86/utility.cc16
-rw-r--r--src/arch/x86/utility.hh7
-rw-r--r--src/arch/x86/x86_traits.hh37
-rw-r--r--src/base/CPA.py8
-rw-r--r--src/base/SConscript38
-rw-r--r--src/base/annotate.cc122
-rw-r--r--src/base/atomicio.cc (renamed from src/unittest/offtest.cc)96
-rw-r--r--src/base/atomicio.hh44
-rw-r--r--src/base/bitunion.hh14
-rw-r--r--src/base/cast.hh68
-rw-r--r--src/base/chunk_generator.hh1
-rw-r--r--src/base/circlebuf.cc33
-rw-r--r--src/base/cp_annotate.cc1404
-rw-r--r--src/base/cp_annotate.hh522
-rw-r--r--src/base/cprintf.cc17
-rw-r--r--src/base/cprintf.hh35
-rw-r--r--src/base/cprintf_formats.hh7
-rw-r--r--src/base/crc.cc6
-rw-r--r--src/base/debug.cc (renamed from src/unittest/tracetest.cc)33
-rw-r--r--src/base/debug.hh (renamed from src/python/swig/init.hh)10
-rw-r--r--src/base/fast_alloc.cc38
-rw-r--r--src/base/fast_alloc.hh73
-rw-r--r--src/base/flags.hh79
-rw-r--r--src/base/hashmap.hh10
-rw-r--r--src/base/hybrid_pred.hh12
-rw-r--r--src/base/inet.cc21
-rw-r--r--src/base/inet.hh112
-rw-r--r--src/base/inifile.cc111
-rw-r--r--src/base/inifile.hh16
-rw-r--r--src/base/intmath.hh6
-rw-r--r--src/base/loader/aout_object.cc2
-rw-r--r--src/base/loader/coff_sym.h354
-rw-r--r--src/base/loader/coff_symconst.h220
-rw-r--r--src/base/loader/ecoff_object.cc2
-rw-r--r--src/base/loader/elf_object.cc21
-rwxr-xr-xsrc/base/loader/hex_file.cc163
-rwxr-xr-xsrc/base/loader/hex_file.hh37
-rw-r--r--src/base/loader/object_file.hh5
-rw-r--r--src/base/loader/symtab.hh3
-rw-r--r--src/base/misc.cc96
-rw-r--r--src/base/misc.hh147
-rw-r--r--src/base/output.cc83
-rw-r--r--src/base/output.hh12
-rw-r--r--src/base/random_mt.cc6
-rw-r--r--src/base/range_map.hh70
-rw-r--r--src/base/remote_gdb.cc38
-rw-r--r--src/base/res_list.hh2
-rw-r--r--src/base/sat_counter.hh12
-rw-r--r--src/base/socket.cc18
-rw-r--r--src/base/socket.hh8
-rw-r--r--src/base/statistics.cc257
-rw-r--r--src/base/statistics.hh1838
-rw-r--r--src/base/stats/events.cc2
-rw-r--r--src/base/stats/flags.hh23
-rw-r--r--src/base/stats/mysql.cc250
-rw-r--r--src/base/stats/mysql.hh73
-rw-r--r--src/base/stats/mysql_run.hh8
-rw-r--r--src/base/stats/output.cc3
-rw-r--r--src/base/stats/text.cc314
-rw-r--r--src/base/stats/text.hh14
-rw-r--r--src/base/stats/types.hh7
-rw-r--r--src/base/stats/visit.hh28
-rw-r--r--src/base/str.cc15
-rw-r--r--src/base/time.cc6
-rw-r--r--src/base/time.hh4
-rw-r--r--src/base/timebuf.hh13
-rw-r--r--src/base/trace.hh9
-rw-r--r--src/base/varargs.hh20
-rw-r--r--src/cpu/BaseCPU.py53
-rw-r--r--src/cpu/CheckerCPU.py42
-rw-r--r--src/cpu/ExeTracer.py3
-rw-r--r--src/cpu/IntelTrace.py3
-rw-r--r--src/cpu/LegionTrace.py3
-rw-r--r--src/cpu/NativeTrace.py3
-rw-r--r--src/cpu/SConscript15
-rw-r--r--src/cpu/activity.cc13
-rw-r--r--src/cpu/activity.hh10
-rw-r--r--src/cpu/base.cc212
-rw-r--r--src/cpu/base.hh100
-rw-r--r--src/cpu/base_dyn_inst.hh98
-rw-r--r--src/cpu/base_dyn_inst_impl.hh24
-rw-r--r--src/cpu/checker/cpu.cc55
-rw-r--r--src/cpu/checker/cpu.hh23
-rw-r--r--src/cpu/checker/cpu_impl.hh9
-rw-r--r--src/cpu/checker/thread_context.hh29
-rw-r--r--src/cpu/cpu_models.py3
-rw-r--r--src/cpu/cpuevent.hh9
-rw-r--r--src/cpu/exetrace.cc82
-rw-r--r--src/cpu/exetrace.hh14
-rw-r--r--src/cpu/inorder/InOrderCPU.py79
-rw-r--r--src/cpu/inorder/InOrderTrace.py35
-rw-r--r--src/cpu/inorder/SConscript90
-rw-r--r--src/cpu/inorder/SConsopts33
-rw-r--r--src/cpu/inorder/comm.hh112
-rw-r--r--src/cpu/inorder/cpu.cc1253
-rw-r--r--src/cpu/inorder/cpu.hh680
-rw-r--r--src/cpu/inorder/first_stage.cc248
-rw-r--r--src/cpu/inorder/first_stage.hh97
-rw-r--r--src/cpu/inorder/inorder_cpu_builder.cc60
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.cc724
-rw-r--r--src/cpu/inorder/inorder_dyn_inst.hh971
-rw-r--r--src/cpu/inorder/inorder_trace.cc (renamed from src/dev/pitreg.h)89
-rw-r--r--src/cpu/inorder/inorder_trace.hh98
-rw-r--r--[-rwxr-xr-x]src/cpu/inorder/params.hh (renamed from src/cpu/o3/params.hh)148
-rw-r--r--src/cpu/inorder/pipeline_stage.cc1021
-rw-r--r--src/cpu/inorder/pipeline_stage.hh358
-rw-r--r--src/cpu/inorder/pipeline_traits.5stage.cc166
-rw-r--r--src/cpu/inorder/pipeline_traits.5stage.hh147
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.cc242
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.hh155
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.smt2.cc240
-rw-r--r--src/cpu/inorder/pipeline_traits.9stage.smt2.hh155
-rw-r--r--src/cpu/inorder/pipeline_traits.cc153
-rw-r--r--src/cpu/inorder/pipeline_traits.hh170
-rw-r--r--src/cpu/inorder/reg_dep_map.cc236
-rw-r--r--src/cpu/inorder/reg_dep_map.hh105
-rw-r--r--src/cpu/inorder/resource.cc434
-rw-r--r--src/cpu/inorder/resource.hh401
-rw-r--r--src/cpu/inorder/resource_pool.9stage.cc357
-rw-r--r--src/cpu/inorder/resource_pool.cc364
-rw-r--r--src/cpu/inorder/resource_pool.hh189
-rw-r--r--src/cpu/inorder/resources/agen_unit.cc98
-rw-r--r--src/cpu/inorder/resources/agen_unit.hh (renamed from src/base/annotate.hh)59
-rw-r--r--src/cpu/inorder/resources/bpred_unit.cc426
-rw-r--r--src/cpu/inorder/resources/bpred_unit.hh258
-rw-r--r--src/cpu/inorder/resources/branch_predictor.cc149
-rw-r--r--src/cpu/inorder/resources/branch_predictor.hh (renamed from src/dev/x86/opteron.cc)111
-rw-r--r--src/cpu/inorder/resources/cache_unit.cc604
-rw-r--r--src/cpu/inorder/resources/cache_unit.hh315
-rw-r--r--src/cpu/inorder/resources/decode_unit.cc92
-rw-r--r--src/cpu/inorder/resources/decode_unit.hh68
-rw-r--r--src/cpu/inorder/resources/execution_unit.cc182
-rw-r--r--src/cpu/inorder/resources/execution_unit.hh77
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.cc323
-rw-r--r--src/cpu/inorder/resources/fetch_seq_unit.hh117
-rw-r--r--src/cpu/inorder/resources/graduation_unit.cc112
-rw-r--r--src/cpu/inorder/resources/graduation_unit.hh (renamed from src/cpu/o3/alpha/params.hh)65
-rw-r--r--src/cpu/inorder/resources/inst_buffer.cc222
-rw-r--r--src/cpu/inorder/resources/inst_buffer.hh93
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.cc156
-rw-r--r--src/cpu/inorder/resources/inst_buffer_new.hh109
-rw-r--r--src/cpu/inorder/resources/mem_dep_unit.hh (renamed from src/base/stats/statdb.hh)56
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.cc285
-rw-r--r--src/cpu/inorder/resources/mult_div_unit.hh138
-rw-r--r--src/cpu/inorder/resources/resource_list.hh (renamed from src/arch/mips/syscallreturn.hh)38
-rw-r--r--src/cpu/inorder/resources/tlb_unit.cc188
-rw-r--r--src/cpu/inorder/resources/tlb_unit.hh124
-rw-r--r--src/cpu/inorder/resources/use_def.cc326
-rw-r--r--src/cpu/inorder/resources/use_def.hh102
-rw-r--r--src/cpu/inorder/thread_context.cc264
-rw-r--r--src/cpu/inorder/thread_context.hh275
-rw-r--r--src/cpu/inorder/thread_state.hh90
-rw-r--r--src/cpu/inteltrace.hh11
-rw-r--r--src/cpu/intr_control.cc4
-rw-r--r--src/cpu/legiontrace.hh11
-rw-r--r--src/cpu/memtest/memtest.cc15
-rw-r--r--src/cpu/memtest/memtest.hh29
-rw-r--r--src/cpu/nativetrace.cc6
-rw-r--r--src/cpu/nativetrace.hh12
-rw-r--r--src/cpu/o3/O3CPU.py6
-rw-r--r--src/cpu/o3/O3Checker.py2
-rwxr-xr-xsrc/cpu/o3/SConscript21
-rw-r--r--src/cpu/o3/alpha/cpu.cc38
-rw-r--r--src/cpu/o3/alpha/cpu.hh149
-rw-r--r--src/cpu/o3/alpha/cpu_builder.cc199
-rw-r--r--src/cpu/o3/alpha/cpu_impl.hh314
-rw-r--r--src/cpu/o3/alpha/dyn_inst.cc36
-rw-r--r--src/cpu/o3/alpha/dyn_inst.hh277
-rw-r--r--src/cpu/o3/alpha/impl.hh92
-rw-r--r--src/cpu/o3/base_dyn_inst.cc5
-rw-r--r--src/cpu/o3/bpred_unit.hh25
-rw-r--r--src/cpu/o3/bpred_unit_impl.hh27
-rw-r--r--src/cpu/o3/commit.hh33
-rw-r--r--src/cpu/o3/commit_impl.hh31
-rw-r--r--src/cpu/o3/cpu.cc297
-rw-r--r--src/cpu/o3/cpu.hh148
-rw-r--r--src/cpu/o3/cpu_builder.cc (renamed from src/cpu/o3/alpha/thread_context.hh)72
-rw-r--r--src/cpu/o3/cpu_policy.hh12
-rw-r--r--src/cpu/o3/decode.hh25
-rw-r--r--src/cpu/o3/decode_impl.hh6
-rw-r--r--src/cpu/o3/dyn_inst.cc (renamed from src/cpu/o3/sparc/dyn_inst.cc)8
-rw-r--r--src/cpu/o3/dyn_inst.hh282
-rw-r--r--src/cpu/o3/dyn_inst_impl.hh (renamed from src/cpu/o3/alpha/dyn_inst_impl.hh)63
-rw-r--r--src/cpu/o3/fetch.hh31
-rw-r--r--src/cpu/o3/fetch_impl.hh17
-rw-r--r--src/cpu/o3/iew.hh61
-rw-r--r--src/cpu/o3/iew_impl.hh5
-rw-r--r--src/cpu/o3/impl.hh (renamed from src/cpu/o3/sparc/impl.hh)27
-rw-r--r--src/cpu/o3/inst_queue.hh43
-rw-r--r--src/cpu/o3/inst_queue_impl.hh15
-rwxr-xr-xsrc/cpu/o3/isa_specific.hh20
-rw-r--r--src/cpu/o3/lsq.hh11
-rw-r--r--src/cpu/o3/lsq_impl.hh23
-rw-r--r--src/cpu/o3/lsq_unit.hh33
-rw-r--r--src/cpu/o3/lsq_unit_impl.hh9
-rw-r--r--src/cpu/o3/mem_dep_unit.hh23
-rw-r--r--src/cpu/o3/mem_dep_unit_impl.hh25
-rwxr-xr-xsrc/cpu/o3/mips/cpu.cc39
-rwxr-xr-xsrc/cpu/o3/mips/cpu.hh130
-rw-r--r--src/cpu/o3/mips/cpu_builder.cc182
-rw-r--r--src/cpu/o3/mips/cpu_impl.hh217
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst.cc37
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst.hh281
-rwxr-xr-xsrc/cpu/o3/mips/dyn_inst_impl.hh130
-rw-r--r--src/cpu/o3/mips/impl.hh93
-rw-r--r--src/cpu/o3/mips/params.hh64
-rw-r--r--src/cpu/o3/ras.hh3
-rw-r--r--src/cpu/o3/regfile.hh3
-rw-r--r--src/cpu/o3/rename.hh43
-rw-r--r--src/cpu/o3/rename_impl.hh5
-rw-r--r--src/cpu/o3/sparc/cpu.hh148
-rw-r--r--src/cpu/o3/sparc/cpu_builder.cc200
-rw-r--r--src/cpu/o3/sparc/cpu_impl.hh298
-rw-r--r--src/cpu/o3/sparc/dyn_inst.hh265
-rw-r--r--src/cpu/o3/sparc/dyn_inst_impl.hh154
-rwxr-xr-xsrc/cpu/o3/thread_context.cc (renamed from src/cpu/o3/alpha/thread_context.cc)4
-rwxr-xr-xsrc/cpu/o3/thread_context.hh82
-rwxr-xr-xsrc/cpu/o3/thread_context_impl.hh134
-rw-r--r--src/cpu/o3/thread_state.hh8
-rw-r--r--src/cpu/ozone/OzoneCPU.py2
-rw-r--r--src/cpu/ozone/OzoneChecker.py2
-rw-r--r--src/cpu/ozone/back_end.hh100
-rw-r--r--src/cpu/ozone/base_dyn_inst.cc4
-rw-r--r--src/cpu/ozone/cpu.hh96
-rw-r--r--src/cpu/ozone/cpu_impl.hh72
-rw-r--r--src/cpu/ozone/front_end.hh40
-rw-r--r--src/cpu/ozone/front_end_impl.hh4
-rw-r--r--src/cpu/ozone/inorder_back_end.hh16
-rw-r--r--src/cpu/ozone/inorder_back_end_impl.hh3
-rw-r--r--src/cpu/ozone/inst_queue.hh32
-rw-r--r--src/cpu/ozone/lsq_unit.hh2
-rw-r--r--src/cpu/ozone/lsq_unit_impl.hh2
-rw-r--r--src/cpu/ozone/lw_back_end.hh84
-rw-r--r--src/cpu/ozone/lw_back_end_impl.hh5
-rw-r--r--src/cpu/ozone/lw_lsq.hh7
-rw-r--r--src/cpu/pc_event.cc2
-rw-r--r--src/cpu/quiesce_event.cc2
-rw-r--r--src/cpu/simple/AtomicSimpleCPU.py13
-rw-r--r--src/cpu/simple/BaseSimpleCPU.py34
-rw-r--r--src/cpu/simple/SConscript1
-rw-r--r--src/cpu/simple/TimingSimpleCPU.py10
-rw-r--r--src/cpu/simple/atomic.cc280
-rw-r--r--src/cpu/simple/atomic.hh29
-rw-r--r--src/cpu/simple/base.cc71
-rw-r--r--src/cpu/simple/base.hh49
-rw-r--r--src/cpu/simple/timing.cc606
-rw-r--r--src/cpu/simple/timing.hh195
-rw-r--r--src/cpu/simple_thread.cc65
-rw-r--r--src/cpu/simple_thread.hh61
-rw-r--r--src/cpu/static_inst.cc43
-rw-r--r--src/cpu/static_inst.hh172
-rw-r--r--src/cpu/thread_context.cc11
-rw-r--r--src/cpu/thread_context.hh69
-rw-r--r--src/cpu/thread_state.cc24
-rw-r--r--src/cpu/thread_state.hh37
-rw-r--r--src/dev/CopyEngine.py59
-rw-r--r--src/dev/DiskImage.py1
-rw-r--r--src/dev/Ethernet.py30
-rw-r--r--src/dev/Pci.py6
-rw-r--r--src/dev/SConscript18
-rw-r--r--src/dev/Terminal.py (renamed from src/dev/SimConsole.py)9
-rw-r--r--src/dev/Uart.py2
-rw-r--r--src/dev/alpha/AlphaBackdoor.py (renamed from src/dev/alpha/AlphaConsole.py)6
-rw-r--r--src/dev/alpha/SConscript7
-rw-r--r--src/dev/alpha/Tsunami.py10
-rw-r--r--src/dev/alpha/access.h34
-rw-r--r--src/dev/alpha/backdoor.cc (renamed from src/dev/alpha/console.cc)42
-rw-r--r--src/dev/alpha/backdoor.hh (renamed from src/dev/alpha/console.hh)22
-rw-r--r--src/dev/alpha/tsunami.cc16
-rw-r--r--src/dev/alpha/tsunami.hh12
-rw-r--r--src/dev/alpha/tsunami_cchip.cc10
-rw-r--r--src/dev/alpha/tsunami_io.cc404
-rw-r--r--src/dev/alpha/tsunami_io.hh228
-rw-r--r--src/dev/alpha/tsunami_pchip.cc11
-rw-r--r--src/dev/alpha/tsunami_pchip.hh2
-rw-r--r--src/dev/copy_engine.cc764
-rw-r--r--src/dev/copy_engine.hh199
-rw-r--r--src/dev/copy_engine_defs.hh225
-rw-r--r--src/dev/etherbus.cc4
-rw-r--r--src/dev/etherbus.hh3
-rw-r--r--src/dev/etherdevice.cc367
-rw-r--r--src/dev/etherdevice.hh54
-rw-r--r--src/dev/etherdump.cc49
-rw-r--r--src/dev/etherdump.hh4
-rw-r--r--src/dev/etherlink.cc16
-rw-r--r--src/dev/etherpkt.cc2
-rw-r--r--src/dev/etherpkt.hh17
-rw-r--r--src/dev/ethertap.cc15
-rw-r--r--src/dev/ethertap.hh3
-rw-r--r--src/dev/i8254xGBe.cc850
-rw-r--r--src/dev/i8254xGBe.hh293
-rw-r--r--src/dev/i8254xGBe_defs.hh227
-rw-r--r--src/dev/ide_ctrl.cc832
-rw-r--r--src/dev/ide_ctrl.hh246
-rw-r--r--src/dev/ide_disk.cc224
-rw-r--r--src/dev/ide_disk.hh18
-rw-r--r--src/dev/intel_8254_timer.cc278
-rw-r--r--src/dev/intel_8254_timer.hh244
-rw-r--r--src/dev/io_device.cc19
-rw-r--r--src/dev/io_device.hh30
-rw-r--r--src/dev/mc146818.cc192
-rw-r--r--src/dev/mc146818.hh126
-rwxr-xr-xsrc/dev/mips/Malta.py11
-rw-r--r--src/dev/mips/MipsBackdoor.py (renamed from src/dev/mips/MipsConsole.py)6
-rwxr-xr-xsrc/dev/mips/SConscript4
-rwxr-xr-xsrc/dev/mips/access.h34
-rwxr-xr-xsrc/dev/mips/backdoor.cc (renamed from src/dev/mips/console.cc)38
-rwxr-xr-xsrc/dev/mips/backdoor.hh (renamed from src/dev/mips/console.hh)24
-rwxr-xr-xsrc/dev/mips/malta.cc2
-rwxr-xr-xsrc/dev/mips/malta_cchip.cc2
-rw-r--r--src/dev/ns_gige.cc395
-rw-r--r--src/dev/ns_gige.hh63
-rw-r--r--src/dev/pciconfigall.cc2
-rw-r--r--src/dev/pcidev.cc79
-rw-r--r--src/dev/pcidev.hh3
-rw-r--r--src/dev/pcireg.h120
-rw-r--r--src/dev/pktfifo.cc55
-rw-r--r--src/dev/pktfifo.hh108
-rw-r--r--src/dev/platform.hh6
-rw-r--r--src/dev/rtcreg.h50
-rw-r--r--src/dev/sinic.cc242
-rw-r--r--src/dev/sinic.hh79
-rw-r--r--src/dev/sinicreg.hh91
-rw-r--r--src/dev/sparc/T1000.py12
-rw-r--r--src/dev/sparc/iob.cc6
-rw-r--r--src/dev/sparc/t1000.cc18
-rw-r--r--src/dev/sparc/t1000.hh12
-rw-r--r--src/dev/terminal.cc (renamed from src/dev/simconsole.cc)116
-rw-r--r--src/dev/terminal.hh (renamed from src/dev/simconsole.hh)36
-rw-r--r--src/dev/uart.cc8
-rw-r--r--src/dev/uart.hh4
-rw-r--r--src/dev/uart8250.cc30
-rw-r--r--src/dev/uart8250.hh2
-rw-r--r--src/dev/x86/Cmos.py41
-rw-r--r--src/dev/x86/I8042.py45
-rw-r--r--src/dev/x86/I82094AA.py43
-rw-r--r--src/dev/x86/I8237.py36
-rw-r--r--src/dev/x86/I8254.py39
-rw-r--r--src/dev/x86/I8259.py50
-rw-r--r--src/dev/x86/Opteron.py18
-rw-r--r--src/dev/x86/Pc.py83
-rw-r--r--src/dev/x86/PcSpeaker.py37
-rw-r--r--src/dev/x86/SConscript40
-rw-r--r--src/dev/x86/SouthBridge.py122
-rw-r--r--src/dev/x86/X86IntPin.py51
-rw-r--r--src/dev/x86/cmos.cc118
-rw-r--r--src/dev/x86/cmos.hh89
-rw-r--r--src/dev/x86/i8042.cc446
-rw-r--r--src/dev/x86/i8042.hh259
-rw-r--r--src/dev/x86/i82094aa.cc236
-rw-r--r--src/dev/x86/i82094aa.hh127
-rw-r--r--src/dev/x86/i8237.cc132
-rw-r--r--src/dev/x86/i8237.hh (renamed from src/cpu/o3/sparc/params.hh)51
-rw-r--r--src/dev/x86/i8254.cc (renamed from src/base/stats/statdb.cc)86
-rw-r--r--src/dev/x86/i8254.hh116
-rw-r--r--src/dev/x86/i8259.cc310
-rw-r--r--src/dev/x86/i8259.hh105
-rw-r--r--src/dev/x86/intdev.cc49
-rw-r--r--src/dev/x86/intdev.hh216
-rw-r--r--src/dev/x86/pc.cc176
-rw-r--r--src/dev/x86/pc.hh (renamed from src/dev/x86/opteron.hh)37
-rw-r--r--src/dev/x86/south_bridge.cc52
-rw-r--r--src/dev/x86/south_bridge.hh70
-rw-r--r--src/dev/x86/speaker.cc79
-rw-r--r--src/dev/x86/speaker.hh (renamed from src/arch/arm/syscallreturn.hh)66
-rw-r--r--src/kern/SConscript6
-rw-r--r--src/kern/kernel_stats.hh16
-rw-r--r--src/kern/linux/linux.cc (renamed from src/arch/alpha/syscallreturn.hh)53
-rw-r--r--src/kern/linux/linux.hh131
-rw-r--r--src/kern/operatingsystem.cc44
-rw-r--r--src/kern/operatingsystem.hh60
-rw-r--r--src/kern/solaris/solaris.hh62
-rw-r--r--src/kern/tru64/mbuf.hh78
-rw-r--r--src/kern/tru64/tru64.hh371
-rw-r--r--src/kern/tru64/tru64_events.cc13
-rw-r--r--src/kern/tru64/tru64_syscalls.cc768
-rw-r--r--src/mem/PhysicalMemory.py6
-rw-r--r--src/mem/SConscript1
-rw-r--r--src/mem/bridge.cc17
-rw-r--r--src/mem/bridge.hh8
-rw-r--r--src/mem/bus.cc75
-rw-r--r--src/mem/bus.hh8
-rw-r--r--src/mem/cache/BaseCache.py17
-rw-r--r--src/mem/cache/base.cc2
-rw-r--r--src/mem/cache/base.hh49
-rw-r--r--src/mem/cache/blk.hh26
-rw-r--r--src/mem/cache/builder.cc166
-rw-r--r--src/mem/cache/cache.cc16
-rw-r--r--src/mem/cache/cache.hh27
-rw-r--r--src/mem/cache/cache_impl.hh258
-rw-r--r--src/mem/cache/mshr.cc41
-rw-r--r--src/mem/cache/mshr.hh35
-rw-r--r--src/mem/cache/mshr_queue.cc2
-rw-r--r--src/mem/cache/prefetch/base.cc160
-rw-r--r--src/mem/cache/prefetch/base.hh42
-rw-r--r--src/mem/cache/prefetch/ghb.cc40
-rw-r--r--src/mem/cache/prefetch/ghb.hh10
-rw-r--r--src/mem/cache/prefetch/stride.cc136
-rw-r--r--src/mem/cache/prefetch/stride.hh34
-rw-r--r--src/mem/cache/prefetch/tagged.cc19
-rw-r--r--src/mem/cache/tags/SConscript4
-rw-r--r--src/mem/cache/tags/base.hh10
-rw-r--r--src/mem/cache/tags/fa_lru.cc17
-rw-r--r--src/mem/cache/tags/fa_lru.hh51
-rw-r--r--src/mem/cache/tags/iic.cc77
-rw-r--r--src/mem/cache/tags/iic.hh52
-rw-r--r--src/mem/cache/tags/iic_repl/gen.hh6
-rw-r--r--src/mem/cache/tags/lru.cc35
-rw-r--r--src/mem/cache/tags/lru.hh61
-rw-r--r--src/mem/cache/tags/split.cc420
-rw-r--r--src/mem/cache/tags/split.hh308
-rw-r--r--src/mem/cache/tags/split_blk.hh68
-rw-r--r--src/mem/cache/tags/split_lifo.cc331
-rw-r--r--src/mem/cache/tags/split_lifo.hh312
-rw-r--r--src/mem/cache/tags/split_lru.cc260
-rw-r--r--src/mem/cache/tags/split_lru.hh295
-rw-r--r--src/mem/config/cache.hh3
-rw-r--r--src/mem/dram.cc20
-rw-r--r--src/mem/dram.hh38
-rw-r--r--src/mem/mem_object.cc8
-rw-r--r--src/mem/mem_object.hh13
-rw-r--r--src/mem/mport.cc60
-rw-r--r--src/mem/mport.hh (renamed from src/cpu/o3/mips/thread_context.hh)68
-rw-r--r--src/mem/packet.cc77
-rw-r--r--src/mem/packet.hh572
-rw-r--r--src/mem/packet_access.hh3
-rw-r--r--src/mem/page_table.cc38
-rw-r--r--src/mem/page_table.hh12
-rw-r--r--src/mem/physical.cc58
-rw-r--r--src/mem/physical.hh12
-rw-r--r--src/mem/port.cc29
-rw-r--r--src/mem/port.hh20
-rw-r--r--src/mem/request.hh443
-rw-r--r--src/mem/tport.cc24
-rw-r--r--src/mem/tport.hh21
-rw-r--r--src/mem/vport.cc15
-rw-r--r--src/python/SConscript14
-rw-r--r--src/python/generate.py529
-rw-r--r--src/python/importer.py80
-rw-r--r--src/python/m5/SimObject.py96
-rw-r--r--src/python/m5/__init__.py48
-rw-r--r--src/python/m5/config.py50
-rw-r--r--src/python/m5/core.py40
-rw-r--r--src/python/m5/debug.py31
-rw-r--r--src/python/m5/event.py37
-rw-r--r--src/python/m5/main.py333
-rw-r--r--src/python/m5/options.py142
-rw-r--r--src/python/m5/params.py25
-rw-r--r--src/python/m5/simulate.py23
-rw-r--r--src/python/m5/stats.py19
-rw-r--r--src/python/m5/trace.py52
-rw-r--r--src/python/m5/util/__init__.py45
-rw-r--r--src/python/m5/util/attrdict.py (renamed from src/python/m5/attrdict.py)30
-rw-r--r--src/python/m5/util/jobfile.py472
-rw-r--r--src/python/m5/util/misc.py (renamed from src/python/m5/util.py)28
-rw-r--r--src/python/m5/util/multidict.py (renamed from src/python/m5/multidict.py)0
-rw-r--r--src/python/m5/util/orderdict.py80
-rw-r--r--src/python/swig/core.i26
-rw-r--r--src/python/swig/debug.i7
-rw-r--r--src/python/swig/event.i55
-rw-r--r--src/python/swig/pyevent.cc33
-rw-r--r--src/python/swig/pyevent.hh31
-rw-r--r--src/python/swig/range.i2
-rw-r--r--src/python/swig/stats.i3
-rw-r--r--src/sim/BaseTLB.py33
-rw-r--r--src/sim/InstTracer.py2
-rw-r--r--src/sim/Process.py3
-rw-r--r--src/sim/SConscript6
-rw-r--r--src/sim/System.py2
-rw-r--r--src/sim/async.hh12
-rw-r--r--src/sim/byteswap.hh56
-rw-r--r--src/sim/core.cc8
-rw-r--r--src/sim/core.hh5
-rw-r--r--src/sim/debug.cc65
-rw-r--r--src/sim/debug.hh14
-rw-r--r--src/sim/eventq.cc273
-rw-r--r--src/sim/eventq.hh510
-rw-r--r--src/sim/faults.hh2
-rw-r--r--src/sim/host.hh8
-rw-r--r--src/sim/init.cc209
-rw-r--r--src/sim/init.hh (renamed from src/mem/config/prefetch.hh)37
-rw-r--r--src/sim/insttracer.hh17
-rw-r--r--src/sim/main.cc124
-rw-r--r--src/sim/microcode_rom.hh (renamed from src/cpu/o3/sparc/cpu.cc)30
-rw-r--r--src/sim/process.cc143
-rw-r--r--src/sim/process.hh52
-rw-r--r--src/sim/pseudo_inst.cc408
-rw-r--r--src/sim/pseudo_inst.hh58
-rw-r--r--src/sim/serialize.cc54
-rw-r--r--src/sim/serialize.hh47
-rw-r--r--src/sim/sim_events.cc54
-rw-r--r--src/sim/sim_events.hh44
-rw-r--r--src/sim/sim_exit.hh8
-rw-r--r--src/sim/sim_object.cc10
-rw-r--r--src/sim/sim_object.hh13
-rw-r--r--src/sim/sim_object_params.hh58
-rw-r--r--src/sim/simulate.cc11
-rw-r--r--src/sim/stat_control.cc46
-rw-r--r--src/sim/stats.hh1
-rw-r--r--src/sim/syscall_emul.cc193
-rw-r--r--src/sim/syscall_emul.hh207
-rw-r--r--src/sim/system.cc72
-rw-r--r--src/sim/system.hh23
-rw-r--r--src/sim/tlb.cc10
-rw-r--r--src/sim/tlb.hh19
-rw-r--r--src/sim/vptr.hh3
-rw-r--r--src/unittest/Makefile101
-rw-r--r--src/unittest/SConscript48
-rw-r--r--src/unittest/bitvectest.cc53
-rw-r--r--src/unittest/circletest.cc58
-rw-r--r--src/unittest/cprintftest.cc18
-rw-r--r--src/unittest/foo.ini1
-rw-r--r--src/unittest/initest.cc20
-rw-r--r--src/unittest/initest.ini14
-rw-r--r--src/unittest/lru_test.cc85
-rw-r--r--src/unittest/nmtest.cc3
-rw-r--r--src/unittest/paramtest.cc107
-rw-r--r--src/unittest/rangemaptest.cc3
-rw-r--r--src/unittest/rangemultimaptest.cc (renamed from src/unittest/rangemaptest2.cc)14
-rw-r--r--src/unittest/rangetest.cc57
-rw-r--r--src/unittest/sized_test.cc70
-rw-r--r--src/unittest/stattest.cc135
-rw-r--r--src/unittest/strnumtest.cc63
-rw-r--r--src/unittest/symtest.cc4
812 files changed, 50839 insertions, 24571 deletions
diff --git a/src/SConscript b/src/SConscript
index 69c5b946d..c02bf239d 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -28,11 +28,15 @@
#
# Authors: Nathan Binkert
+import array
import imp
+import marshal
import os
+import re
import sys
+import zlib
-from os.path import basename, exists, isdir, isfile, join as joinpath
+from os.path import basename, dirname, exists, isdir, isfile, join as joinpath
import SCons
@@ -44,6 +48,8 @@ Import('*')
# Children need to see the environment
Export('env')
+build_env = dict([(opt, env[opt]) for opt in env.ExportVariables])
+
def sort_list(_list):
"""return a sorted copy of '_list'"""
if isinstance(_list, list):
@@ -54,39 +60,60 @@ def sort_list(_list):
return _list
class PySourceFile(object):
- def __init__(self, package, source):
- filename = str(source)
+ invalid_sym_char = re.compile('[^A-z0-9_]')
+ def __init__(self, package, tnode):
+ snode = tnode.srcnode()
+ filename = str(tnode)
pyname = basename(filename)
assert pyname.endswith('.py')
name = pyname[:-3]
- path = package.split('.')
- modpath = path
+ if package:
+ path = package.split('.')
+ else:
+ path = []
+
+ modpath = path[:]
if name != '__init__':
modpath += [name]
modpath = '.'.join(modpath)
- arcpath = package.split('.') + [ pyname + 'c' ]
+ arcpath = path + [ pyname ]
arcname = joinpath(*arcpath)
- self.source = source
+ debugname = snode.abspath
+ if not exists(debugname):
+ debugname = tnode.abspath
+
+ self.tnode = tnode
+ self.snode = snode
self.pyname = pyname
- self.srcpath = source.srcnode().abspath
self.package = package
self.modpath = modpath
self.arcname = arcname
- self.filename = filename
+ self.debugname = debugname
self.compiled = File(filename + 'c')
+ self.assembly = File(filename + '.s')
+ self.symname = "PyEMB_" + self.invalid_sym_char.sub('_', modpath)
+
########################################################################
# Code for adding source files of various types
#
-cc_sources = []
+cc_lib_sources = []
def Source(source):
- '''Add a C/C++ source file to the build'''
+ '''Add a source file to the libm5 build'''
if not isinstance(source, SCons.Node.FS.File):
source = File(source)
- cc_sources.append(source)
+ cc_lib_sources.append(source)
+
+cc_bin_sources = []
+def BinSource(source):
+ '''Add a source file to the m5 binary build'''
+ if not isinstance(source, SCons.Node.FS.File):
+ source = File(source)
+
+ cc_bin_sources.append(source)
py_sources = []
def PySource(package, source):
@@ -123,40 +150,50 @@ def SwigSource(package, source):
val = source,package
swig_sources.append(val)
+unit_tests = []
+def UnitTest(target, sources):
+ if not isinstance(sources, (list, tuple)):
+ sources = [ sources ]
+
+ srcs = []
+ for source in sources:
+ if not isinstance(source, SCons.Node.FS.File):
+ source = File(source)
+ srcs.append(source)
+
+ unit_tests.append((target, srcs))
+
# Children should have access
Export('Source')
+Export('BinSource')
Export('PySource')
Export('SimObject')
Export('SwigSource')
+Export('UnitTest')
########################################################################
#
# Trace Flags
#
-all_flags = {}
-trace_flags = []
-def TraceFlag(name, desc=''):
- if name in all_flags:
+trace_flags = {}
+def TraceFlag(name, desc=None):
+ if name in trace_flags:
raise AttributeError, "Flag %s already specified" % name
- flag = (name, (), desc)
- trace_flags.append(flag)
- all_flags[name] = ()
+ trace_flags[name] = (name, (), desc)
-def CompoundFlag(name, flags, desc=''):
- if name in all_flags:
+def CompoundFlag(name, flags, desc=None):
+ if name in trace_flags:
raise AttributeError, "Flag %s already specified" % name
compound = tuple(flags)
for flag in compound:
- if flag not in all_flags:
+ if flag not in trace_flags:
raise AttributeError, "Trace flag %s not found" % flag
- if all_flags[flag]:
+ if trace_flags[flag][1]:
raise AttributeError, \
"Compound flag can't point to another compound flag"
- flag = (name, compound, desc)
- trace_flags.append(flag)
- all_flags[name] = compound
+ trace_flags[name] = (name, compound, desc)
Export('TraceFlag')
Export('CompoundFlag')
@@ -172,26 +209,40 @@ Export('CompoundFlag')
# files.
env.Append(CPPPATH=Dir('.'))
+for extra_dir in extras_dir_list:
+ env.Append(CPPPATH=Dir(extra_dir))
+
# Add a flag defining what THE_ISA should be for all compilation
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
+# Workaround for bug in SCons version > 0.97d20071212
+# Scons bug id: 2006 M5 Bug id: 308
+for root, dirs, files in os.walk(base_dir, topdown=True):
+ Dir(root[len(base_dir) + 1:])
+
########################################################################
#
# Walk the tree and execute all SConscripts in subdirectories
#
-for base_dir in base_dir_list:
- here = Dir('.').srcnode().abspath
- for root, dirs, files in os.walk(base_dir, topdown=True):
- if root == here:
- # we don't want to recurse back into this SConscript
- continue
+here = Dir('.').srcnode().abspath
+for root, dirs, files in os.walk(base_dir, topdown=True):
+ if root == here:
+ # we don't want to recurse back into this SConscript
+ continue
+ if 'SConscript' in files:
+ build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
+ SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
+
+for extra_dir in extras_dir_list:
+ prefix_len = len(dirname(extra_dir)) + 1
+ for root, dirs, files in os.walk(extra_dir, topdown=True):
if 'SConscript' in files:
- build_dir = joinpath(env['BUILDDIR'], root[len(base_dir) + 1:])
+ build_dir = joinpath(env['BUILDDIR'], root[prefix_len:])
SConscript(joinpath(root, 'SConscript'), build_dir=build_dir)
-for opt in env.ExportOptions:
+for opt in env.ExportVariables:
env.ConfigFile(opt)
########################################################################
@@ -199,55 +250,150 @@ for opt in env.ExportOptions:
# Prevent any SimObjects from being added after this point, they
# should all have been added in the SConscripts above
#
-sim_objects_fixed = True
+class DictImporter(object):
+ '''This importer takes a dictionary of arbitrary module names that
+ map to arbitrary filenames.'''
+ def __init__(self, modules):
+ self.modules = modules
+ self.installed = set()
-########################################################################
-#
-# Manually turn python/generate.py into a python module and import it
-#
-generate_file = File('python/generate.py')
-generate_module = imp.new_module('generate')
-sys.modules['generate'] = generate_module
-exec file(generate_file.srcnode().abspath, 'r') in generate_module.__dict__
+ def __del__(self):
+ self.unload()
-########################################################################
-#
-# build a generate
-#
-from generate import Generate
-optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
-generate = Generate(py_sources, sim_object_modfiles, optionDict)
-m5 = generate.m5
+ def unload(self):
+ import sys
+ for module in self.installed:
+ del sys.modules[module]
+ self.installed = set()
+
+ def find_module(self, fullname, path):
+ if fullname == 'defines':
+ return self
+
+ if fullname == 'm5.objects':
+ return self
+
+ if fullname.startswith('m5.internal'):
+ return None
+
+ if fullname in self.modules and exists(self.modules[fullname]):
+ return self
+
+ return None
+
+ def load_module(self, fullname):
+ mod = imp.new_module(fullname)
+ sys.modules[fullname] = mod
+ self.installed.add(fullname)
+
+ mod.__loader__ = self
+ if fullname == 'm5.objects':
+ mod.__path__ = fullname.split('.')
+ return mod
+
+ if fullname == 'defines':
+ mod.__dict__['buildEnv'] = build_env
+ return mod
+
+ srcfile = self.modules[fullname]
+ if basename(srcfile) == '__init__.py':
+ mod.__path__ = fullname.split('.')
+ mod.__file__ = srcfile
+
+ exec file(srcfile, 'r') in mod.__dict__
+
+ return mod
+
+py_modules = {}
+for source in py_sources:
+ py_modules[source.modpath] = source.snode.abspath
+
+# install the python importer so we can grab stuff from the source
+# tree itself. We can't have SimObjects added after this point or
+# else we won't know about them for the rest of the stuff.
+sim_objects_fixed = True
+importer = DictImporter(py_modules)
+sys.meta_path[0:0] = [ importer ]
+
+import m5
+
+# import all sim objects so we can populate the all_objects list
+# make sure that we're working with a list, then let's sort it
+sim_objects = list(sim_object_modfiles)
+sim_objects.sort()
+for simobj in sim_objects:
+ exec('from m5.objects import %s' % simobj)
+
+# we need to unload all of the currently imported modules so that they
+# will be re-imported the next time the sconscript is run
+importer.unload()
+sys.meta_path.remove(importer)
+
+sim_objects = m5.SimObject.allClasses
+all_enums = m5.params.allEnums
+
+all_params = {}
+for name,obj in sim_objects.iteritems():
+ for param in obj._params.local.values():
+ if not hasattr(param, 'swig_decl'):
+ continue
+ pname = param.ptype_str
+ if pname not in all_params:
+ all_params[pname] = param
########################################################################
#
# calculate extra dependencies
#
module_depends = ["m5", "m5.SimObject", "m5.params"]
-module_depends = [ File(generate.py_modules[dep]) for dep in module_depends ]
-file_depends = [ generate_file ]
-depends = module_depends + file_depends
+depends = [ File(py_modules[dep]) for dep in module_depends ]
########################################################################
#
# Commands for the basic automatically generated python files
#
+# Generate Python file containing a dict specifying the current
+# build_env flags.
+def makeDefinesPyFile(target, source, env):
+ f = file(str(target[0]), 'w')
+ build_env, hg_info = [ x.get_contents() for x in source ]
+ print >>f, "buildEnv = %s" % build_env
+ print >>f, "hgRev = '%s'" % hg_info
+ f.close()
+
+defines_info = [ Value(build_env), Value(env['HG_INFO']) ]
# Generate a file with all of the compile options in it
-env.Command('python/m5/defines.py', Value(optionDict),
- generate.makeDefinesPyFile)
+env.Command('python/m5/defines.py', defines_info, makeDefinesPyFile)
PySource('m5', 'python/m5/defines.py')
+# Generate python file containing info about the M5 source code
+def makeInfoPyFile(target, source, env):
+ f = file(str(target[0]), 'w')
+ for src in source:
+ data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
+ print >>f, "%s = %s" % (src, repr(data))
+ f.close()
+
# Generate a file that wraps the basic top level files
env.Command('python/m5/info.py',
[ '#/AUTHORS', '#/LICENSE', '#/README', '#/RELEASE_NOTES' ],
- generate.makeInfoPyFile)
+ makeInfoPyFile)
PySource('m5', 'python/m5/info.py')
+# Generate the __init__.py file for m5.objects
+def makeObjectsInitFile(target, source, env):
+ f = file(str(target[0]), 'w')
+ print >>f, 'from params import *'
+ print >>f, 'from m5.SimObject import *'
+ for module in source:
+ print >>f, 'from %s import *' % module.get_contents()
+ f.close()
+
# Generate an __init__.py file for the objects package
env.Command('python/m5/objects/__init__.py',
[ Value(o) for o in sort_list(sim_object_modfiles) ],
- generate.makeObjectsInitFile)
+ makeObjectsInitFile)
PySource('m5.objects', 'python/m5/objects/__init__.py')
########################################################################
@@ -255,51 +401,189 @@ PySource('m5.objects', 'python/m5/objects/__init__.py')
# Create all of the SimObject param headers and enum headers
#
+def createSimObjectParam(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ hh_file = file(target[0].abspath, 'w')
+ name = str(source[0].get_contents())
+ obj = sim_objects[name]
+
+ print >>hh_file, obj.cxx_decl()
+
+def createSwigParam(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ i_file = file(target[0].abspath, 'w')
+ name = str(source[0].get_contents())
+ param = all_params[name]
+
+ for line in param.swig_decl():
+ print >>i_file, line
+
+def createEnumStrings(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ cc_file = file(target[0].abspath, 'w')
+ name = str(source[0].get_contents())
+ obj = all_enums[name]
+
+ print >>cc_file, obj.cxx_def()
+ cc_file.close()
+
+def createEnumParam(target, source, env):
+ assert len(target) == 1 and len(source) == 1
+
+ hh_file = file(target[0].abspath, 'w')
+ name = str(source[0].get_contents())
+ obj = all_enums[name]
+
+ print >>hh_file, obj.cxx_decl()
+
# Generate all of the SimObject param struct header files
params_hh_files = []
-for name,simobj in generate.sim_objects.iteritems():
- extra_deps = [ File(generate.py_modules[simobj.__module__]) ]
+for name,simobj in sim_objects.iteritems():
+ extra_deps = [ File(py_modules[simobj.__module__]) ]
hh_file = File('params/%s.hh' % name)
params_hh_files.append(hh_file)
- env.Command(hh_file, Value(name), generate.createSimObjectParam)
+ env.Command(hh_file, Value(name), createSimObjectParam)
env.Depends(hh_file, depends + extra_deps)
# Generate any parameter header files needed
-for name,param in generate.params.iteritems():
+params_i_files = []
+for name,param in all_params.iteritems():
if isinstance(param, m5.params.VectorParamDesc):
ext = 'vptype'
else:
ext = 'ptype'
i_file = File('params/%s_%s.i' % (name, ext))
- env.Command(i_file, Value(name), generate.createSwigParam)
+ params_i_files.append(i_file)
+ env.Command(i_file, Value(name), createSwigParam)
env.Depends(i_file, depends)
# Generate all enum header files
-for name,enum in generate.enums.iteritems():
- extra_deps = [ File(generate.py_modules[enum.__module__]) ]
+for name,enum in all_enums.iteritems():
+ extra_deps = [ File(py_modules[enum.__module__]) ]
cc_file = File('enums/%s.cc' % name)
- env.Command(cc_file, Value(name), generate.createEnumStrings)
+ env.Command(cc_file, Value(name), createEnumStrings)
env.Depends(cc_file, depends + extra_deps)
Source(cc_file)
hh_file = File('enums/%s.hh' % name)
- env.Command(hh_file, Value(name), generate.createEnumParam)
+ env.Command(hh_file, Value(name), createEnumParam)
env.Depends(hh_file, depends + extra_deps)
# Build the big monolithic swigged params module (wraps all SimObject
# param structs and enum structs)
+def buildParams(target, source, env):
+ names = [ s.get_contents() for s in source ]
+ objs = [ sim_objects[name] for name in names ]
+ out = file(target[0].abspath, 'w')
+
+ ordered_objs = []
+ obj_seen = set()
+ def order_obj(obj):
+ name = str(obj)
+ if name in obj_seen:
+ return
+
+ obj_seen.add(name)
+ if str(obj) != 'SimObject':
+ order_obj(obj.__bases__[0])
+
+ ordered_objs.append(obj)
+
+ for obj in objs:
+ order_obj(obj)
+
+ enums = set()
+ predecls = []
+ pd_seen = set()
+
+ def add_pds(*pds):
+ for pd in pds:
+ if pd not in pd_seen:
+ predecls.append(pd)
+ pd_seen.add(pd)
+
+ for obj in ordered_objs:
+ params = obj._params.local.values()
+ for param in params:
+ ptype = param.ptype
+ if issubclass(ptype, m5.params.Enum):
+ if ptype not in enums:
+ enums.add(ptype)
+ pds = param.swig_predecls()
+ if isinstance(pds, (list, tuple)):
+ add_pds(*pds)
+ else:
+ add_pds(pds)
+
+ print >>out, '%module params'
+
+ print >>out, '%{'
+ for obj in ordered_objs:
+ print >>out, '#include "params/%s.hh"' % obj
+ print >>out, '%}'
+
+ for pd in predecls:
+ print >>out, pd
+
+ enums = list(enums)
+ enums.sort()
+ for enum in enums:
+ print >>out, '%%include "enums/%s.hh"' % enum.__name__
+ print >>out
+
+ for obj in ordered_objs:
+ if obj.swig_objdecls:
+ for decl in obj.swig_objdecls:
+ print >>out, decl
+ continue
+
+ class_path = obj.cxx_class.split('::')
+ classname = class_path[-1]
+ namespaces = class_path[:-1]
+ namespaces.reverse()
+
+ code = ''
+
+ if namespaces:
+ code += '// avoid name conflicts\n'
+ sep_string = '_COLONS_'
+ flat_name = sep_string.join(class_path)
+ code += '%%rename(%s) %s;\n' % (flat_name, classname)
+
+ code += '// stop swig from creating/wrapping default ctor/dtor\n'
+ code += '%%nodefault %s;\n' % classname
+ code += 'class %s ' % classname
+ if obj._base:
+ code += ': public %s' % obj._base.cxx_class
+ code += ' {};\n'
+
+ for ns in namespaces:
+ new_code = 'namespace %s {\n' % ns
+ new_code += code
+ new_code += '}\n'
+ code = new_code
+
+ print >>out, code
+
+ print >>out, '%%include "src/sim/sim_object_params.hh"' % obj
+ for obj in ordered_objs:
+ print >>out, '%%include "params/%s.hh"' % obj
+
params_file = File('params/params.i')
-names = sort_list(generate.sim_objects.keys())
-env.Command(params_file, [ Value(v) for v in names ],
- generate.buildParams)
-env.Depends(params_file, params_hh_files + depends)
+names = sort_list(sim_objects.keys())
+env.Command(params_file, [ Value(v) for v in names ], buildParams)
+env.Depends(params_file, params_hh_files + params_i_files + depends)
SwigSource('m5.objects', params_file)
# Build all swig modules
swig_modules = []
+cc_swig_sources = []
for source,package in swig_sources:
filename = str(source)
assert filename.endswith('.i')
@@ -316,37 +600,316 @@ for source,package in swig_sources:
env.Depends(cc_file, source)
swig_modules.append(Value(module))
- Source(cc_file)
+ cc_swig_sources.append(File(cc_file))
PySource(package, py_file)
# Generate the main swig init file
-env.Command('swig/init.cc', swig_modules, generate.makeSwigInit)
-Source('swig/init.cc')
+def makeSwigInit(target, source, env):
+ f = file(str(target[0]), 'w')
+ print >>f, 'extern "C" {'
+ for module in source:
+ print >>f, ' void init_%s();' % module.get_contents()
+ print >>f, '}'
+ print >>f, 'void initSwig() {'
+ for module in source:
+ print >>f, ' init_%s();' % module.get_contents()
+ print >>f, '}'
+ f.close()
+
+env.Command('python/swig/init.cc', swig_modules, makeSwigInit)
+Source('python/swig/init.cc')
# Generate traceflags.py
-flags = [ Value(f) for f in trace_flags ]
-env.Command('base/traceflags.py', flags, generate.traceFlagsPy)
+def traceFlagsPy(target, source, env):
+ assert(len(target) == 1)
+
+ f = file(str(target[0]), 'w')
+
+ allFlags = []
+ for s in source:
+ val = eval(s.get_contents())
+ allFlags.append(val)
+
+ allFlags.sort()
+
+ print >>f, 'basic = ['
+ for flag, compound, desc in allFlags:
+ if not compound:
+ print >>f, " '%s'," % flag
+ print >>f, " ]"
+ print >>f
+
+ print >>f, 'compound = ['
+ print >>f, " 'All',"
+ for flag, compound, desc in allFlags:
+ if compound:
+ print >>f, " '%s'," % flag
+ print >>f, " ]"
+ print >>f
+
+ print >>f, "all = frozenset(basic + compound)"
+ print >>f
+
+ print >>f, 'compoundMap = {'
+ all = tuple([flag for flag,compound,desc in allFlags if not compound])
+ print >>f, " 'All' : %s," % (all, )
+ for flag, compound, desc in allFlags:
+ if compound:
+ print >>f, " '%s' : %s," % (flag, compound)
+ print >>f, " }"
+ print >>f
+
+ print >>f, 'descriptions = {'
+ print >>f, " 'All' : 'All flags',"
+ for flag, compound, desc in allFlags:
+ print >>f, " '%s' : '%s'," % (flag, desc)
+ print >>f, " }"
+
+ f.close()
+
+def traceFlagsCC(target, source, env):
+ assert(len(target) == 1)
+
+ f = file(str(target[0]), 'w')
+
+ allFlags = []
+ for s in source:
+ val = eval(s.get_contents())
+ allFlags.append(val)
+
+ # file header
+ print >>f, '''
+/*
+ * DO NOT EDIT THIS FILE! Automatically generated
+ */
+
+#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, compound, desc in allFlags:
+ if not compound:
+ print >>f, ' "%s",' % flag
+
+ print >>f, ' "All",'
+ for flag, compound, desc in allFlags:
+ if compound:
+ print >>f, ' "%s",' % flag
+
+ print >>f, '};'
+ print >>f
+ print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
+ print >>f
+
+ #
+ # Now define the individual compound flag arrays. There is an array
+ # for each compound flag listing the component base flags.
+ #
+ all = tuple([flag for flag,compound,desc in allFlags if not compound])
+ print >>f, 'static const Flags AllMap[] = {'
+ for flag, compound, desc in allFlags:
+ if not compound:
+ print >>f, " %s," % flag
+ print >>f, '};'
+ print >>f
+
+ for flag, compound, desc in allFlags:
+ if not compound:
+ continue
+ print >>f, 'static const Flags %sMap[] = {' % flag
+ for flag in compound:
+ print >>f, " %s," % flag
+ print >>f, " (Flags)-1"
+ print >>f, '};'
+ print >>f
+
+ #
+ # Finally the compoundFlags[] array maps the compound flags
+ # to their individual arrays/
+ #
+ print >>f, 'const Flags *Trace::compoundFlags[] ='
+ print >>f, '{'
+ print >>f, ' AllMap,'
+ for flag, compound, desc in allFlags:
+ if compound:
+ print >>f, ' %sMap,' % flag
+ # file trailer
+ print >>f, '};'
+
+ f.close()
+
+def traceFlagsHH(target, source, env):
+ assert(len(target) == 1)
+
+ f = file(str(target[0]), 'w')
+
+ allFlags = []
+ for s in source:
+ val = eval(s.get_contents())
+ allFlags.append(val)
+
+ # file header boilerplate
+ print >>f, '''
+/*
+ * 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, compound, desc in allFlags:
+ if not compound:
+ print >>f, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+ numBaseFlags = idx
+ print >>f, ' NumFlags = %d,' % idx
+
+ # put a comment in here to separate base from compound flags
+ print >>f, '''
+// 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 by changeFlag.'''
+
+ print >>f, ' All = %d,' % idx
+ idx += 1
+ for flag, compound, desc in allFlags:
+ if compound:
+ print >>f, ' %s = %d,' % (flag, idx)
+ idx += 1
+
+ numCompoundFlags = idx - numBaseFlags
+ print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
+
+ # trailer boilerplate
+ print >>f, '''\
+}; // 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__
+'''
+
+ f.close()
+
+flags = [ Value(f) for f in trace_flags.values() ]
+env.Command('base/traceflags.py', flags, traceFlagsPy)
PySource('m5', 'base/traceflags.py')
-env.Command('base/traceflags.hh', flags, generate.traceFlagsHH)
-env.Command('base/traceflags.cc', flags, generate.traceFlagsCC)
+env.Command('base/traceflags.hh', flags, traceFlagsHH)
+env.Command('base/traceflags.cc', flags, traceFlagsCC)
Source('base/traceflags.cc')
-# Build the zip file
-py_compiled = []
-py_zip_depends = []
-for source in py_sources:
- env.Command(source.compiled, source.source, generate.compilePyFile)
- py_compiled.append(source.compiled)
+# embed python files. All .py files that have been indicated by a
+# PySource() call in a SConscript need to be embedded into the M5
+# library. To do that, we compile the file to byte code, marshal the
+# byte code, compress it, and then generate an assembly file that
+# inserts the result into the data section with symbols indicating the
+# beginning, and end (and with the size at the end)
+py_sources_tnodes = {}
+for pysource in py_sources:
+ py_sources_tnodes[pysource.tnode] = pysource
+
+def objectifyPyFile(target, source, env):
+ '''Action function to compile a .py into a code object, marshal
+ it, compress it, and stick it into an asm file so the code appears
+ as just bytes with a label in the data section'''
+
+ src = file(str(source[0]), 'r').read()
+ dst = file(str(target[0]), 'w')
+
+ pysource = py_sources_tnodes[source[0]]
+ compiled = compile(src, pysource.debugname, 'exec')
+ marshalled = marshal.dumps(compiled)
+ compressed = zlib.compress(marshalled)
+ data = compressed
+
+ # Some C/C++ compilers prepend an underscore to global symbol
+ # names, so if they're going to do that, we need to prepend that
+ # leading underscore to globals in the assembly file.
+ if env['LEADING_UNDERSCORE']:
+ sym = '_' + pysource.symname
+ else:
+ sym = pysource.symname
+
+ step = 16
+ print >>dst, ".data"
+ print >>dst, ".globl %s_beg" % sym
+ print >>dst, ".globl %s_end" % sym
+ print >>dst, "%s_beg:" % sym
+ for i in xrange(0, len(data), step):
+ x = array.array('B', data[i:i+step])
+ print >>dst, ".byte", ','.join([str(d) for d in x])
+ print >>dst, "%s_end:" % sym
+ print >>dst, ".long %d" % len(marshalled)
- # make the zipfile depend on the archive name so that the archive
- # is rebuilt if the name changes
- py_zip_depends.append(Value(source.arcname))
+for source in py_sources:
+ env.Command(source.assembly, source.tnode, objectifyPyFile)
+ Source(source.assembly)
+
+# Generate init_python.cc which creates a bunch of EmbeddedPyModule
+# structs that describe the embedded python code. One such struct
+# contains information about the importer that python uses to get at
+# the embedded files, and then there's a list of all of the rest that
+# the importer uses to load the rest on demand.
+py_sources_symbols = {}
+for pysource in py_sources:
+ py_sources_symbols[pysource.symname] = pysource
+def pythonInit(target, source, env):
+ dst = file(str(target[0]), 'w')
+
+ def dump_mod(sym, endchar=','):
+ pysource = py_sources_symbols[sym]
+ print >>dst, ' { "%s",' % pysource.arcname
+ print >>dst, ' "%s",' % pysource.modpath
+ print >>dst, ' %s_beg, %s_end,' % (sym, sym)
+ print >>dst, ' %s_end - %s_beg,' % (sym, sym)
+ print >>dst, ' *(int *)%s_end }%s' % (sym, endchar)
+
+ print >>dst, '#include "sim/init.hh"'
+
+ for sym in source:
+ sym = sym.get_contents()
+ print >>dst, "extern const char %s_beg[], %s_end[];" % (sym, sym)
+
+ print >>dst, "const EmbeddedPyModule embeddedPyImporter = "
+ dump_mod("PyEMB_importer", endchar=';');
+ print >>dst
+
+ print >>dst, "const EmbeddedPyModule embeddedPyModules[] = {"
+ for i,sym in enumerate(source):
+ sym = sym.get_contents()
+ if sym == "PyEMB_importer":
+ # Skip the importer since we've already exported it
+ continue
+ dump_mod(sym)
+ print >>dst, " { 0, 0, 0, 0, 0, 0 }"
+ print >>dst, "};"
-# Add the zip file target to the environment.
-m5zip = File('m5py.zip')
-env.Command(m5zip, py_compiled, generate.buildPyZip)
-env.Depends(m5zip, py_zip_depends)
+symbols = [Value(s.symname) for s in py_sources]
+env.Command('sim/init_python.cc', symbols, pythonInit)
+Source('sim/init_python.cc')
########################################################################
#
@@ -362,11 +925,18 @@ envList = []
# 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]
+def make_objs(sources, env, static):
+ if static:
+ XObject = env.StaticObject
+ else:
+ XObject = env.SharedObject
+
+ objs = [ XObject(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')
+ date_obj = XObject('base/date.cc')
+
env.Depends(date_obj, objs)
objs.append(date_obj)
return objs
@@ -376,23 +946,50 @@ def make_objs(sources, env):
# binary. Additional keyword arguments are appended to corresponding
# build environment vars.
def makeEnv(label, objsfx, strip = False, **kwargs):
- newEnv = env.Copy(OBJSUFFIX=objsfx)
- newEnv.Label = label
- newEnv.Append(**kwargs)
- exe = 'm5.' + label # final executable
- bin = exe + '.bin' # executable w/o appended Python zip archive
- newEnv.Program(bin, make_objs(cc_sources, newEnv))
+ # SCons doesn't know to append a library suffix when there is a '.' in the
+ # name. Use '_' instead.
+ libname = 'm5_' + label
+ exename = 'm5.' + label
+
+ new_env = env.Clone(OBJSUFFIX=objsfx, SHOBJSUFFIX=objsfx + 's')
+ new_env.Label = label
+ new_env.Append(**kwargs)
+
+ swig_env = new_env.Clone()
+ if env['GCC']:
+ swig_env.Append(CCFLAGS='-Wno-uninitialized')
+ swig_env.Append(CCFLAGS='-Wno-sign-compare')
+ swig_env.Append(CCFLAGS='-Wno-parentheses')
+
+ static_objs = make_objs(cc_lib_sources, new_env, static=True)
+ shared_objs = make_objs(cc_lib_sources, new_env, static=False)
+ static_objs += [ swig_env.StaticObject(s) for s in cc_swig_sources ]
+ shared_objs += [ swig_env.SharedObject(s) for s in cc_swig_sources ]
+
+ # First make a library of everything but main() so other programs can
+ # link against m5.
+ static_lib = new_env.StaticLibrary(libname, static_objs)
+ shared_lib = new_env.SharedLibrary(libname, shared_objs)
+
+ for target, sources in unit_tests:
+ objs = [ new_env.StaticObject(s) for s in sources ]
+ new_env.Program("unittest/%s.%s" % (target, label), objs + static_objs)
+
+ # Now link a stub with main() and the static library.
+ objects = [new_env.Object(s) for s in cc_bin_sources] + static_objs
if strip:
- stripped_bin = bin + '.stripped'
+ unstripped_exe = exename + '.unstripped'
+ new_env.Program(unstripped_exe, objects)
if sys.platform == 'sunos5':
cmd = 'cp $SOURCE $TARGET; strip $TARGET'
else:
cmd = 'strip $SOURCE -o $TARGET'
- newEnv.Command(stripped_bin, bin, cmd)
- bin = stripped_bin
- targets = newEnv.Concat(exe, [bin, 'm5py.zip'])
- newEnv.M5Binary = targets[0]
- envList.append(newEnv)
+ targets = new_env.Command(exename, unstripped_exe, cmd)
+ else:
+ targets = new_env.Program(exename, objects)
+
+ new_env.M5Binary = targets[0]
+ envList.append(new_env)
# Debug binary
ccflags = {}
diff --git a/src/arch/SConscript b/src/arch/SConscript
index 66f93870e..b85ffbd89 100644
--- a/src/arch/SConscript
+++ b/src/arch/SConscript
@@ -49,13 +49,13 @@ isa_switch_hdrs = Split('''
isa_traits.hh
kernel_stats.hh
locked_mem.hh
+ microcode_rom.hh
mmaped_ipr.hh
process.hh
predecoder.hh
regfile.hh
remote_gdb.hh
stacktrace.hh
- syscallreturn.hh
tlb.hh
types.hh
utility.hh
@@ -125,3 +125,8 @@ else:
emitter = isa_desc_emitter)
env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
+
+TraceFlag('IntRegs')
+TraceFlag('FloatRegs')
+TraceFlag('MiscRegs')
+CompoundFlag('Registers', [ 'IntRegs', 'FloatRegs', 'MiscRegs' ])
diff --git a/src/arch/alpha/AlphaInterrupts.py b/src/arch/alpha/AlphaInterrupts.py
new file mode 100644
index 000000000..ecfcf5c21
--- /dev/null
+++ b/src/arch/alpha/AlphaInterrupts.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+
+class AlphaInterrupts(SimObject):
+ type = 'AlphaInterrupts'
+ cxx_class = 'AlphaISA::Interrupts'
diff --git a/src/arch/alpha/AlphaTLB.py b/src/arch/alpha/AlphaTLB.py
index fec245b75..099327470 100644
--- a/src/arch/alpha/AlphaTLB.py
+++ b/src/arch/alpha/AlphaTLB.py
@@ -28,21 +28,20 @@
from m5.SimObject import SimObject
from m5.params import *
-class AlphaTLB(SimObject):
+
+from BaseTLB import BaseTLB
+
+class AlphaTLB(BaseTLB):
type = 'AlphaTLB'
abstract = True
size = Param.Int("TLB size")
class AlphaDTB(AlphaTLB):
type = 'AlphaDTB'
- cxx_namespace = 'AlphaISA'
- cxx_class = 'DTB'
-
+ cxx_class = 'AlphaISA::DTB'
size = 64
class AlphaITB(AlphaTLB):
type = 'AlphaITB'
- cxx_namespace = 'AlphaISA'
- cxx_class = 'ITB'
-
+ cxx_class = 'AlphaISA::ITB'
size = 48
diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript
index 04bac3996..069db2551 100644
--- a/src/arch/alpha/SConscript
+++ b/src/arch/alpha/SConscript
@@ -47,9 +47,11 @@ if env['TARGET_ISA'] == 'alpha':
SimObject('AlphaTLB.py')
if env['FULL_SYSTEM']:
+ SimObject('AlphaInterrupts.py')
SimObject('AlphaSystem.py')
Source('idle_event.cc')
+ Source('interrupts.cc')
Source('kernel_stats.cc')
Source('osfpal.cc')
Source('stacktrace.cc')
diff --git a/src/arch/alpha/SConsopts b/src/arch/alpha/SConsopts
index 633eeb06f..b418e27c8 100644
--- a/src/arch/alpha/SConsopts
+++ b/src/arch/alpha/SConsopts
@@ -33,5 +33,5 @@ Import('*')
all_isa_list.append('alpha')
# Alpha can be compiled with Turbolaser support instead of Tsunami
-sticky_opts.Add(BoolOption('ALPHA_TLASER',
+sticky_vars.Add(BoolVariable('ALPHA_TLASER',
'Model Alpha TurboLaser platform (vs. Tsunami)', False))
diff --git a/src/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h
index 58991256a..bcf004d05 100644
--- a/src/arch/alpha/aout_machdep.h
+++ b/src/arch/alpha/aout_machdep.h
@@ -36,35 +36,35 @@
/// Funky Alpha 64-bit a.out header used for PAL code.
///
struct aout_exechdr {
- uint16_t magic; ///< magic number
- uint16_t vstamp; ///< version stamp?
- uint16_t bldrev; ///< ???
- uint16_t padcell; ///< padding
- uint64_t tsize; ///< text segment size
- uint64_t dsize; ///< data segment size
- uint64_t bsize; ///< bss segment size
- uint64_t entry; ///< entry point
- uint64_t text_start; ///< text base address
- uint64_t data_start; ///< data base address
- uint64_t bss_start; ///< bss base address
- uint32_t gprmask; ///< GPR mask (unused, AFAIK)
- uint32_t fprmask; ///< FPR mask (unused, AFAIK)
- uint64_t gp_value; ///< global pointer reg value
+ uint16_t magic; ///< magic number
+ uint16_t vstamp; ///< version stamp?
+ uint16_t bldrev; ///< ???
+ uint16_t padcell; ///< padding
+ uint64_t tsize; ///< text segment size
+ uint64_t dsize; ///< data segment size
+ uint64_t bsize; ///< bss segment size
+ uint64_t entry; ///< entry point
+ uint64_t text_start; ///< text base address
+ uint64_t data_start; ///< data base address
+ uint64_t bss_start; ///< bss base address
+ uint32_t gprmask; ///< GPR mask (unused, AFAIK)
+ uint32_t fprmask; ///< FPR mask (unused, AFAIK)
+ uint64_t gp_value; ///< global pointer reg value
};
-#define AOUT_LDPGSZ 8192
+#define AOUT_LDPGSZ 8192
-#define N_GETMAGIC(ex) ((ex).magic)
+#define N_GETMAGIC(ex) ((ex).magic)
#define N_BADMAX
-#define N_TXTADDR(ex) ((ex).text_start)
-#define N_DATADDR(ex) ((ex).data_start)
-#define N_BSSADDR(ex) ((ex).bss_start)
+#define N_TXTADDR(ex) ((ex).text_start)
+#define N_DATADDR(ex) ((ex).data_start)
+#define N_BSSADDR(ex) ((ex).bss_start)
-#define N_TXTOFF(ex) \
+#define N_TXTOFF(ex) \
(N_GETMAGIC(ex) == ZMAGIC ? 0 : sizeof(struct aout_exechdr))
-#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize)
+#define N_DATOFF(ex) N_ALIGN(ex, N_TXTOFF(ex) + (ex).tsize)
#endif /* !__AOUT_MACHDEP_H__*/
diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc
index 5dc49623e..02497e282 100644
--- a/src/arch/alpha/ev5.cc
+++ b/src/arch/alpha/ev5.cc
@@ -35,32 +35,33 @@
#include "arch/alpha/osfpal.hh"
#include "arch/alpha/tlb.hh"
#include "arch/alpha/kgdb.h"
+#include "base/cp_annotate.hh"
+#include "base/debug.hh"
#include "base/remote_gdb.hh"
#include "base/stats/events.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
-#include "sim/debug.hh"
#include "sim/sim_exit.hh"
-#if FULL_SYSTEM
+namespace AlphaISA {
-using namespace EV5;
+#if FULL_SYSTEM
////////////////////////////////////////////////////////////////////////
//
// Machine dependent functions
//
void
-AlphaISA::initCPU(ThreadContext *tc, int cpuId)
+initCPU(ThreadContext *tc, int cpuId)
{
initIPRs(tc, cpuId);
tc->setIntReg(16, cpuId);
tc->setIntReg(0, cpuId);
- AlphaISA::AlphaFault *reset = new AlphaISA::ResetFault;
+ AlphaFault *reset = new ResetFault;
tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + reset->vect());
tc->setNextPC(tc->readPC() + sizeof(MachInst));
@@ -71,7 +72,7 @@ AlphaISA::initCPU(ThreadContext *tc, int cpuId)
template <class CPU>
void
-AlphaISA::processInterrupts(CPU *cpu)
+processInterrupts(CPU *cpu)
{
//Check if there are any outstanding interrupts
//Handle the interrupts
@@ -117,7 +118,7 @@ AlphaISA::processInterrupts(CPU *cpu)
template <class CPU>
void
-AlphaISA::zeroRegisters(CPU *cpu)
+zeroRegisters(CPU *cpu)
{
// Insure ISA semantics
// (no longer very clean due to the change in setIntReg() in the
@@ -126,33 +127,16 @@ AlphaISA::zeroRegisters(CPU *cpu)
cpu->thread->setFloatReg(ZeroReg, 0.0);
}
-Fault
-SimpleThread::hwrei()
-{
- if (!(readPC() & 0x3))
- return new UnimplementedOpcodeFault;
-
- setNextPC(readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR));
-
- if (!misspeculating()) {
- if (kernelStats)
- kernelStats->hwrei();
- }
-
- // FIXME: XXX check for interrupts? XXX
- return NoFault;
-}
-
int
-AlphaISA::MiscRegFile::getInstAsid()
+MiscRegFile::getInstAsid()
{
- return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
+ return ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
}
int
-AlphaISA::MiscRegFile::getDataAsid()
+MiscRegFile::getDataAsid()
{
- return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
+ return DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
}
#endif
@@ -162,90 +146,90 @@ AlphaISA::MiscRegFile::getDataAsid()
//
//
void
-AlphaISA::initIPRs(ThreadContext *tc, int cpuId)
+initIPRs(ThreadContext *tc, int cpuId)
{
for (int i = 0; i < NumInternalProcRegs; ++i) {
tc->setMiscRegNoEffect(i, 0);
}
- tc->setMiscRegNoEffect(IPR_PAL_BASE, EV5::PalBase);
+ tc->setMiscRegNoEffect(IPR_PAL_BASE, PalBase);
tc->setMiscRegNoEffect(IPR_MCSR, 0x6);
tc->setMiscRegNoEffect(IPR_PALtemp16, cpuId);
}
-AlphaISA::MiscReg
-AlphaISA::MiscRegFile::readIpr(int idx, ThreadContext *tc)
+MiscReg
+MiscRegFile::readIpr(int idx, ThreadContext *tc)
{
- uint64_t retval = 0; // return value, default 0
+ 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:
+ case IPR_PALtemp0:
+ case IPR_PALtemp1:
+ case IPR_PALtemp2:
+ case IPR_PALtemp3:
+ case IPR_PALtemp4:
+ case IPR_PALtemp5:
+ case IPR_PALtemp6:
+ case IPR_PALtemp7:
+ case IPR_PALtemp8:
+ case IPR_PALtemp9:
+ case IPR_PALtemp10:
+ case IPR_PALtemp11:
+ case IPR_PALtemp12:
+ case IPR_PALtemp13:
+ case IPR_PALtemp14:
+ case IPR_PALtemp15:
+ case IPR_PALtemp16:
+ case IPR_PALtemp17:
+ case IPR_PALtemp18:
+ case IPR_PALtemp19:
+ case IPR_PALtemp20:
+ case IPR_PALtemp21:
+ case IPR_PALtemp22:
+ case IPR_PALtemp23:
+ case IPR_PAL_BASE:
+
+ case IPR_IVPTBR:
+ case IPR_DC_MODE:
+ case IPR_MAF_MODE:
+ case IPR_ISR:
+ case IPR_EXC_ADDR:
+ case IPR_IC_PERR_STAT:
+ case IPR_DC_PERR_STAT:
+ case IPR_MCSR:
+ case IPR_ASTRR:
+ case IPR_ASTER:
+ case IPR_SIRR:
+ case IPR_ICSR:
+ case IPR_ICM:
+ case IPR_DTB_CM:
+ case IPR_IPLR:
+ case IPR_INTID:
+ case IPR_PMCTR:
// no side-effect
retval = ipr[idx];
break;
- case AlphaISA::IPR_CC:
+ case IPR_CC:
retval |= ipr[idx] & ULL(0xffffffff00000000);
retval |= tc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff);
break;
- case AlphaISA::IPR_VA:
+ case 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:
+ case IPR_VA_FORM:
+ case IPR_MM_STAT:
+ case IPR_IFAULT_VA_FORM:
+ case IPR_EXC_MASK:
+ case IPR_EXC_SUM:
retval = ipr[idx];
break;
- case AlphaISA::IPR_DTB_PTE:
+ case IPR_DTB_PTE:
{
- AlphaISA::TlbEntry &entry
+ TlbEntry &entry
= tc->getDTBPtr()->index(!tc->misspeculating());
retval |= ((uint64_t)entry.ppn & ULL(0x7ffffff)) << 32;
@@ -259,15 +243,15 @@ AlphaISA::MiscRegFile::readIpr(int idx, ThreadContext *tc)
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:
+ case IPR_HWINT_CLR:
+ case IPR_SL_XMIT:
+ case IPR_DC_FLUSH:
+ case IPR_IC_FLUSH:
+ case IPR_ALT_MODE:
+ case IPR_DTB_IA:
+ case IPR_DTB_IAP:
+ case IPR_ITB_IA:
+ case IPR_ITB_IAP:
panic("Tried to read write only register %d\n", idx);
break;
@@ -286,7 +270,7 @@ int break_ipl = -1;
#endif
void
-AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
+MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
{
uint64_t old;
@@ -294,52 +278,52 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
return;
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:
+ case IPR_PALtemp0:
+ case IPR_PALtemp1:
+ case IPR_PALtemp2:
+ case IPR_PALtemp3:
+ case IPR_PALtemp4:
+ case IPR_PALtemp5:
+ case IPR_PALtemp6:
+ case IPR_PALtemp7:
+ case IPR_PALtemp8:
+ case IPR_PALtemp9:
+ case IPR_PALtemp10:
+ case IPR_PALtemp11:
+ case IPR_PALtemp12:
+ case IPR_PALtemp13:
+ case IPR_PALtemp14:
+ case IPR_PALtemp15:
+ case IPR_PALtemp16:
+ case IPR_PALtemp17:
+ case IPR_PALtemp18:
+ case IPR_PALtemp19:
+ case IPR_PALtemp20:
+ case IPR_PALtemp21:
+ case IPR_PALtemp22:
+ case IPR_PAL_BASE:
+ case IPR_IC_PERR_STAT:
+ case IPR_DC_PERR_STAT:
+ case IPR_PMCTR:
// write entire quad w/ no side-effect
ipr[idx] = val;
break;
- case AlphaISA::IPR_CC_CTL:
+ case 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:
+ case 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:
+ case IPR_PALtemp23:
// write entire quad w/ no side-effect
old = ipr[idx];
ipr[idx] = val;
@@ -349,23 +333,23 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
#endif
break;
- case AlphaISA::IPR_DTB_PTE:
+ case IPR_DTB_PTE:
// write entire quad w/ no side-effect, tag is forthcoming
ipr[idx] = val;
break;
- case AlphaISA::IPR_EXC_ADDR:
+ case 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:
+ case IPR_ASTRR:
+ case IPR_ASTER:
// only write least significant four bits - privilege mask
ipr[idx] = val & 0xf;
break;
- case AlphaISA::IPR_IPLR:
+ case IPR_IPLR:
#ifdef DEBUG
if (break_ipl != -1 && break_ipl == (val & 0x1f))
debug_break();
@@ -379,175 +363,173 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
#endif
break;
- case AlphaISA::IPR_DTB_CM:
+ case IPR_DTB_CM:
#if FULL_SYSTEM
if (val & 0x18) {
if (tc->getKernelStats())
- tc->getKernelStats()->mode(TheISA::Kernel::user, tc);
+ tc->getKernelStats()->mode(Kernel::user, tc);
} else {
if (tc->getKernelStats())
- tc->getKernelStats()->mode(TheISA::Kernel::kernel, tc);
+ tc->getKernelStats()->mode(Kernel::kernel, tc);
}
#endif
- case AlphaISA::IPR_ICM:
+ case IPR_ICM:
// only write two mode bits - processor mode
ipr[idx] = val & 0x18;
break;
- case AlphaISA::IPR_ALT_MODE:
+ case IPR_ALT_MODE:
// only write two mode bits - processor mode
ipr[idx] = val & 0x18;
break;
- case AlphaISA::IPR_MCSR:
+ case IPR_MCSR:
// more here after optimization...
ipr[idx] = val;
break;
- case AlphaISA::IPR_SIRR:
+ case IPR_SIRR:
// only write software interrupt mask
ipr[idx] = val & 0x7fff0;
break;
- case AlphaISA::IPR_ICSR:
+ case IPR_ICSR:
ipr[idx] = val & ULL(0xffffff0300);
break;
- case AlphaISA::IPR_IVPTBR:
- case AlphaISA::IPR_MVPTBR:
+ case IPR_IVPTBR:
+ case IPR_MVPTBR:
ipr[idx] = val & ULL(0xffffffffc0000000);
break;
- case AlphaISA::IPR_DC_TEST_CTL:
+ case IPR_DC_TEST_CTL:
ipr[idx] = val & 0x1ffb;
break;
- case AlphaISA::IPR_DC_MODE:
- case AlphaISA::IPR_MAF_MODE:
+ case IPR_DC_MODE:
+ case IPR_MAF_MODE:
ipr[idx] = val & 0x3f;
break;
- case AlphaISA::IPR_ITB_ASN:
+ case IPR_ITB_ASN:
ipr[idx] = val & 0x7f0;
break;
- case AlphaISA::IPR_DTB_ASN:
+ case IPR_DTB_ASN:
ipr[idx] = val & ULL(0xfe00000000000000);
break;
- case AlphaISA::IPR_EXC_SUM:
- case AlphaISA::IPR_EXC_MASK:
+ case IPR_EXC_SUM:
+ case 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:
+ case IPR_INTID:
+ case IPR_SL_RCV:
+ case IPR_MM_STAT:
+ case IPR_ITB_PTE_TEMP:
+ case IPR_DTB_PTE_TEMP:
// read-only registers
panic("Tried to write read only ipr %d\n", idx);
- case AlphaISA::IPR_HWINT_CLR:
- case AlphaISA::IPR_SL_XMIT:
- case AlphaISA::IPR_DC_FLUSH:
- case AlphaISA::IPR_IC_FLUSH:
+ case IPR_HWINT_CLR:
+ case IPR_SL_XMIT:
+ case IPR_DC_FLUSH:
+ case IPR_IC_FLUSH:
// the following are write only
ipr[idx] = val;
break;
- case AlphaISA::IPR_DTB_IA:
+ case IPR_DTB_IA:
// really a control write
ipr[idx] = 0;
tc->getDTBPtr()->flushAll();
break;
- case AlphaISA::IPR_DTB_IAP:
+ case IPR_DTB_IAP:
// really a control write
ipr[idx] = 0;
tc->getDTBPtr()->flushProcesses();
break;
- case AlphaISA::IPR_DTB_IS:
+ case IPR_DTB_IS:
// really a control write
ipr[idx] = val;
- tc->getDTBPtr()->flushAddr(val,
- EV5::DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
+ tc->getDTBPtr()->flushAddr(val, DTB_ASN_ASN(ipr[IPR_DTB_ASN]));
break;
- case AlphaISA::IPR_DTB_TAG: {
- struct AlphaISA::TlbEntry entry;
+ case IPR_DTB_TAG: {
+ struct TlbEntry entry;
// FIXME: granularity hints NYI...
- if (EV5::DTB_PTE_GH(ipr[AlphaISA::IPR_DTB_PTE]) != 0)
+ if (DTB_PTE_GH(ipr[IPR_DTB_PTE]) != 0)
panic("PTE GH field != 0");
// write entire quad
ipr[idx] = val;
// construct PTE for new entry
- entry.ppn = EV5::DTB_PTE_PPN(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.xre = EV5::DTB_PTE_XRE(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.xwe = EV5::DTB_PTE_XWE(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.fonr = EV5::DTB_PTE_FONR(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.fonw = EV5::DTB_PTE_FONW(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.asma = EV5::DTB_PTE_ASMA(ipr[AlphaISA::IPR_DTB_PTE]);
- entry.asn = EV5::DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]);
+ entry.ppn = DTB_PTE_PPN(ipr[IPR_DTB_PTE]);
+ entry.xre = DTB_PTE_XRE(ipr[IPR_DTB_PTE]);
+ entry.xwe = DTB_PTE_XWE(ipr[IPR_DTB_PTE]);
+ entry.fonr = DTB_PTE_FONR(ipr[IPR_DTB_PTE]);
+ entry.fonw = DTB_PTE_FONW(ipr[IPR_DTB_PTE]);
+ entry.asma = DTB_PTE_ASMA(ipr[IPR_DTB_PTE]);
+ entry.asn = DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
// insert new TAG/PTE value into data TLB
tc->getDTBPtr()->insert(val, entry);
}
break;
- case AlphaISA::IPR_ITB_PTE: {
- struct AlphaISA::TlbEntry entry;
+ case IPR_ITB_PTE: {
+ struct TlbEntry entry;
// FIXME: granularity hints NYI...
- if (EV5::ITB_PTE_GH(val) != 0)
+ if (ITB_PTE_GH(val) != 0)
panic("PTE GH field != 0");
// write entire quad
ipr[idx] = val;
// construct PTE for new entry
- entry.ppn = EV5::ITB_PTE_PPN(val);
- entry.xre = EV5::ITB_PTE_XRE(val);
+ entry.ppn = ITB_PTE_PPN(val);
+ entry.xre = ITB_PTE_XRE(val);
entry.xwe = 0;
- entry.fonr = EV5::ITB_PTE_FONR(val);
- entry.fonw = EV5::ITB_PTE_FONW(val);
- entry.asma = EV5::ITB_PTE_ASMA(val);
- entry.asn = EV5::ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]);
+ entry.fonr = ITB_PTE_FONR(val);
+ entry.fonw = ITB_PTE_FONW(val);
+ entry.asma = ITB_PTE_ASMA(val);
+ entry.asn = ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
// insert new TAG/PTE value into data TLB
- tc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], entry);
+ tc->getITBPtr()->insert(ipr[IPR_ITB_TAG], entry);
}
break;
- case AlphaISA::IPR_ITB_IA:
+ case IPR_ITB_IA:
// really a control write
ipr[idx] = 0;
tc->getITBPtr()->flushAll();
break;
- case AlphaISA::IPR_ITB_IAP:
+ case IPR_ITB_IAP:
// really a control write
ipr[idx] = 0;
tc->getITBPtr()->flushProcesses();
break;
- case AlphaISA::IPR_ITB_IS:
+ case IPR_ITB_IS:
// really a control write
ipr[idx] = val;
- tc->getITBPtr()->flushAddr(val,
- EV5::ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
+ tc->getITBPtr()->flushAddr(val, ITB_ASN_ASN(ipr[IPR_ITB_ASN]));
break;
default:
@@ -558,17 +540,38 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
// no error...
}
-
void
-AlphaISA::copyIprs(ThreadContext *src, ThreadContext *dest)
+copyIprs(ThreadContext *src, ThreadContext *dest)
{
- for (int i = 0; i < NumInternalProcRegs; ++i) {
+ for (int i = 0; i < NumInternalProcRegs; ++i)
dest->setMiscRegNoEffect(i, src->readMiscRegNoEffect(i));
- }
}
+} // namespace AlphaISA
+
#if FULL_SYSTEM
+using namespace AlphaISA;
+
+Fault
+SimpleThread::hwrei()
+{
+ if (!(readPC() & 0x3))
+ return new UnimplementedOpcodeFault;
+
+ setNextPC(readMiscRegNoEffect(IPR_EXC_ADDR));
+
+ CPA::cpa()->swAutoBegin(tc, readNextPC());
+
+ if (!misspeculating()) {
+ if (kernelStats)
+ kernelStats->hwrei();
+ }
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
/**
* Check for special simulator handling of specific PAL calls.
* If return value is false, actual PAL call will be suppressed.
diff --git a/src/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh
index 4dd225786..1915d822b 100644
--- a/src/arch/alpha/ev5.hh
+++ b/src/arch/alpha/ev5.hh
@@ -36,10 +36,7 @@
#include "config/alpha_tlaser.hh"
#include "arch/alpha/isa_traits.hh"
-namespace EV5 {
-
-//It seems like a safe assumption EV5 only applies to alpha
-using namespace AlphaISA;
+namespace AlphaISA {
#if ALPHA_TLASER
const uint64_t AsnMask = ULL(0x7f);
@@ -51,8 +48,8 @@ const int VAddrImplBits = 43;
const Addr VAddrImplMask = (ULL(1) << VAddrImplBits) - 1;
const Addr VAddrUnImplMask = ~VAddrImplMask;
inline Addr VAddrImpl(Addr a) { return a & VAddrImplMask; }
-inline Addr VAddrVPN(Addr a) { return a >> AlphaISA::PageShift; }
-inline Addr VAddrOffset(Addr a) { return a & AlphaISA::PageOffset; }
+inline Addr VAddrVPN(Addr a) { return a >> PageShift; }
+inline Addr VAddrOffset(Addr a) { return a & PageOffset; }
inline Addr VAddrSpaceEV5(Addr a) { return a >> 41 & 0x3; }
inline Addr VAddrSpaceEV6(Addr a) { return a >> 41 & 0x7f; }
@@ -68,7 +65,9 @@ const Addr PAddrUncachedBit39 = ULL(0x8000000000);
const Addr PAddrUncachedBit40 = ULL(0x10000000000);
const Addr PAddrUncachedBit43 = ULL(0x80000000000);
const Addr PAddrUncachedMask = ULL(0x807ffffffff); // Clear PA<42:35>
-inline Addr Phys2K0Seg(Addr addr)
+
+inline Addr
+Phys2K0Seg(Addr addr)
{
#if !ALPHA_TLASER
if (addr & PAddrUncachedBit43) {
@@ -76,12 +75,12 @@ inline Addr Phys2K0Seg(Addr addr)
addr |= PAddrUncachedBit40;
}
#endif
- return addr | AlphaISA::K0SegBase;
+ return addr | K0SegBase;
}
inline int DTB_ASN_ASN(uint64_t reg) { return reg >> 57 & AsnMask; }
inline Addr DTB_PTE_PPN(uint64_t reg)
-{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; }
+{ return reg >> 32 & ((ULL(1) << (PAddrImplBits - PageShift)) - 1); }
inline int DTB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; }
inline int DTB_PTE_XWE(uint64_t reg) { return reg >> 12 & 0xf; }
inline int DTB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; }
@@ -91,7 +90,7 @@ inline int DTB_PTE_ASMA(uint64_t reg) { return reg >> 4 & 0x1; }
inline int ITB_ASN_ASN(uint64_t reg) { return reg >> 4 & AsnMask; }
inline Addr ITB_PTE_PPN(uint64_t reg)
-{ return reg >> 32 & (ULL(1) << PAddrImplBits - AlphaISA::PageShift) - 1; }
+{ return reg >> 32 & ((ULL(1) << (PAddrImplBits - PageShift)) - 1); }
inline int ITB_PTE_XRE(uint64_t reg) { return reg >> 8 & 0xf; }
inline bool ITB_PTE_FONR(uint64_t reg) { return reg >> 1 & 0x1; }
inline bool ITB_PTE_FONW(uint64_t reg) { return reg >> 2 & 0x1; }
@@ -114,12 +113,12 @@ const uint64_t MM_STAT_FONW_MASK = ULL(0x0008);
const uint64_t MM_STAT_FONR_MASK = ULL(0x0004);
const uint64_t MM_STAT_ACV_MASK = ULL(0x0002);
const uint64_t MM_STAT_WR_MASK = ULL(0x0001);
-inline int Opcode(AlphaISA::MachInst inst) { return inst >> 26 & 0x3f; }
-inline int Ra(AlphaISA::MachInst inst) { return inst >> 21 & 0x1f; }
+inline int Opcode(MachInst inst) { return inst >> 26 & 0x3f; }
+inline int Ra(MachInst inst) { return inst >> 21 & 0x1f; }
const Addr PalBase = 0x4000;
const Addr PalMax = 0x10000;
-/* namespace EV5 */ }
+} // namespace AlphaISA
#endif // __ARCH_ALPHA_EV5_HH__
diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
index 20591b357..e93e16711 100644
--- a/src/arch/alpha/faults.cc
+++ b/src/arch/alpha/faults.cc
@@ -40,8 +40,7 @@
#include "mem/page_table.hh"
#endif
-namespace AlphaISA
-{
+namespace AlphaISA {
FaultName MachineCheckFault::_name = "mchk";
FaultVect MachineCheckFault::_vect = 0x0401;
@@ -109,64 +108,67 @@ FaultStat IntegerOverflowFault::_count;
#if FULL_SYSTEM
-void AlphaFault::invoke(ThreadContext * tc)
+void
+AlphaFault::invoke(ThreadContext *tc)
{
FaultBase::invoke(tc);
countStat()++;
// exception restart address
if (setRestartAddress() || !(tc->readPC() & 0x3))
- tc->setMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR, tc->readPC());
+ tc->setMiscRegNoEffect(IPR_EXC_ADDR, tc->readPC());
if (skipFaultingInstruction()) {
// traps... skip faulting instruction.
- tc->setMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
- tc->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR) + 4);
+ tc->setMiscRegNoEffect(IPR_EXC_ADDR,
+ tc->readMiscRegNoEffect(IPR_EXC_ADDR) + 4);
}
- tc->setPC(tc->readMiscRegNoEffect(AlphaISA::IPR_PAL_BASE) + vect());
+ tc->setPC(tc->readMiscRegNoEffect(IPR_PAL_BASE) + vect());
tc->setNextPC(tc->readPC() + sizeof(MachInst));
}
-void ArithmeticFault::invoke(ThreadContext * tc)
+void
+ArithmeticFault::invoke(ThreadContext *tc)
{
FaultBase::invoke(tc);
panic("Arithmetic traps are unimplemented!");
}
-void DtbFault::invoke(ThreadContext * tc)
+void
+DtbFault::invoke(ThreadContext *tc)
{
// Set fault address and flags. Even though we're modeling an
// EV5, we use the EV6 technique of not latching fault registers
// on VPTE loads (instead of locking the registers until IPR_VA is
// read, like the EV5). The EV6 approach is cleaner and seems to
// work with EV5 PAL code, but not the other way around.
- if (!tc->misspeculating()
- && !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) {
+ if (!tc->misspeculating() &&
+ reqFlags.noneSet(Request::VPTE|Request::NO_FAULT)) {
// set VA register with faulting address
- tc->setMiscRegNoEffect(AlphaISA::IPR_VA, vaddr);
+ tc->setMiscRegNoEffect(IPR_VA, vaddr);
// set MM_STAT register flags
- tc->setMiscRegNoEffect(AlphaISA::IPR_MM_STAT,
- (((EV5::Opcode(tc->getInst()) & 0x3f) << 11)
- | ((EV5::Ra(tc->getInst()) & 0x1f) << 6)
- | (flags & 0x3f)));
+ tc->setMiscRegNoEffect(IPR_MM_STAT,
+ (((Opcode(tc->getInst()) & 0x3f) << 11) |
+ ((Ra(tc->getInst()) & 0x1f) << 6) |
+ (flags & 0x3f)));
// set VA_FORM register with faulting formatted address
- tc->setMiscRegNoEffect(AlphaISA::IPR_VA_FORM,
- tc->readMiscRegNoEffect(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
+ tc->setMiscRegNoEffect(IPR_VA_FORM,
+ tc->readMiscRegNoEffect(IPR_MVPTBR) | (vaddr.vpn() << 3));
}
AlphaFault::invoke(tc);
}
-void ItbFault::invoke(ThreadContext * tc)
+void
+ItbFault::invoke(ThreadContext *tc)
{
if (!tc->misspeculating()) {
- tc->setMiscRegNoEffect(AlphaISA::IPR_ITB_TAG, pc);
- tc->setMiscRegNoEffect(AlphaISA::IPR_IFAULT_VA_FORM,
- tc->readMiscRegNoEffect(AlphaISA::IPR_IVPTBR) |
- (AlphaISA::VAddr(pc).vpn() << 3));
+ tc->setMiscRegNoEffect(IPR_ITB_TAG, pc);
+ tc->setMiscRegNoEffect(IPR_IFAULT_VA_FORM,
+ tc->readMiscRegNoEffect(IPR_IVPTBR) | (VAddr(pc).vpn() << 3));
}
AlphaFault::invoke(tc);
@@ -174,12 +176,13 @@ void ItbFault::invoke(ThreadContext * tc)
#else
-void ItbPageFault::invoke(ThreadContext * tc)
+void
+ItbPageFault::invoke(ThreadContext *tc)
{
Process *p = tc->getProcessPtr();
TlbEntry entry;
bool success = p->pTable->lookup(pc, entry);
- if(!success) {
+ if (!success) {
panic("Tried to execute unmapped address %#x.\n", pc);
} else {
VAddr vaddr(pc);
@@ -187,16 +190,17 @@ void ItbPageFault::invoke(ThreadContext * tc)
}
}
-void NDtbMissFault::invoke(ThreadContext * tc)
+void
+NDtbMissFault::invoke(ThreadContext *tc)
{
Process *p = tc->getProcessPtr();
TlbEntry entry;
bool success = p->pTable->lookup(vaddr, entry);
- if(!success) {
+ if (!success) {
p->checkAndAllocNextPage(vaddr);
success = p->pTable->lookup(vaddr, entry);
}
- if(!success) {
+ if (!success) {
panic("Tried to access unmapped address %#x.\n", (Addr)vaddr);
} else {
tc->getDTBPtr()->insert(vaddr.page(), entry);
diff --git a/src/arch/alpha/faults.hh b/src/arch/alpha/faults.hh
index 74699b2b5..9d90c7719 100644
--- a/src/arch/alpha/faults.hh
+++ b/src/arch/alpha/faults.hh
@@ -29,18 +29,16 @@
* Kevin Lim
*/
-#ifndef __ALPHA_FAULTS_HH__
-#define __ALPHA_FAULTS_HH__
+#ifndef __ARCH_ALPHA_FAULTS_HH__
+#define __ARCH_ALPHA_FAULTS_HH__
+#include "arch/alpha/pagetable.hh"
#include "config/full_system.hh"
#include "sim/faults.hh"
-#include "arch/alpha/pagetable.hh"
-
// The design of the "name" and "vect" functions is in sim/faults.hh
-namespace AlphaISA
-{
+namespace AlphaISA {
typedef const Addr FaultVect;
@@ -63,6 +61,7 @@ class MachineCheckFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -76,6 +75,7 @@ class AlignmentFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -94,6 +94,7 @@ class ResetFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -102,12 +103,14 @@ class ResetFault : public AlphaFault
class ArithmeticFault : public AlphaFault
{
- protected:
- bool skipFaultingInstruction() {return true;}
private:
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
+ protected:
+ bool skipFaultingInstruction() {return true;}
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -119,12 +122,14 @@ class ArithmeticFault : public AlphaFault
class InterruptFault : public AlphaFault
{
- protected:
- bool setRestartAddress() {return false;}
private:
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
+ protected:
+ bool setRestartAddress() {return false;}
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -134,11 +139,12 @@ class InterruptFault : public AlphaFault
class DtbFault : public AlphaFault
{
protected:
- AlphaISA::VAddr vaddr;
- uint32_t reqFlags;
+ VAddr vaddr;
+ Request::Flags reqFlags;
uint64_t flags;
+
public:
- DtbFault(AlphaISA::VAddr _vaddr, uint32_t _reqFlags, uint64_t _flags)
+ DtbFault(VAddr _vaddr, Request::Flags _reqFlags, uint64_t _flags)
: vaddr(_vaddr), reqFlags(_reqFlags), flags(_flags)
{ }
FaultName name() const = 0;
@@ -155,8 +161,9 @@ class NDtbMissFault : public DtbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- NDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ NDtbMissFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags)
: DtbFault(vaddr, reqFlags, flags)
{ }
FaultName name() const {return _name;}
@@ -173,8 +180,9 @@ class PDtbMissFault : public DtbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- PDtbMissFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ PDtbMissFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags)
: DtbFault(vaddr, reqFlags, flags)
{ }
FaultName name() const {return _name;}
@@ -188,8 +196,9 @@ class DtbPageFault : public DtbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- DtbPageFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ DtbPageFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags)
: DtbFault(vaddr, reqFlags, flags)
{ }
FaultName name() const {return _name;}
@@ -203,8 +212,9 @@ class DtbAcvFault : public DtbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- DtbAcvFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ DtbAcvFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags)
: DtbFault(vaddr, reqFlags, flags)
{ }
FaultName name() const {return _name;}
@@ -218,8 +228,9 @@ class DtbAlignmentFault : public DtbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- DtbAlignmentFault(AlphaISA::VAddr vaddr, uint32_t reqFlags, uint64_t flags)
+ DtbAlignmentFault(VAddr vaddr, Request::Flags reqFlags, uint64_t flags)
: DtbFault(vaddr, reqFlags, flags)
{ }
FaultName name() const {return _name;}
@@ -231,10 +242,9 @@ class ItbFault : public AlphaFault
{
protected:
Addr pc;
+
public:
- ItbFault(Addr _pc)
- : pc(_pc)
- { }
+ ItbFault(Addr _pc) : pc(_pc) { }
FaultName name() const = 0;
FaultVect vect() = 0;
FaultStat & countStat() = 0;
@@ -249,10 +259,9 @@ class ItbPageFault : public ItbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- ItbPageFault(Addr pc)
- : ItbFault(pc)
- { }
+ ItbPageFault(Addr pc) : ItbFault(pc) { }
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
FaultStat & countStat() {return _count;}
@@ -267,10 +276,9 @@ class ItbAcvFault : public ItbFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
- ItbAcvFault(Addr pc)
- : ItbFault(pc)
- { }
+ ItbAcvFault(Addr pc) : ItbFault(pc) { }
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
FaultStat & countStat() {return _count;}
@@ -282,6 +290,7 @@ class UnimplementedOpcodeFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -294,6 +303,7 @@ class FloatEnableFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -302,12 +312,14 @@ class FloatEnableFault : public AlphaFault
class PalFault : public AlphaFault
{
- protected:
- bool skipFaultingInstruction() {return true;}
private:
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
+ protected:
+ bool skipFaultingInstruction() {return true;}
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
@@ -320,12 +332,13 @@ class IntegerOverflowFault : public AlphaFault
static FaultName _name;
static FaultVect _vect;
static FaultStat _count;
+
public:
FaultName name() const {return _name;}
FaultVect vect() {return _vect;}
FaultStat & countStat() {return _count;}
};
-} // AlphaISA namespace
+} // namespace AlphaISA
-#endif // __FAULTS_HH__
+#endif // __ARCH_ALPHA_FAULTS_HH__
diff --git a/src/arch/alpha/floatregfile.cc b/src/arch/alpha/floatregfile.cc
index 512b0df95..192b0f1d4 100644
--- a/src/arch/alpha/floatregfile.cc
+++ b/src/arch/alpha/floatregfile.cc
@@ -30,20 +30,28 @@
* Kevin Lim
*/
+#include <cstring>
+
#include "arch/alpha/floatregfile.hh"
#include "sim/serialize.hh"
-namespace AlphaISA
+namespace AlphaISA {
+void
+FloatRegFile::clear()
{
- void
- FloatRegFile::serialize(std::ostream &os)
- {
- SERIALIZE_ARRAY(q, NumFloatRegs);
- }
+ std::memset(d, 0, sizeof(d));
+}
- void
- FloatRegFile::unserialize(Checkpoint *cp, const std::string &section)
- {
- UNSERIALIZE_ARRAY(q, NumFloatRegs);
- }
+void
+FloatRegFile::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(q, NumFloatRegs);
}
+
+void
+FloatRegFile::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(q, NumFloatRegs);
+}
+
+} // namespace AlphaISA
diff --git a/src/arch/alpha/floatregfile.hh b/src/arch/alpha/floatregfile.hh
index 0c5fe17a7..d5f9eec0f 100644
--- a/src/arch/alpha/floatregfile.hh
+++ b/src/arch/alpha/floatregfile.hh
@@ -32,37 +32,30 @@
#ifndef __ARCH_ALPHA_FLOATREGFILE_HH__
#define __ARCH_ALPHA_FLOATREGFILE_HH__
+#include <iosfwd>
+#include <string>
+
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/types.hh"
-#include <cstring>
-#include <iostream>
-
class Checkpoint;
-namespace AlphaISA
-{
- static inline std::string getFloatRegName(RegIndex)
- {
- return "";
- }
-
- class FloatRegFile
- {
- public:
+namespace AlphaISA {
- union {
- uint64_t q[NumFloatRegs]; // integer qword view
- double d[NumFloatRegs]; // double-precision floating point view
- };
+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 clear();
- void unserialize(Checkpoint *cp, const std::string &section);
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+};
- void clear()
- { std::memset(d, 0, sizeof(d)); }
- };
-}
+} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_FLOATREGFILE_HH__
diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc
index f666de604..e541b260c 100644
--- a/src/arch/alpha/freebsd/system.cc
+++ b/src/arch/alpha/freebsd/system.cc
@@ -62,29 +62,25 @@ FreebsdAlphaSystem::FreebsdAlphaSystem(Params *p)
addKernelFuncEvent<SkipCalibrateClocksEvent>("calibrate_clocks");
}
-
FreebsdAlphaSystem::~FreebsdAlphaSystem()
{
delete skipDelayEvent;
delete skipCalibrateClocks;
}
-
void
FreebsdAlphaSystem::doCalibrateClocks(ThreadContext *tc)
{
Addr ppc_vaddr = 0;
Addr timer_vaddr = 0;
- assert(NumArgumentRegs >= 3);
- ppc_vaddr = (Addr)tc->readIntReg(ArgumentReg[1]);
- timer_vaddr = (Addr)tc->readIntReg(ArgumentReg[2]);
+ ppc_vaddr = (Addr)tc->readIntReg(17);
+ timer_vaddr = (Addr)tc->readIntReg(18);
virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency);
virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY);
}
-
void
FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ThreadContext *tc)
{
diff --git a/src/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh
index 8e8493f97..48f6238c0 100644
--- a/src/arch/alpha/freebsd/system.hh
+++ b/src/arch/alpha/freebsd/system.hh
@@ -57,7 +57,6 @@ class FreebsdAlphaSystem : public AlphaSystem
~FreebsdAlphaSystem();
void doCalibrateClocks(ThreadContext *tc);
-
};
#endif // __ARCH_ALPHA_FREEBSD_SYSTEM_HH__
diff --git a/src/arch/alpha/idle_event.cc b/src/arch/alpha/idle_event.cc
index f0f1eab7a..bb68782e7 100644
--- a/src/arch/alpha/idle_event.cc
+++ b/src/arch/alpha/idle_event.cc
@@ -33,13 +33,14 @@
#include "arch/alpha/kernel_stats.hh"
#include "cpu/thread_context.hh"
-using namespace TheISA;
+using namespace AlphaISA;
void
IdleStartEvent::process(ThreadContext *tc)
{
- if (tc->getKernelStats())
- tc->getKernelStats()->setIdleProcess(
- tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23), tc);
+ if (tc->getKernelStats()) {
+ MiscReg val = tc->readMiscRegNoEffect(IPR_PALtemp23);
+ tc->getKernelStats()->setIdleProcess(val, tc);
+ }
remove();
}
diff --git a/src/cpu/o3/sparc/thread_context.cc b/src/arch/alpha/interrupts.cc
index d85aff502..4b5dc5661 100755..100644
--- a/src/cpu/o3/sparc/thread_context.cc
+++ b/src/arch/alpha/interrupts.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,8 +28,10 @@
* Authors: Gabe Black
*/
-#include "cpu/o3/thread_context.hh"
-#include "cpu/o3/thread_context_impl.hh"
-
-template class O3ThreadContext<SparcSimpleImpl>;
+#include "arch/alpha/interrupts.hh"
+AlphaISA::Interrupts *
+AlphaInterruptsParams::create()
+{
+ return new AlphaISA::Interrupts(this);
+}
diff --git a/src/arch/alpha/interrupts.hh b/src/arch/alpha/interrupts.hh
index 6453edf97..f8e0ad4ef 100644
--- a/src/arch/alpha/interrupts.hh
+++ b/src/arch/alpha/interrupts.hh
@@ -35,142 +35,163 @@
#include "arch/alpha/faults.hh"
#include "arch/alpha/isa_traits.hh"
#include "base/compiler.hh"
+#include "base/trace.hh"
#include "cpu/thread_context.hh"
+#include "params/AlphaInterrupts.hh"
+#include "sim/sim_object.hh"
-namespace AlphaISA
+namespace AlphaISA {
+
+class Interrupts : public SimObject
{
- class Interrupts
+ private:
+ bool newInfoSet;
+ int newIpl;
+ int newSummary;
+ BaseCPU * cpu;
+
+ protected:
+ uint64_t interrupts[NumInterruptLevels];
+ uint64_t intstatus;
+
+ public:
+ typedef AlphaInterruptsParams Params;
+
+ const Params *
+ params() const
{
- protected:
- uint64_t interrupts[NumInterruptLevels];
- uint64_t intstatus;
-
- public:
- Interrupts()
- {
- memset(interrupts, 0, sizeof(interrupts));
- intstatus = 0;
- newInfoSet = false;
- }
+ return dynamic_cast<const Params *>(_params);
+ }
- void post(int int_num, int index)
- {
- DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
+ Interrupts(Params * p) : SimObject(p), cpu(NULL)
+ {
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+ newInfoSet = false;
+ }
- if (int_num < 0 || int_num >= NumInterruptLevels)
- panic("int_num out of bounds\n");
+ void
+ setCPU(BaseCPU * _cpu)
+ {
+ cpu = _cpu;
+ }
- if (index < 0 || index >= sizeof(uint64_t) * 8)
- panic("int_num out of bounds\n");
+ void
+ post(int int_num, int index)
+ {
+ DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
- interrupts[int_num] |= 1 << index;
- intstatus |= (ULL(1) << int_num);
- }
+ if (int_num < 0 || int_num >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
- void clear(int int_num, int index)
- {
- DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
+ if (index < 0 || index >= (int)sizeof(uint64_t) * 8)
+ panic("int_num out of bounds\n");
- if (int_num < 0 || int_num >= TheISA::NumInterruptLevels)
- panic("int_num out of bounds\n");
+ interrupts[int_num] |= 1 << index;
+ intstatus |= (ULL(1) << int_num);
+ }
- if (index < 0 || index >= sizeof(uint64_t) * 8)
- panic("int_num out of bounds\n");
+ void
+ clear(int int_num, int index)
+ {
+ DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
- interrupts[int_num] &= ~(1 << index);
- if (interrupts[int_num] == 0)
- intstatus &= ~(ULL(1) << int_num);
- }
+ if (int_num < 0 || int_num >= NumInterruptLevels)
+ panic("int_num out of bounds\n");
- void clear_all()
- {
- DPRINTF(Interrupt, "Interrupts all cleared\n");
+ if (index < 0 || index >= (int)sizeof(uint64_t) * 8)
+ panic("int_num out of bounds\n");
- memset(interrupts, 0, sizeof(interrupts));
- intstatus = 0;
- }
+ interrupts[int_num] &= ~(1 << index);
+ if (interrupts[int_num] == 0)
+ intstatus &= ~(ULL(1) << int_num);
+ }
- void serialize(std::ostream &os)
- {
- SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
- SERIALIZE_SCALAR(intstatus);
- }
+ void
+ clearAll()
+ {
+ DPRINTF(Interrupt, "Interrupts all cleared\n");
- void unserialize(Checkpoint *cp, const std::string &section)
- {
- UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
- UNSERIALIZE_SCALAR(intstatus);
- }
+ memset(interrupts, 0, sizeof(interrupts));
+ intstatus = 0;
+ }
- bool check_interrupts(ThreadContext * tc) const
- {
- return (intstatus != 0) && !(tc->readPC() & 0x3);
- }
+ void
+ serialize(std::ostream &os)
+ {
+ SERIALIZE_ARRAY(interrupts, NumInterruptLevels);
+ SERIALIZE_SCALAR(intstatus);
+ }
- Fault getInterrupt(ThreadContext * tc)
- {
- int ipl = 0;
- int summary = 0;
-
- if (tc->readMiscRegNoEffect(IPR_ASTRR))
- panic("asynchronous traps not implemented\n");
-
- if (tc->readMiscRegNoEffect(IPR_SIRR)) {
- for (int i = INTLEVEL_SOFTWARE_MIN;
- i < INTLEVEL_SOFTWARE_MAX; i++) {
- if (tc->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) {
- // See table 4-19 of 21164 hardware reference
- ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
- summary |= (ULL(1) << i);
- }
- }
- }
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
+ {
+ UNSERIALIZE_ARRAY(interrupts, NumInterruptLevels);
+ UNSERIALIZE_SCALAR(intstatus);
+ }
+
+ bool
+ checkInterrupts(ThreadContext *tc) const
+ {
+ return (intstatus != 0) && !(tc->readPC() & 0x3);
+ }
- uint64_t interrupts = intstatus;
- if (interrupts) {
- 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);
- }
+ Fault
+ getInterrupt(ThreadContext *tc)
+ {
+ int ipl = 0;
+ int summary = 0;
+
+ if (tc->readMiscRegNoEffect(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (tc->readMiscRegNoEffect(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (tc->readMiscRegNoEffect(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
}
}
+ }
- if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) {
- newIpl = ipl;
- newSummary = summary;
- newInfoSet = true;
- DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
- tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary);
-
- return new InterruptFault;
- } else {
- return NoFault;
+ uint64_t interrupts = intstatus;
+ if (interrupts) {
+ 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);
+ }
}
}
- void updateIntrInfo(ThreadContext *tc)
- {
- assert(newInfoSet);
- tc->setMiscRegNoEffect(IPR_ISR, newSummary);
- tc->setMiscRegNoEffect(IPR_INTID, newIpl);
- newInfoSet = false;
- }
+ if (ipl && ipl > tc->readMiscRegNoEffect(IPR_IPLR)) {
+ newIpl = ipl;
+ newSummary = summary;
+ newInfoSet = true;
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ tc->readMiscRegNoEffect(IPR_IPLR), ipl, summary);
- uint64_t get_vec(int int_num)
- {
- panic("Shouldn't be called for Alpha\n");
- M5_DUMMY_RETURN
+ return new InterruptFault;
+ } else {
+ return NoFault;
}
+ }
+
+ void
+ updateIntrInfo(ThreadContext *tc)
+ {
+ assert(newInfoSet);
+ tc->setMiscRegNoEffect(IPR_ISR, newSummary);
+ tc->setMiscRegNoEffect(IPR_INTID, newIpl);
+ newInfoSet = false;
+ }
+};
- private:
- bool newInfoSet;
- int newIpl;
- int newSummary;
- };
-}
+} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_INTERRUPT_HH__
diff --git a/src/arch/alpha/intregfile.cc b/src/arch/alpha/intregfile.cc
index 0188cb2cd..8f692f856 100644
--- a/src/arch/alpha/intregfile.cc
+++ b/src/arch/alpha/intregfile.cc
@@ -30,36 +30,45 @@
* Kevin Lim
*/
+#include <cstring>
+
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/intregfile.hh"
#include "sim/serialize.hh"
-namespace AlphaISA
-{
+namespace AlphaISA {
+
#if FULL_SYSTEM
- const int reg_redir[AlphaISA::NumIntRegs] = {
- /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7,
- /* 8 */ 32, 33, 34, 35, 36, 37, 38, 15,
- /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23,
- /* 24 */ 24, 39, 26, 27, 28, 29, 30, 31 };
+const int reg_redir[NumIntRegs] = {
+ /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* 8 */ 32, 33, 34, 35, 36, 37, 38, 15,
+ /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23,
+ /* 24 */ 24, 39, 26, 27, 28, 29, 30, 31 };
#else
- const int reg_redir[AlphaISA::NumIntRegs] = {
- /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7,
- /* 8 */ 8, 9, 10, 11, 12, 13, 14, 15,
- /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23,
- /* 24 */ 24, 25, 26, 27, 28, 29, 30, 31 };
+const int reg_redir[NumIntRegs] = {
+ /* 0 */ 0, 1, 2, 3, 4, 5, 6, 7,
+ /* 8 */ 8, 9, 10, 11, 12, 13, 14, 15,
+ /* 16 */ 16, 17, 18, 19, 20, 21, 22, 23,
+ /* 24 */ 24, 25, 26, 27, 28, 29, 30, 31 };
#endif
- void
- IntRegFile::serialize(std::ostream &os)
- {
- SERIALIZE_ARRAY(regs, NumIntRegs);
- }
+void
+IntRegFile::clear()
+{
+ std::memset(regs, 0, sizeof(regs));
+}
+
+void
+IntRegFile::serialize(std::ostream &os)
+{
+ SERIALIZE_ARRAY(regs, NumIntRegs);
+}
- void
- IntRegFile::unserialize(Checkpoint *cp, const std::string &section)
- {
- UNSERIALIZE_ARRAY(regs, NumIntRegs);
- }
+void
+IntRegFile::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ARRAY(regs, NumIntRegs);
}
+} // namespace AlphaISA
+
diff --git a/src/arch/alpha/intregfile.hh b/src/arch/alpha/intregfile.hh
index dea160992..3aa7d92c4 100644
--- a/src/arch/alpha/intregfile.hh
+++ b/src/arch/alpha/intregfile.hh
@@ -32,47 +32,42 @@
#ifndef __ARCH_ALPHA_INTREGFILE_HH__
#define __ARCH_ALPHA_INTREGFILE_HH__
-#include "arch/alpha/types.hh"
+#include <iosfwd>
+#include <string>
-#include <iostream>
-#include <cstring>
+#include "arch/alpha/types.hh"
class Checkpoint;
-namespace AlphaISA
+namespace AlphaISA {
+
+// redirected register map, really only used for the full system case.
+extern const int reg_redir[NumIntRegs];
+
+class IntRegFile
{
- static inline std::string getIntRegName(RegIndex)
+ protected:
+ IntReg regs[NumIntRegs];
+
+ public:
+ IntReg
+ readReg(int intReg)
{
- return "";
+ return regs[intReg];
}
- // redirected register map, really only used for the full system case.
- extern const int reg_redir[NumIntRegs];
-
- class IntRegFile
+ void
+ setReg(int intReg, const IntReg &val)
{
- protected:
- IntReg regs[NumIntRegs];
-
- public:
-
- IntReg readReg(int intReg)
- {
- return regs[intReg];
- }
-
- void setReg(int intReg, const IntReg &val)
- {
- regs[intReg] = val;
- }
+ regs[intReg] = val;
+ }
- void serialize(std::ostream &os);
+ void clear();
- void unserialize(Checkpoint *cp, const std::string &section);
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+};
- void clear()
- { std::memset(regs, 0, sizeof(regs)); }
- };
-}
+} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_INTREGFILE_HH__
diff --git a/src/arch/alpha/ipr.cc b/src/arch/alpha/ipr.cc
index 8e83102eb..502ada5eb 100644
--- a/src/arch/alpha/ipr.cc
+++ b/src/arch/alpha/ipr.cc
@@ -28,113 +28,115 @@
* Authors: Gabe Black
*/
-#include <assert.h>
-#include <string.h>
+#include <cassert>
+#include <cstring>
#include "arch/alpha/ipr.hh"
-namespace AlphaISA
+namespace AlphaISA {
+
+md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs] = {
+
+ //Write only
+ RAW_IPR_HWINT_CLR, // H/W interrupt clear register
+ RAW_IPR_SL_XMIT, // serial line transmit register
+ RAW_IPR_DC_FLUSH,
+ RAW_IPR_IC_FLUSH, // instruction cache flush control
+ RAW_IPR_ALT_MODE, // alternate mode register
+ RAW_IPR_DTB_IA, // DTLB invalidate all register
+ RAW_IPR_DTB_IAP, // DTLB invalidate all process register
+ RAW_IPR_ITB_IA, // ITLB invalidate all register
+ RAW_IPR_ITB_IAP, // ITLB invalidate all process register
+
+ //Read only
+ RAW_IPR_INTID, // interrupt ID register
+ RAW_IPR_SL_RCV, // serial line receive register
+ RAW_IPR_MM_STAT, // data MMU fault status register
+ RAW_IPR_ITB_PTE_TEMP, // ITLB page table entry temp register
+ RAW_IPR_DTB_PTE_TEMP, // DTLB page table entry temporary register
+
+ RAW_IPR_ISR, // interrupt summary register
+ RAW_IPR_ITB_TAG, // ITLB tag register
+ RAW_IPR_ITB_PTE, // ITLB page table entry register
+ RAW_IPR_ITB_ASN, // ITLB address space register
+ RAW_IPR_ITB_IS, // ITLB invalidate select register
+ RAW_IPR_SIRR, // software interrupt request register
+ RAW_IPR_ASTRR, // asynchronous system trap request register
+ RAW_IPR_ASTER, // asynchronous system trap enable register
+ RAW_IPR_EXC_ADDR, // exception address register
+ RAW_IPR_EXC_SUM, // exception summary register
+ RAW_IPR_EXC_MASK, // exception mask register
+ RAW_IPR_PAL_BASE, // PAL base address register
+ RAW_IPR_ICM, // instruction current mode
+ RAW_IPR_IPLR, // interrupt priority level register
+ RAW_IPR_IFAULT_VA_FORM, // formatted faulting virtual addr register
+ RAW_IPR_IVPTBR, // virtual page table base register
+ RAW_IPR_ICSR, // instruction control and status register
+ RAW_IPR_IC_PERR_STAT, // inst cache parity error status register
+ RAW_IPR_PMCTR, // performance counter register
+
+ // PAL temporary registers...
+ // register meanings gleaned from osfpal.s source code
+ RAW_IPR_PALtemp0, // local scratch
+ RAW_IPR_PALtemp1, // local scratch
+ RAW_IPR_PALtemp2, // entUna
+ RAW_IPR_PALtemp3, // CPU specific impure area pointer
+ RAW_IPR_PALtemp4, // memory management temp
+ RAW_IPR_PALtemp5, // memory management temp
+ RAW_IPR_PALtemp6, // memory management temp
+ RAW_IPR_PALtemp7, // entIF
+ RAW_IPR_PALtemp8, // intmask
+ RAW_IPR_PALtemp9, // entSys
+ RAW_IPR_PALtemp10, // ??
+ RAW_IPR_PALtemp11, // entInt
+ RAW_IPR_PALtemp12, // entArith
+ RAW_IPR_PALtemp13, // reserved for platform specific PAL
+ RAW_IPR_PALtemp14, // reserved for platform specific PAL
+ RAW_IPR_PALtemp15, // reserved for platform specific PAL
+ RAW_IPR_PALtemp16, // scratch / whami<7:0> / mces<4:0>
+ RAW_IPR_PALtemp17, // sysval
+ RAW_IPR_PALtemp18, // usp
+ RAW_IPR_PALtemp19, // ksp
+ RAW_IPR_PALtemp20, // PTBR
+ RAW_IPR_PALtemp21, // entMM
+ RAW_IPR_PALtemp22, // kgp
+ RAW_IPR_PALtemp23, // PCBB
+
+ RAW_IPR_DTB_ASN, // DTLB address space number register
+ RAW_IPR_DTB_CM, // DTLB current mode register
+ RAW_IPR_DTB_TAG, // DTLB tag register
+ RAW_IPR_DTB_PTE, // DTLB page table entry register
+
+ RAW_IPR_VA, // fault virtual address register
+ RAW_IPR_VA_FORM, // formatted virtual address register
+ RAW_IPR_MVPTBR, // MTU virtual page table base register
+ RAW_IPR_DTB_IS, // DTLB invalidate single register
+ RAW_IPR_CC, // cycle counter register
+ RAW_IPR_CC_CTL, // cycle counter control register
+ RAW_IPR_MCSR, // MTU control register
+
+ RAW_IPR_DC_PERR_STAT, // Dcache parity error status register
+ RAW_IPR_DC_TEST_CTL, // Dcache test tag control register
+ RAW_IPR_DC_TEST_TAG, // Dcache test tag register
+ RAW_IPR_DC_TEST_TAG_TEMP, // Dcache test tag temporary register
+ RAW_IPR_DC_MODE, // Dcache mode register
+ RAW_IPR_MAF_MODE // miss address file mode register
+};
+
+int IprToMiscRegIndex[MaxInternalProcRegs];
+
+void
+initializeIprTable()
{
- md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs] =
- {
- //Write only
- RAW_IPR_HWINT_CLR, // H/W interrupt clear register
- RAW_IPR_SL_XMIT, // serial line transmit register
- RAW_IPR_DC_FLUSH,
- RAW_IPR_IC_FLUSH, // instruction cache flush control
- RAW_IPR_ALT_MODE, // alternate mode register
- RAW_IPR_DTB_IA, // DTLB invalidate all register
- RAW_IPR_DTB_IAP, // DTLB invalidate all process register
- RAW_IPR_ITB_IA, // ITLB invalidate all register
- RAW_IPR_ITB_IAP, // ITLB invalidate all process register
-
- //Read only
- RAW_IPR_INTID, // interrupt ID register
- RAW_IPR_SL_RCV, // serial line receive register
- RAW_IPR_MM_STAT, // data MMU fault status register
- RAW_IPR_ITB_PTE_TEMP, // ITLB page table entry temp register
- RAW_IPR_DTB_PTE_TEMP, // DTLB page table entry temporary register
-
- RAW_IPR_ISR, // interrupt summary register
- RAW_IPR_ITB_TAG, // ITLB tag register
- RAW_IPR_ITB_PTE, // ITLB page table entry register
- RAW_IPR_ITB_ASN, // ITLB address space register
- RAW_IPR_ITB_IS, // ITLB invalidate select register
- RAW_IPR_SIRR, // software interrupt request register
- RAW_IPR_ASTRR, // asynchronous system trap request register
- RAW_IPR_ASTER, // asynchronous system trap enable register
- RAW_IPR_EXC_ADDR, // exception address register
- RAW_IPR_EXC_SUM, // exception summary register
- RAW_IPR_EXC_MASK, // exception mask register
- RAW_IPR_PAL_BASE, // PAL base address register
- RAW_IPR_ICM, // instruction current mode
- RAW_IPR_IPLR, // interrupt priority level register
- RAW_IPR_IFAULT_VA_FORM, // formatted faulting virtual addr register
- RAW_IPR_IVPTBR, // virtual page table base register
- RAW_IPR_ICSR, // instruction control and status register
- RAW_IPR_IC_PERR_STAT, // inst cache parity error status register
- RAW_IPR_PMCTR, // performance counter register
-
- // PAL temporary registers...
- // register meanings gleaned from osfpal.s source code
- RAW_IPR_PALtemp0, // local scratch
- RAW_IPR_PALtemp1, // local scratch
- RAW_IPR_PALtemp2, // entUna
- RAW_IPR_PALtemp3, // CPU specific impure area pointer
- RAW_IPR_PALtemp4, // memory management temp
- RAW_IPR_PALtemp5, // memory management temp
- RAW_IPR_PALtemp6, // memory management temp
- RAW_IPR_PALtemp7, // entIF
- RAW_IPR_PALtemp8, // intmask
- RAW_IPR_PALtemp9, // entSys
- RAW_IPR_PALtemp10, // ??
- RAW_IPR_PALtemp11, // entInt
- RAW_IPR_PALtemp12, // entArith
- RAW_IPR_PALtemp13, // reserved for platform specific PAL
- RAW_IPR_PALtemp14, // reserved for platform specific PAL
- RAW_IPR_PALtemp15, // reserved for platform specific PAL
- RAW_IPR_PALtemp16, // scratch / whami<7:0> / mces<4:0>
- RAW_IPR_PALtemp17, // sysval
- RAW_IPR_PALtemp18, // usp
- RAW_IPR_PALtemp19, // ksp
- RAW_IPR_PALtemp20, // PTBR
- RAW_IPR_PALtemp21, // entMM
- RAW_IPR_PALtemp22, // kgp
- RAW_IPR_PALtemp23, // PCBB
-
- RAW_IPR_DTB_ASN, // DTLB address space number register
- RAW_IPR_DTB_CM, // DTLB current mode register
- RAW_IPR_DTB_TAG, // DTLB tag register
- RAW_IPR_DTB_PTE, // DTLB page table entry register
-
- RAW_IPR_VA, // fault virtual address register
- RAW_IPR_VA_FORM, // formatted virtual address register
- RAW_IPR_MVPTBR, // MTU virtual page table base register
- RAW_IPR_DTB_IS, // DTLB invalidate single register
- RAW_IPR_CC, // cycle counter register
- RAW_IPR_CC_CTL, // cycle counter control register
- RAW_IPR_MCSR, // MTU control register
-
- RAW_IPR_DC_PERR_STAT, // Dcache parity error status register
- RAW_IPR_DC_TEST_CTL, // Dcache test tag control register
- RAW_IPR_DC_TEST_TAG, // Dcache test tag register
- RAW_IPR_DC_TEST_TAG_TEMP, // Dcache test tag temporary register
- RAW_IPR_DC_MODE, // Dcache mode register
- RAW_IPR_MAF_MODE // miss address file mode register
- };
-
- int IprToMiscRegIndex[MaxInternalProcRegs];
-
- void initializeIprTable()
- {
- static bool initialized = false;
- if(initialized)
- return;
-
- memset(IprToMiscRegIndex, -1, MaxInternalProcRegs * sizeof(int));
-
- for(int x = 0; x < NumInternalProcRegs; x++)
- IprToMiscRegIndex[MiscRegIndexToIpr[x]] = x;
- }
+ static bool initialized = false;
+ if (initialized)
+ return;
+
+ memset(IprToMiscRegIndex, -1, MaxInternalProcRegs * sizeof(int));
+
+ for (int x = 0; x < NumInternalProcRegs; x++)
+ IprToMiscRegIndex[MiscRegIndexToIpr[x]] = x;
}
+} // namespace AlphaISA
+
diff --git a/src/arch/alpha/ipr.hh b/src/arch/alpha/ipr.hh
index b55154764..4e7bf1fa4 100644
--- a/src/arch/alpha/ipr.hh
+++ b/src/arch/alpha/ipr.hh
@@ -32,206 +32,208 @@
#ifndef __ARCH_ALPHA_IPR_HH__
#define __ARCH_ALPHA_IPR_HH__
-namespace AlphaISA
+namespace AlphaISA {
+
+////////////////////////////////////////////////////////////////////////
+//
+// Internal Processor Reigsters
+//
+enum md_ipr_names {
+ RAW_IPR_ISR = 0x100, // interrupt summary
+ RAW_IPR_ITB_TAG = 0x101, // ITLB tag
+ RAW_IPR_ITB_PTE = 0x102, // ITLB page table entry
+ RAW_IPR_ITB_ASN = 0x103, // ITLB address space
+ RAW_IPR_ITB_PTE_TEMP = 0x104, // ITLB page table entry temp
+ RAW_IPR_ITB_IA = 0x105, // ITLB invalidate all
+ RAW_IPR_ITB_IAP = 0x106, // ITLB invalidate all process
+ RAW_IPR_ITB_IS = 0x107, // ITLB invalidate select
+ RAW_IPR_SIRR = 0x108, // software interrupt request
+ RAW_IPR_ASTRR = 0x109, // asynchronous system trap request
+ RAW_IPR_ASTER = 0x10a, // asynchronous system trap enable
+ RAW_IPR_EXC_ADDR = 0x10b, // exception address
+ RAW_IPR_EXC_SUM = 0x10c, // exception summary
+ RAW_IPR_EXC_MASK = 0x10d, // exception mask
+ RAW_IPR_PAL_BASE = 0x10e, // PAL base address
+ RAW_IPR_ICM = 0x10f, // instruction current mode
+ RAW_IPR_IPLR = 0x110, // interrupt priority level
+ RAW_IPR_INTID = 0x111, // interrupt ID
+ RAW_IPR_IFAULT_VA_FORM = 0x112, // formatted faulting virtual addr
+ RAW_IPR_IVPTBR = 0x113, // virtual page table base
+ RAW_IPR_HWINT_CLR = 0x115, // H/W interrupt clear
+ RAW_IPR_SL_XMIT = 0x116, // serial line transmit
+ RAW_IPR_SL_RCV = 0x117, // serial line receive
+ RAW_IPR_ICSR = 0x118, // instruction control and status
+ RAW_IPR_IC_FLUSH = 0x119, // instruction cache flush control
+ RAW_IPR_IC_PERR_STAT = 0x11a, // inst cache parity error status
+ RAW_IPR_PMCTR = 0x11c, // performance counter
+
+ // PAL temporary registers...
+ // register meanings gleaned from osfpal.s source code
+ RAW_IPR_PALtemp0 = 0x140, // local scratch
+ RAW_IPR_PALtemp1 = 0x141, // local scratch
+ RAW_IPR_PALtemp2 = 0x142, // entUna
+ RAW_IPR_PALtemp3 = 0x143, // CPU specific impure area pointer
+ RAW_IPR_PALtemp4 = 0x144, // memory management temp
+ RAW_IPR_PALtemp5 = 0x145, // memory management temp
+ RAW_IPR_PALtemp6 = 0x146, // memory management temp
+ RAW_IPR_PALtemp7 = 0x147, // entIF
+ RAW_IPR_PALtemp8 = 0x148, // intmask
+ RAW_IPR_PALtemp9 = 0x149, // entSys
+ RAW_IPR_PALtemp10 = 0x14a, // ??
+ RAW_IPR_PALtemp11 = 0x14b, // entInt
+ RAW_IPR_PALtemp12 = 0x14c, // entArith
+ RAW_IPR_PALtemp13 = 0x14d, // reserved for platform specific PAL
+ RAW_IPR_PALtemp14 = 0x14e, // reserved for platform specific PAL
+ RAW_IPR_PALtemp15 = 0x14f, // reserved for platform specific PAL
+ RAW_IPR_PALtemp16 = 0x150, // scratch / whami<7:0> / mces<4:0>
+ RAW_IPR_PALtemp17 = 0x151, // sysval
+ RAW_IPR_PALtemp18 = 0x152, // usp
+ RAW_IPR_PALtemp19 = 0x153, // ksp
+ RAW_IPR_PALtemp20 = 0x154, // PTBR
+ RAW_IPR_PALtemp21 = 0x155, // entMM
+ RAW_IPR_PALtemp22 = 0x156, // kgp
+ RAW_IPR_PALtemp23 = 0x157, // PCBB
+
+ RAW_IPR_DTB_ASN = 0x200, // DTLB address space number
+ RAW_IPR_DTB_CM = 0x201, // DTLB current mode
+ RAW_IPR_DTB_TAG = 0x202, // DTLB tag
+ RAW_IPR_DTB_PTE = 0x203, // DTLB page table entry
+ RAW_IPR_DTB_PTE_TEMP = 0x204, // DTLB page table entry temporary
+
+ RAW_IPR_MM_STAT = 0x205, // data MMU fault status
+ RAW_IPR_VA = 0x206, // fault virtual address
+ RAW_IPR_VA_FORM = 0x207, // formatted virtual address
+ RAW_IPR_MVPTBR = 0x208, // MTU virtual page table base
+ RAW_IPR_DTB_IAP = 0x209, // DTLB invalidate all process
+ RAW_IPR_DTB_IA = 0x20a, // DTLB invalidate all
+ RAW_IPR_DTB_IS = 0x20b, // DTLB invalidate single
+ RAW_IPR_ALT_MODE = 0x20c, // alternate mode
+ RAW_IPR_CC = 0x20d, // cycle counter
+ RAW_IPR_CC_CTL = 0x20e, // cycle counter control
+ RAW_IPR_MCSR = 0x20f, // MTU control
+
+ RAW_IPR_DC_FLUSH = 0x210,
+ RAW_IPR_DC_PERR_STAT = 0x212, // Dcache parity error status
+ RAW_IPR_DC_TEST_CTL = 0x213, // Dcache test tag control
+ RAW_IPR_DC_TEST_TAG = 0x214, // Dcache test tag
+ RAW_IPR_DC_TEST_TAG_TEMP = 0x215, // Dcache test tag temporary
+ RAW_IPR_DC_MODE = 0x216, // Dcache mode
+ RAW_IPR_MAF_MODE = 0x217, // miss address file mode
+
+ MaxInternalProcRegs // number of IPRs
+};
+
+enum MiscRegIpr
{
- ////////////////////////////////////////////////////////////////////////
- //
- // Internal Processor Reigsters
- //
- enum md_ipr_names
- {
- RAW_IPR_ISR = 0x100, // interrupt summary register
- RAW_IPR_ITB_TAG = 0x101, // ITLB tag register
- RAW_IPR_ITB_PTE = 0x102, // ITLB page table entry register
- RAW_IPR_ITB_ASN = 0x103, // ITLB address space register
- RAW_IPR_ITB_PTE_TEMP = 0x104, // ITLB page table entry temp register
- RAW_IPR_ITB_IA = 0x105, // ITLB invalidate all register
- RAW_IPR_ITB_IAP = 0x106, // ITLB invalidate all process register
- RAW_IPR_ITB_IS = 0x107, // ITLB invalidate select register
- RAW_IPR_SIRR = 0x108, // software interrupt request register
- RAW_IPR_ASTRR = 0x109, // asynchronous system trap request register
- RAW_IPR_ASTER = 0x10a, // asynchronous system trap enable register
- RAW_IPR_EXC_ADDR = 0x10b, // exception address register
- RAW_IPR_EXC_SUM = 0x10c, // exception summary register
- RAW_IPR_EXC_MASK = 0x10d, // exception mask register
- RAW_IPR_PAL_BASE = 0x10e, // PAL base address register
- RAW_IPR_ICM = 0x10f, // instruction current mode
- RAW_IPR_IPLR = 0x110, // interrupt priority level register
- RAW_IPR_INTID = 0x111, // interrupt ID register
- RAW_IPR_IFAULT_VA_FORM = 0x112, // formatted faulting virtual addr register
- RAW_IPR_IVPTBR = 0x113, // virtual page table base register
- RAW_IPR_HWINT_CLR = 0x115, // H/W interrupt clear register
- RAW_IPR_SL_XMIT = 0x116, // serial line transmit register
- RAW_IPR_SL_RCV = 0x117, // serial line receive register
- RAW_IPR_ICSR = 0x118, // instruction control and status register
- RAW_IPR_IC_FLUSH = 0x119, // instruction cache flush control
- RAW_IPR_IC_PERR_STAT = 0x11a, // inst cache parity error status register
- RAW_IPR_PMCTR = 0x11c, // performance counter register
-
- // PAL temporary registers...
- // register meanings gleaned from osfpal.s source code
- RAW_IPR_PALtemp0 = 0x140, // local scratch
- RAW_IPR_PALtemp1 = 0x141, // local scratch
- RAW_IPR_PALtemp2 = 0x142, // entUna
- RAW_IPR_PALtemp3 = 0x143, // CPU specific impure area pointer
- RAW_IPR_PALtemp4 = 0x144, // memory management temp
- RAW_IPR_PALtemp5 = 0x145, // memory management temp
- RAW_IPR_PALtemp6 = 0x146, // memory management temp
- RAW_IPR_PALtemp7 = 0x147, // entIF
- RAW_IPR_PALtemp8 = 0x148, // intmask
- RAW_IPR_PALtemp9 = 0x149, // entSys
- RAW_IPR_PALtemp10 = 0x14a, // ??
- RAW_IPR_PALtemp11 = 0x14b, // entInt
- RAW_IPR_PALtemp12 = 0x14c, // entArith
- RAW_IPR_PALtemp13 = 0x14d, // reserved for platform specific PAL
- RAW_IPR_PALtemp14 = 0x14e, // reserved for platform specific PAL
- RAW_IPR_PALtemp15 = 0x14f, // reserved for platform specific PAL
- RAW_IPR_PALtemp16 = 0x150, // scratch / whami<7:0> / mces<4:0>
- RAW_IPR_PALtemp17 = 0x151, // sysval
- RAW_IPR_PALtemp18 = 0x152, // usp
- RAW_IPR_PALtemp19 = 0x153, // ksp
- RAW_IPR_PALtemp20 = 0x154, // PTBR
- RAW_IPR_PALtemp21 = 0x155, // entMM
- RAW_IPR_PALtemp22 = 0x156, // kgp
- RAW_IPR_PALtemp23 = 0x157, // PCBB
-
- RAW_IPR_DTB_ASN = 0x200, // DTLB address space number register
- RAW_IPR_DTB_CM = 0x201, // DTLB current mode register
- RAW_IPR_DTB_TAG = 0x202, // DTLB tag register
- RAW_IPR_DTB_PTE = 0x203, // DTLB page table entry register
- RAW_IPR_DTB_PTE_TEMP = 0x204, // DTLB page table entry temporary register
-
- RAW_IPR_MM_STAT = 0x205, // data MMU fault status register
- RAW_IPR_VA = 0x206, // fault virtual address register
- RAW_IPR_VA_FORM = 0x207, // formatted virtual address register
- RAW_IPR_MVPTBR = 0x208, // MTU virtual page table base register
- RAW_IPR_DTB_IAP = 0x209, // DTLB invalidate all process register
- RAW_IPR_DTB_IA = 0x20a, // DTLB invalidate all register
- RAW_IPR_DTB_IS = 0x20b, // DTLB invalidate single register
- RAW_IPR_ALT_MODE = 0x20c, // alternate mode register
- RAW_IPR_CC = 0x20d, // cycle counter register
- RAW_IPR_CC_CTL = 0x20e, // cycle counter control register
- RAW_IPR_MCSR = 0x20f, // MTU control register
-
- RAW_IPR_DC_FLUSH = 0x210,
- RAW_IPR_DC_PERR_STAT = 0x212, // Dcache parity error status register
- RAW_IPR_DC_TEST_CTL = 0x213, // Dcache test tag control register
- RAW_IPR_DC_TEST_TAG = 0x214, // Dcache test tag register
- RAW_IPR_DC_TEST_TAG_TEMP = 0x215, // Dcache test tag temporary register
- RAW_IPR_DC_MODE = 0x216, // Dcache mode register
- RAW_IPR_MAF_MODE = 0x217, // miss address file mode register
-
- MaxInternalProcRegs // number of IPR registers
- };
-
- enum MiscRegIpr
- {
- //Write only
- MinWriteOnlyIpr,
- IPR_HWINT_CLR = MinWriteOnlyIpr,
- IPR_SL_XMIT,
- IPR_DC_FLUSH,
- IPR_IC_FLUSH,
- IPR_ALT_MODE,
- IPR_DTB_IA,
- IPR_DTB_IAP,
- IPR_ITB_IA,
- MaxWriteOnlyIpr,
- IPR_ITB_IAP = MaxWriteOnlyIpr,
-
- //Read only
- MinReadOnlyIpr,
- IPR_INTID = MinReadOnlyIpr,
- IPR_SL_RCV,
- IPR_MM_STAT,
- IPR_ITB_PTE_TEMP,
- MaxReadOnlyIpr,
- IPR_DTB_PTE_TEMP = MaxReadOnlyIpr,
-
- IPR_ISR,
- IPR_ITB_TAG,
- IPR_ITB_PTE,
- IPR_ITB_ASN,
- IPR_ITB_IS,
- IPR_SIRR,
- IPR_ASTRR,
- IPR_ASTER,
- IPR_EXC_ADDR,
- IPR_EXC_SUM,
- IPR_EXC_MASK,
- IPR_PAL_BASE,
- IPR_ICM,
- IPR_IPLR,
- IPR_IFAULT_VA_FORM,
- IPR_IVPTBR,
- IPR_ICSR,
- IPR_IC_PERR_STAT,
- IPR_PMCTR,
-
- // PAL temporary registers...
- // register meanings gleaned from osfpal.s source code
- IPR_PALtemp0,
- IPR_PALtemp1,
- IPR_PALtemp2,
- IPR_PALtemp3,
- IPR_PALtemp4,
- IPR_PALtemp5,
- IPR_PALtemp6,
- IPR_PALtemp7,
- IPR_PALtemp8,
- IPR_PALtemp9,
- IPR_PALtemp10,
- IPR_PALtemp11,
- IPR_PALtemp12,
- IPR_PALtemp13,
- IPR_PALtemp14,
- IPR_PALtemp15,
- IPR_PALtemp16,
- IPR_PALtemp17,
- IPR_PALtemp18,
- IPR_PALtemp19,
- IPR_PALtemp20,
- IPR_PALtemp21,
- IPR_PALtemp22,
- IPR_PALtemp23,
-
- IPR_DTB_ASN,
- IPR_DTB_CM,
- IPR_DTB_TAG,
- IPR_DTB_PTE,
-
- IPR_VA,
- IPR_VA_FORM,
- IPR_MVPTBR,
- IPR_DTB_IS,
- IPR_CC,
- IPR_CC_CTL,
- IPR_MCSR,
-
- IPR_DC_PERR_STAT,
- IPR_DC_TEST_CTL,
- IPR_DC_TEST_TAG,
- IPR_DC_TEST_TAG_TEMP,
- IPR_DC_MODE,
- IPR_MAF_MODE,
-
- NumInternalProcRegs // number of IPR registers
- };
-
- inline bool IprIsWritable(int index)
- {
- return index < MinReadOnlyIpr || index > MaxReadOnlyIpr;
- }
-
- inline bool IprIsReadable(int index)
- {
- return index < MinWriteOnlyIpr || index > MaxWriteOnlyIpr;
- }
-
- extern md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs];
- extern int IprToMiscRegIndex[MaxInternalProcRegs];
-
- void initializeIprTable();
+ //Write only
+ MinWriteOnlyIpr,
+ IPR_HWINT_CLR = MinWriteOnlyIpr,
+ IPR_SL_XMIT,
+ IPR_DC_FLUSH,
+ IPR_IC_FLUSH,
+ IPR_ALT_MODE,
+ IPR_DTB_IA,
+ IPR_DTB_IAP,
+ IPR_ITB_IA,
+ MaxWriteOnlyIpr,
+ IPR_ITB_IAP = MaxWriteOnlyIpr,
+
+ //Read only
+ MinReadOnlyIpr,
+ IPR_INTID = MinReadOnlyIpr,
+ IPR_SL_RCV,
+ IPR_MM_STAT,
+ IPR_ITB_PTE_TEMP,
+ MaxReadOnlyIpr,
+ IPR_DTB_PTE_TEMP = MaxReadOnlyIpr,
+
+ IPR_ISR,
+ IPR_ITB_TAG,
+ IPR_ITB_PTE,
+ IPR_ITB_ASN,
+ IPR_ITB_IS,
+ IPR_SIRR,
+ IPR_ASTRR,
+ IPR_ASTER,
+ IPR_EXC_ADDR,
+ IPR_EXC_SUM,
+ IPR_EXC_MASK,
+ IPR_PAL_BASE,
+ IPR_ICM,
+ IPR_IPLR,
+ IPR_IFAULT_VA_FORM,
+ IPR_IVPTBR,
+ IPR_ICSR,
+ IPR_IC_PERR_STAT,
+ IPR_PMCTR,
+
+ // PAL temporary registers...
+ // register meanings gleaned from osfpal.s source code
+ IPR_PALtemp0,
+ IPR_PALtemp1,
+ IPR_PALtemp2,
+ IPR_PALtemp3,
+ IPR_PALtemp4,
+ IPR_PALtemp5,
+ IPR_PALtemp6,
+ IPR_PALtemp7,
+ IPR_PALtemp8,
+ IPR_PALtemp9,
+ IPR_PALtemp10,
+ IPR_PALtemp11,
+ IPR_PALtemp12,
+ IPR_PALtemp13,
+ IPR_PALtemp14,
+ IPR_PALtemp15,
+ IPR_PALtemp16,
+ IPR_PALtemp17,
+ IPR_PALtemp18,
+ IPR_PALtemp19,
+ IPR_PALtemp20,
+ IPR_PALtemp21,
+ IPR_PALtemp22,
+ IPR_PALtemp23,
+
+ IPR_DTB_ASN,
+ IPR_DTB_CM,
+ IPR_DTB_TAG,
+ IPR_DTB_PTE,
+
+ IPR_VA,
+ IPR_VA_FORM,
+ IPR_MVPTBR,
+ IPR_DTB_IS,
+ IPR_CC,
+ IPR_CC_CTL,
+ IPR_MCSR,
+
+ IPR_DC_PERR_STAT,
+ IPR_DC_TEST_CTL,
+ IPR_DC_TEST_TAG,
+ IPR_DC_TEST_TAG_TEMP,
+ IPR_DC_MODE,
+ IPR_MAF_MODE,
+
+ NumInternalProcRegs // number of IPR registers
+};
+
+inline bool
+IprIsWritable(int index)
+{
+ return index < MinReadOnlyIpr || index > MaxReadOnlyIpr;
+}
+
+inline bool
+IprIsReadable(int index)
+{
+ return index < MinWriteOnlyIpr || index > MaxWriteOnlyIpr;
}
-#endif
+extern md_ipr_names MiscRegIndexToIpr[NumInternalProcRegs];
+extern int IprToMiscRegIndex[MaxInternalProcRegs];
+
+void initializeIprTable();
+
+} // namespace AlphaISA
+
+#endif // __ARCH_ALPHA_IPR_HH__
diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa
index 2177e8c4f..0b2a31410 100644
--- a/src/arch/alpha/isa/decoder.isa
+++ b/src/arch/alpha/isa/decoder.isa
@@ -638,7 +638,7 @@ decode OPCODE default Unknown::unknown() {
/* Rb is a fake dependency so here is a fun way to get
* the parser to understand that.
*/
- Ra = xc->readMiscReg(AlphaISA::IPR_CC) + (Rb & 0);
+ Ra = xc->readMiscReg(IPR_CC) + (Rb & 0);
#else
Ra = curTick;
@@ -690,7 +690,7 @@ decode OPCODE default Unknown::unknown() {
0x00: CallPal::call_pal({{
if (!palValid ||
(palPriv
- && xc->readMiscReg(AlphaISA::IPR_ICM) != AlphaISA::mode_kernel)) {
+ && xc->readMiscReg(IPR_ICM) != mode_kernel)) {
// invalid pal function code, or attempt to do privileged
// PAL call in non-kernel mode
fault = new UnimplementedOpcodeFault;
@@ -701,8 +701,8 @@ decode OPCODE default Unknown::unknown() {
bool dopal = xc->simPalCheck(palFunc);
if (dopal) {
- xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, NPC);
- NPC = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + palOffset;
+ xc->setMiscReg(IPR_EXC_ADDR, NPC);
+ NPC = xc->readMiscReg(IPR_PAL_BASE) + palOffset;
}
}
}}, IsNonSpeculative);
@@ -783,14 +783,19 @@ decode OPCODE default Unknown::unknown() {
}
}
- format BasicOperate {
- 0x1e: decode PALMODE {
- 0: OpcdecFault::hw_rei();
- 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore);
+ 0x1e: decode PALMODE {
+ 0: OpcdecFault::hw_rei();
+ format BasicOperate {
+ 1: hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore);
}
+ }
+
+#endif
+ format BasicOperate {
// M5 special opcodes use the reserved 0x01 opcode space
0x01: decode M5FUNC {
+#if FULL_SYSTEM
0x00: arm({{
PseudoInst::arm(xc->tcBase());
}}, IsNonSpeculative);
@@ -806,22 +811,34 @@ decode OPCODE default Unknown::unknown() {
0x04: quiesceTime({{
R0 = PseudoInst::quiesceTime(xc->tcBase());
}}, IsNonSpeculative, IsUnverifiable);
- 0x10: ivlb({{
- warn_once("Obsolete M5 instruction ivlb encountered.\n");
+#endif
+ 0x07: rpns({{
+ R0 = PseudoInst::rpns(xc->tcBase());
+ }}, IsNonSpeculative, IsUnverifiable);
+ 0x09: wakeCPU({{
+ PseudoInst::wakeCPU(xc->tcBase(), R16);
+ }}, IsNonSpeculative, IsUnverifiable);
+ 0x10: deprecated_ivlb({{
+ warn_once("Obsolete M5 ivlb instruction encountered.\n");
}});
- 0x11: ivle({{
- warn_once("Obsolete M5 instruction ivlb encountered.\n");
+ 0x11: deprecated_ivle({{
+ warn_once("Obsolete M5 ivlb instruction encountered.\n");
}});
- 0x20: m5exit_old({{
- PseudoInst::m5exit_old(xc->tcBase());
+ 0x20: deprecated_exit ({{
+ warn_once("deprecated M5 exit instruction encountered.\n");
+ PseudoInst::m5exit(xc->tcBase(), 0);
}}, No_OpClass, IsNonSpeculative);
0x21: m5exit({{
PseudoInst::m5exit(xc->tcBase(), R16);
}}, No_OpClass, IsNonSpeculative);
+#if FULL_SYSTEM
0x31: loadsymbol({{
PseudoInst::loadsymbol(xc->tcBase());
}}, No_OpClass, IsNonSpeculative);
- 0x30: initparam({{ Ra = xc->tcBase()->getCpuPtr()->system->init_param; }});
+ 0x30: initparam({{
+ Ra = xc->tcBase()->getCpuPtr()->system->init_param;
+ }});
+#endif
0x40: resetstats({{
PseudoInst::resetstats(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
@@ -834,28 +851,93 @@ decode OPCODE default Unknown::unknown() {
0x43: m5checkpoint({{
PseudoInst::m5checkpoint(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
+#if FULL_SYSTEM
0x50: m5readfile({{
R0 = PseudoInst::readfile(xc->tcBase(), R16, R17, R18);
}}, IsNonSpeculative);
+#endif
0x51: m5break({{
PseudoInst::debugbreak(xc->tcBase());
}}, IsNonSpeculative);
0x52: m5switchcpu({{
PseudoInst::switchcpu(xc->tcBase());
}}, IsNonSpeculative);
+#if FULL_SYSTEM
0x53: m5addsymbol({{
PseudoInst::addsymbol(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
+#endif
0x54: m5panic({{
panic("M5 panic instruction called at pc=%#x.", xc->readPC());
}}, IsNonSpeculative);
- 0x55: m5anBegin({{
- PseudoInst::anBegin(xc->tcBase(), R16);
+#define CPANN(lbl) CPA::cpa()->lbl(xc->tcBase())
+ 0x55: decode RA {
+ 0x00: m5a_old({{
+ panic("Deprecated M5 annotate instruction executed at pc=%#x\n",
+ xc->readPC());
+ }}, IsNonSpeculative);
+ 0x01: m5a_bsm({{
+ CPANN(swSmBegin);
+ }}, IsNonSpeculative);
+ 0x02: m5a_esm({{
+ CPANN(swSmEnd);
+ }}, IsNonSpeculative);
+ 0x03: m5a_begin({{
+ CPANN(swExplictBegin);
+ }}, IsNonSpeculative);
+ 0x04: m5a_end({{
+ CPANN(swEnd);
+ }}, IsNonSpeculative);
+ 0x06: m5a_q({{
+ CPANN(swQ);
+ }}, IsNonSpeculative);
+ 0x07: m5a_dq({{
+ CPANN(swDq);
+ }}, IsNonSpeculative);
+ 0x08: m5a_wf({{
+ CPANN(swWf);
+ }}, IsNonSpeculative);
+ 0x09: m5a_we({{
+ CPANN(swWe);
+ }}, IsNonSpeculative);
+ 0x0C: m5a_sq({{
+ CPANN(swSq);
+ }}, IsNonSpeculative);
+ 0x0D: m5a_aq({{
+ CPANN(swAq);
+ }}, IsNonSpeculative);
+ 0x0E: m5a_pq({{
+ CPANN(swPq);
+ }}, IsNonSpeculative);
+ 0x0F: m5a_l({{
+ CPANN(swLink);
+ }}, IsNonSpeculative);
+ 0x10: m5a_identify({{
+ CPANN(swIdentify);
+ }}, IsNonSpeculative);
+ 0x11: m5a_getid({{
+ R0 = CPANN(swGetId);
+ }}, IsNonSpeculative);
+ 0x13: m5a_scl({{
+ CPANN(swSyscallLink);
+ }}, IsNonSpeculative);
+ 0x14: m5a_rq({{
+ CPANN(swRq);
+ }}, IsNonSpeculative);
+ } // M5 Annotate Operations
+#undef CPANN
+ 0x56: m5reserved2({{
+ warn("M5 reserved opcode ignored");
+ }}, IsNonSpeculative);
+ 0x57: m5reserved3({{
+ warn("M5 reserved opcode ignored");
}}, IsNonSpeculative);
- 0x56: m5anWait({{
- PseudoInst::anWait(xc->tcBase(), R16, R17);
+ 0x58: m5reserved4({{
+ warn("M5 reserved opcode ignored");
+ }}, IsNonSpeculative);
+ 0x59: m5reserved5({{
+ warn("M5 reserved opcode ignored");
}}, IsNonSpeculative);
}
}
-#endif
}
diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa
index 773e7d10c..ed04d2a50 100644
--- a/src/arch/alpha/isa/fp.isa
+++ b/src/arch/alpha/isa/fp.isa
@@ -46,7 +46,7 @@ output exec {{
inline Fault checkFpEnableFault(%(CPU_exec_context)s *xc)
{
Fault fault = NoFault; // dummy... this ipr access should not fault
- if (!EV5::ICSR_FPE(xc->readMiscReg(AlphaISA::IPR_ICSR))) {
+ if (!ICSR_FPE(xc->readMiscReg(IPR_ICSR))) {
fault = new FloatEnableFault;
}
return fault;
@@ -229,7 +229,7 @@ def template FloatingPointExecute {{
%(code)s;
} else {
m5_fesetround(getC99RoundingMode(
- xc->readMiscRegNoEffect(AlphaISA::MISCREG_FPCR)));
+ xc->readMiscRegNoEffect(MISCREG_FPCR)));
%(code)s;
m5_fesetround(M5_FE_TONEAREST);
}
diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa
index d72dfe34a..aea44976c 100644
--- a/src/arch/alpha/isa/main.isa
+++ b/src/arch/alpha/isa/main.isa
@@ -68,9 +68,8 @@ using namespace AlphaISA;
output exec {{
#include <math.h>
-#if FULL_SYSTEM
+#include "base/cp_annotate.hh"
#include "sim/pseudo_inst.hh"
-#endif
#include "arch/alpha/ipr.hh"
#include "base/fenv.hh"
#include "config/ss_compatible_fp.hh"
@@ -173,11 +172,11 @@ 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',
+ 'Ra': ('IntReg', 'uq', 'PALMODE ? reg_redir[RA] : RA',
'IsInteger', 1),
- 'Rb': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RB] : RB',
+ 'Rb': ('IntReg', 'uq', 'PALMODE ? reg_redir[RB] : RB',
'IsInteger', 2),
- 'Rc': ('IntReg', 'uq', 'PALMODE ? AlphaISA::reg_redir[RC] : RC',
+ 'Rc': ('IntReg', 'uq', 'PALMODE ? reg_redir[RC] : RC',
'IsInteger', 3),
'Fa': ('FloatReg', 'df', 'FA', 'IsFloating', 1),
'Fb': ('FloatReg', 'df', 'FB', 'IsFloating', 2),
diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa
index fe0daf772..cd5e117ec 100644
--- a/src/arch/alpha/isa/mem.isa
+++ b/src/arch/alpha/isa/mem.isa
@@ -43,7 +43,7 @@ output header {{
protected:
/// Memory request flags. See mem_req_base.hh.
- unsigned memAccessFlags;
+ Request::Flags memAccessFlags;
/// Pointer to EAComp object.
const StaticInstPtr eaCompPtr;
/// Pointer to MemAcc object.
@@ -54,7 +54,7 @@ output header {{
StaticInstPtr _eaCompPtr = nullStaticInstPtr,
StaticInstPtr _memAccPtr = nullStaticInstPtr)
: AlphaStaticInst(mnem, _machInst, __opClass),
- memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr)
+ eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr)
{
}
@@ -677,6 +677,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
inst_flags)
if mem_flags:
+ mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
iop.constructor += s
memacc_iop.constructor += s
diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa
index 294b92e2f..3d3b81600 100644
--- a/src/arch/alpha/isa/pal.isa
+++ b/src/arch/alpha/isa/pal.isa
@@ -174,11 +174,11 @@ output decoder {{
: 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;
+ memAccessFlags.clear();
+ if (HW_LDST_PHYS) memAccessFlags.set(Request::PHYSICAL);
+ if (HW_LDST_ALT) memAccessFlags.set(Request::ALTMODE);
+ if (HW_LDST_VPTE) memAccessFlags.set(Request::VPTE);
+ if (HW_LDST_LOCK) memAccessFlags.set(Request::LOCKED);
}
std::string
diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh
index be1d1b8bb..d37a769ea 100644
--- a/src/arch/alpha/isa_traits.hh
+++ b/src/arch/alpha/isa_traits.hh
@@ -42,142 +42,134 @@ namespace LittleEndianGuest {}
class StaticInstPtr;
-namespace AlphaISA
+namespace AlphaISA {
+
+using namespace LittleEndianGuest;
+using AlphaISAInst::MaxInstSrcRegs;
+using AlphaISAInst::MaxInstDestRegs;
+
+// 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
+};
+
+StaticInstPtr decodeInst(ExtMachInst);
+
+// Alpha Does NOT have a delay slot
+#define ISA_HAS_DELAY_SLOT 0
+
+const Addr PageShift = 13;
+const Addr PageBytes = ULL(1) << PageShift;
+const Addr PageMask = ~(PageBytes - 1);
+const Addr PageOffset = PageBytes - 1;
+
+////////////////////////////////////////////////////////////////////////
+//
+// Translation stuff
+//
+
+const Addr PteShift = 3;
+const Addr NPtePageShift = PageShift - PteShift;
+const Addr NPtePage = ULL(1) << NPtePageShift;
+const Addr PteMask = NPtePage - 1;
+
+// User Virtual
+const Addr USegBase = ULL(0x0);
+const Addr USegEnd = ULL(0x000003ffffffffff);
+
+// Kernel Direct Mapped
+const Addr K0SegBase = ULL(0xfffffc0000000000);
+const Addr K0SegEnd = ULL(0xfffffdffffffffff);
+
+// Kernel Virtual
+const Addr K1SegBase = ULL(0xfffffe0000000000);
+const Addr K1SegEnd = ULL(0xffffffffffffffff);
+
+// For loading... XXX This maybe could be USegEnd?? --ali
+const Addr LoadAddrMask = ULL(0xffffffffff);
+
+////////////////////////////////////////////////////////////////////////
+//
+// Interrupt levels
+//
+enum InterruptLevels
{
- using namespace LittleEndianGuest;
- using AlphaISAInst::MaxInstSrcRegs;
- using AlphaISAInst::MaxInstDestRegs;
-
- // 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
- };
-
- StaticInstPtr decodeInst(ExtMachInst);
-
- // Alpha Does NOT have a delay slot
- #define ISA_HAS_DELAY_SLOT 0
-
- const Addr PageShift = 13;
- const Addr PageBytes = ULL(1) << PageShift;
- const Addr PageMask = ~(PageBytes - 1);
- const Addr PageOffset = PageBytes - 1;
-
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Translation stuff
- //
-
- const Addr PteShift = 3;
- const Addr NPtePageShift = PageShift - PteShift;
- const Addr NPtePage = ULL(1) << NPtePageShift;
- const Addr PteMask = NPtePage - 1;
-
- // User Virtual
- const Addr USegBase = ULL(0x0);
- const Addr USegEnd = ULL(0x000003ffffffffff);
-
- // Kernel Direct Mapped
- const Addr K0SegBase = ULL(0xfffffc0000000000);
- const Addr K0SegEnd = ULL(0xfffffdffffffffff);
-
- // Kernel Virtual
- const Addr K1SegBase = ULL(0xfffffe0000000000);
- const Addr K1SegEnd = ULL(0xffffffffffffffff);
-
- // For loading... XXX This maybe could be USegEnd?? --ali
- const Addr LoadAddrMask = ULL(0xffffffffff);
-
-#if FULL_SYSTEM
-
- ////////////////////////////////////////////////////////////////////////
- //
- // Interrupt levels
- //
- enum InterruptLevels
- {
- INTLEVEL_SOFTWARE_MIN = 4,
- INTLEVEL_SOFTWARE_MAX = 19,
-
- INTLEVEL_EXTERNAL_MIN = 20,
- INTLEVEL_EXTERNAL_MAX = 34,
-
- INTLEVEL_IRQ0 = 20,
- INTLEVEL_IRQ1 = 21,
- INTINDEX_ETHERNET = 0,
- INTINDEX_SCSI = 1,
- INTLEVEL_IRQ2 = 22,
- INTLEVEL_IRQ3 = 23,
-
- INTLEVEL_SERIAL = 33,
-
- NumInterruptLevels = INTLEVEL_EXTERNAL_MAX
- };
-
-#endif
-
- // EV5 modes
- enum mode_type
- {
- mode_kernel = 0, // kernel
- mode_executive = 1, // executive (unused by unix)
- mode_supervisor = 2, // supervisor (unused by unix)
- mode_user = 3, // user mode
- mode_number // number of modes
- };
-
- // Constants Related to the number of registers
-
- const int NumIntArchRegs = 32;
- const int NumPALShadowRegs = 8;
- const int NumFloatArchRegs = 32;
- // @todo: Figure out what this number really should be.
- const int NumMiscArchRegs = 77;
-
- const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs;
- const int NumFloatRegs = NumFloatArchRegs;
- const int NumMiscRegs = NumMiscArchRegs;
-
- const int TotalNumRegs = NumIntRegs + NumFloatRegs +
- NumMiscRegs + NumInternalProcRegs;
-
- const int TotalDataRegs = NumIntRegs + NumFloatRegs;
-
- // 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;
+ INTLEVEL_SOFTWARE_MIN = 4,
+ INTLEVEL_SOFTWARE_MAX = 19,
+
+ INTLEVEL_EXTERNAL_MIN = 20,
+ INTLEVEL_EXTERNAL_MAX = 34,
- const int ArgumentReg[] = {16, 17, 18, 19, 20, 21};
- const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
+ INTLEVEL_IRQ0 = 20,
+ INTLEVEL_IRQ1 = 21,
+ INTINDEX_ETHERNET = 0,
+ INTINDEX_SCSI = 1,
+ INTLEVEL_IRQ2 = 22,
+ INTLEVEL_IRQ3 = 23,
- const int SyscallNumReg = ReturnValueReg;
- const int SyscallPseudoReturnReg = ArgumentReg[4];
- const int SyscallSuccessReg = 19;
+ INTLEVEL_SERIAL = 33,
- const int LogVMPageSize = 13; // 8K bytes
- const int VMPageSize = (1 << LogVMPageSize);
-
- const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned
-
- const int MachineBytes = 8;
- const int WordBytes = 4;
- const int HalfwordBytes = 2;
- const int ByteBytes = 1;
-
- // return a no-op instruction... used for instruction fetch faults
- // Alpha UNOP (ldq_u r31,0(r0))
- const ExtMachInst NoopMachInst = 0x2ffe0000;
+ NumInterruptLevels = INTLEVEL_EXTERNAL_MAX
+};
+// EV5 modes
+enum mode_type
+{
+ mode_kernel = 0, // kernel
+ mode_executive = 1, // executive (unused by unix)
+ mode_supervisor = 2, // supervisor (unused by unix)
+ mode_user = 3, // user mode
+ mode_number // number of modes
};
+// Constants Related to the number of registers
+
+const int NumIntArchRegs = 32;
+const int NumPALShadowRegs = 8;
+const int NumFloatArchRegs = 32;
+// @todo: Figure out what this number really should be.
+const int NumMiscArchRegs = 77;
+
+const int NumIntRegs = NumIntArchRegs + NumPALShadowRegs;
+const int NumFloatRegs = NumFloatArchRegs;
+const int NumMiscRegs = NumMiscArchRegs;
+
+const int TotalNumRegs =
+ NumIntRegs + NumFloatRegs + NumMiscRegs + NumInternalProcRegs;
+
+const int TotalDataRegs = NumIntRegs + NumFloatRegs;
+
+// 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 SyscallNumReg = 0;
+const int FirstArgumentReg = 16;
+const int SyscallPseudoReturnReg = 20;
+
+const int LogVMPageSize = 13; // 8K bytes
+const int VMPageSize = (1 << LogVMPageSize);
+
+const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned
+
+const int MachineBytes = 8;
+const int WordBytes = 4;
+const int HalfwordBytes = 2;
+const int ByteBytes = 1;
+
+// return a no-op instruction... used for instruction fetch faults
+// Alpha UNOP (ldq_u r31,0(r0))
+const ExtMachInst NoopMachInst = 0x2ffe0000;
+
+} // namespace AlphaISA
+
#endif // __ARCH_ALPHA_ISA_TRAITS_HH__
diff --git a/src/arch/alpha/kernel_stats.cc b/src/arch/alpha/kernel_stats.cc
index a004d5f25..6e9dc1611 100644
--- a/src/arch/alpha/kernel_stats.cc
+++ b/src/arch/alpha/kernel_stats.cc
@@ -152,7 +152,7 @@ Statistics::changeMode(cpu_mode newmode, ThreadContext *tc)
void
Statistics::mode(cpu_mode newmode, ThreadContext *tc)
{
- Addr pcbb = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23);
+ Addr pcbb = tc->readMiscRegNoEffect(IPR_PALtemp23);
if (newmode == kernel && pcbb == idleProcess)
newmode = idle;
@@ -213,5 +213,5 @@ Statistics::unserialize(Checkpoint *cp, const string &section)
themode = (cpu_mode)exemode;
}
-} /* end namespace AlphaISA::Kernel */
-} /* end namespace AlphaISA */
+} // namespace Kernel
+} // namespace AlphaISA
diff --git a/src/arch/alpha/kernel_stats.hh b/src/arch/alpha/kernel_stats.hh
index 7b8640ad7..837269309 100644
--- a/src/arch/alpha/kernel_stats.hh
+++ b/src/arch/alpha/kernel_stats.hh
@@ -62,15 +62,15 @@ class Statistics : public ::Kernel::Statistics
void changeMode(cpu_mode newmode, ThreadContext *tc);
private:
- Stats::Vector<> _callpal;
-// Stats::Vector<> _faults;
+ Stats::Vector _callpal;
+// Stats::Vector _faults;
- Stats::Vector<> _mode;
- Stats::Vector<> _modeGood;
+ Stats::Vector _mode;
+ Stats::Vector _modeGood;
Stats::Formula _modeFraction;
- Stats::Vector<> _modeTicks;
+ Stats::Vector _modeTicks;
- Stats::Scalar<> _swap_context;
+ Stats::Scalar _swap_context;
public:
Statistics(System *system);
@@ -90,7 +90,7 @@ class Statistics : public ::Kernel::Statistics
void unserialize(Checkpoint *cp, const std::string &section);
};
-} /* end namespace AlphaISA::Kernel */
-} /* end namespace AlphaISA */
+} // namespace Kernel
+} // namespace AlphaISA
#endif // __ARCH_ALPHA_KERNEL_STATS_HH__
diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc
index e6908a572..ad8388096 100644
--- a/src/arch/alpha/linux/linux.cc
+++ b/src/arch/alpha/linux/linux.cc
@@ -28,47 +28,44 @@
* Authors: Korey Sewell
*/
-#include "arch/alpha/linux/linux.hh"
-
#include <fcntl.h>
+#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 },
+ { 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 },
+ { AlphaLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
#endif
#ifdef _O_NOCTTY
- { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY },
+ { AlphaLinux::TGT_O_NOCTTY, _O_NOCTTY },
#endif
#ifdef _O_SYNC
- { AlphaLinux::TGT_O_SYNC, _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 },
+ { 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 },
+ { AlphaLinux::TGT_O_SYNC, O_SYNC },
#endif
#endif /* _MSC_VER */
};
const int AlphaLinux::NUM_OPEN_FLAGS =
- (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0]));
-
-
-
+ (sizeof(AlphaLinux::openFlagTable)/sizeof(AlphaLinux::openFlagTable[0]));
diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh
index 84c04ebc3..c622c5ef1 100644
--- a/src/arch/alpha/linux/linux.hh
+++ b/src/arch/alpha/linux/linux.hh
@@ -28,8 +28,8 @@
* Authors: Korey Sewell
*/
-#ifndef __ALPHA_ALPHA_LINUX_HH
-#define __ALPHA_ALPHA_LINUX_HH
+#ifndef __ALPHA_ALPHA_LINUX_LINUX_HH__
+#define __ALPHA_ALPHA_LINUX_LINUX_HH__
#include "kern/linux/linux.hh"
@@ -50,21 +50,21 @@ class AlphaLinux : public Linux
//@{
/// 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
+ 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().
@@ -72,13 +72,13 @@ class AlphaLinux : public Linux
//@{
/// 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_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 # CPUs on 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;
//@}
@@ -127,4 +127,4 @@ class AlphaLinux : public Linux
};
};
-#endif
+#endif // __ALPHA_ALPHA_LINUX_LINUX_HH__
diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc
index ec47992bd..aeff9fbed 100644
--- a/src/arch/alpha/linux/process.cc
+++ b/src/arch/alpha/linux/process.cc
@@ -43,18 +43,16 @@
using namespace std;
using namespace AlphaISA;
-
-
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
- strcpy(name->release, "2.4.20");
+ strcpy(name->release, "2.6.26");
strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
strcpy(name->machine, "alpha");
@@ -69,13 +67,13 @@ static SyscallReturn
osf_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
- // unsigned nbytes = tc->getSyscallArg(2);
+ unsigned op = process->getSyscallArg(tc, 0);
+ // unsigned nbytes = process->getSyscallArg(tc, 2);
switch (op) {
case 45: { // GSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1));
// I don't think this exactly matches the HW FPCR
*fpcr = 0;
fpcr.copyOut(tc->getMemPort());
@@ -96,13 +94,13 @@ static SyscallReturn
osf_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
- // unsigned nbytes = tc->getSyscallArg(2);
+ unsigned op = process->getSyscallArg(tc, 0);
+ // unsigned nbytes = process->getSyscallArg(tc, 2);
switch (op) {
case 14: { // SSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1));
// I don't think this exactly matches the HW FPCR
fpcr.copyIn(tc->getMemPort());
DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): "
@@ -138,7 +136,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<AlphaLinux>),
/* 16 */ SyscallDesc("chown", chownFunc),
- /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 17 */ SyscallDesc("brk", brkFunc),
/* 18 */ SyscallDesc("osf_getfsstat", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getxpid", getpidPseudoFunc),
@@ -179,9 +177,9 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 55 */ SyscallDesc("osf_reboot", unimplementedFunc),
/* 56 */ SyscallDesc("osf_revoke", unimplementedFunc),
/* 57 */ SyscallDesc("symlink", unimplementedFunc),
- /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", readlinkFunc),
/* 59 */ SyscallDesc("execve", unimplementedFunc),
- /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", umaskFunc),
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
/* 62 */ SyscallDesc("osf_old_fstat", unimplementedFunc),
/* 63 */ SyscallDesc("getpgrp", unimplementedFunc),
@@ -250,14 +248,14 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 126 */ SyscallDesc("setreuid", unimplementedFunc),
/* 127 */ SyscallDesc("setregid", unimplementedFunc),
/* 128 */ SyscallDesc("rename", renameFunc),
- /* 129 */ SyscallDesc("truncate", unimplementedFunc),
- /* 130 */ SyscallDesc("ftruncate", unimplementedFunc),
+ /* 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),
+ /* 136 */ SyscallDesc("mkdir", mkdirFunc),
/* 137 */ SyscallDesc("rmdir", unimplementedFunc),
/* 138 */ SyscallDesc("osf_utimes", unimplementedFunc),
/* 139 */ SyscallDesc("osf_old_sigreturn", unimplementedFunc),
@@ -465,7 +463,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 338 */ SyscallDesc("afs_syscall", unimplementedFunc),
/* 339 */ SyscallDesc("uname", unameFunc),
/* 340 */ SyscallDesc("nanosleep", unimplementedFunc),
- /* 341 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 341 */ SyscallDesc("mremap", mremapFunc<AlphaLinux>),
/* 342 */ SyscallDesc("nfsservctl", unimplementedFunc),
/* 343 */ SyscallDesc("setresuid", unimplementedFunc),
/* 344 */ SyscallDesc("getresuid", unimplementedFunc),
@@ -491,7 +489,7 @@ SyscallDesc AlphaLinuxProcess::syscallDescs[] = {
/* 364 */ SyscallDesc("getrusage", getrusageFunc<AlphaLinux>),
/* 365 */ SyscallDesc("wait4", unimplementedFunc),
/* 366 */ SyscallDesc("adjtimex", unimplementedFunc),
- /* 367 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 367 */ SyscallDesc("getcwd", getcwdFunc),
/* 368 */ SyscallDesc("capget", unimplementedFunc),
/* 369 */ SyscallDesc("capset", unimplementedFunc),
/* 370 */ SyscallDesc("sendfile", unimplementedFunc),
@@ -581,7 +579,7 @@ AlphaLinuxProcess::AlphaLinuxProcess(LiveProcessParams * params,
SyscallDesc*
AlphaLinuxProcess::getDesc(int callnum)
{
- if (callnum < 0 || callnum > Num_Syscall_Descs)
+ 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
index 8d7c24e37..9ab7b0501 100644
--- a/src/arch/alpha/linux/process.hh
+++ b/src/arch/alpha/linux/process.hh
@@ -51,4 +51,5 @@ class AlphaLinuxProcess : public AlphaLiveProcess
};
} // namespace AlphaISA
+
#endif // __ALPHA_LINUX_PROCESS_HH__
diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc
index 102598716..1d9332a58 100644
--- a/src/arch/alpha/linux/system.cc
+++ b/src/arch/alpha/linux/system.cc
@@ -157,7 +157,6 @@ LinuxAlphaSystem::~LinuxAlphaSystem()
delete printThreadEvent;
}
-
void
LinuxAlphaSystem::setDelayLoop(ThreadContext *tc)
{
@@ -169,11 +168,9 @@ LinuxAlphaSystem::setDelayLoop(ThreadContext *tc)
vp = tc->getVirtPort();
vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988));
- tc->delVirtPort(vp);
}
}
-
void
LinuxAlphaSystem::SkipDelayLoopEvent::process(ThreadContext *tc)
{
diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh
index 00cde826a..3e4de7b2a 100644
--- a/src/arch/alpha/linux/system.hh
+++ b/src/arch/alpha/linux/system.hh
@@ -43,9 +43,6 @@ class IdleStartEvent;
#include "kern/linux/events.hh"
#include "params/LinuxAlphaSystem.hh"
-using namespace AlphaISA;
-using namespace Linux;
-
/**
* This class contains linux specific system code (Loading, Events).
* It points to objects that are the system binaries to load and patches them
@@ -54,23 +51,20 @@ using namespace Linux;
class LinuxAlphaSystem : public AlphaSystem
{
private:
- class SkipDelayLoopEvent : public SkipFuncEvent
+ struct SkipDelayLoopEvent : public SkipFuncEvent
{
- public:
SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: SkipFuncEvent(q, desc, addr) {}
virtual void process(ThreadContext *tc);
};
- class PrintThreadInfo : public PCEvent
+ struct PrintThreadInfo : public PCEvent
{
- public:
PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
virtual void process(ThreadContext *tc);
};
-
/**
* Addresses defining where the kernel bootloader places various
* elements. Details found in include/asm-alpha/system.h
@@ -112,7 +106,7 @@ class LinuxAlphaSystem : public AlphaSystem
* PC based event to skip the dprink() call and emulate its
* functionality
*/
- DebugPrintkEvent *debugPrintkEvent;
+ Linux::DebugPrintkEvent *debugPrintkEvent;
/**
* Skip calculate_delay_loop() rather than waiting for this to be
diff --git a/src/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh
index b0c8284be..db723bed3 100644
--- a/src/arch/alpha/linux/threadinfo.hh
+++ b/src/arch/alpha/linux/threadinfo.hh
@@ -55,7 +55,7 @@ class ThreadInfo
CopyOut(tc, &data, addr, sizeof(T));
- data = TheISA::gtoh(data);
+ data = AlphaISA::gtoh(data);
return true;
}
@@ -76,7 +76,7 @@ class ThreadInfo
Addr sp;
if (!addr)
- addr = tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23);
+ addr = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp23);
FunctionalPort *p = tc->getPhysPort();
p->readBlob(addr, (uint8_t *)&sp, sizeof(Addr));
@@ -147,6 +147,6 @@ class ThreadInfo
}
};
-/* namespace Linux */ }
+} // namespace Linux
#endif // __ARCH_ALPHA_LINUX_LINUX_THREADINFO_HH__
diff --git a/src/arch/alpha/locked_mem.hh b/src/arch/alpha/locked_mem.hh
index df66b92bc..e8928ba08 100644
--- a/src/arch/alpha/locked_mem.hh
+++ b/src/arch/alpha/locked_mem.hh
@@ -49,9 +49,8 @@
#include "base/misc.hh"
#include "mem/request.hh"
+namespace AlphaISA {
-namespace AlphaISA
-{
template <class XC>
inline void
handleLockedRead(XC *xc, Request *req)
@@ -86,9 +85,9 @@ handleLockedWrite(XC *xc, Request *req)
stCondFailures++;
xc->setStCondFailures(stCondFailures);
if (stCondFailures % 100000 == 0) {
- warn("cpu %d: %d consecutive "
+ warn("context %d: %d consecutive "
"store conditional failures\n",
- xc->readCpuId(), stCondFailures);
+ xc->contextId(), stCondFailures);
}
// store conditional failed already, so don't issue it to mem
@@ -99,7 +98,6 @@ handleLockedWrite(XC *xc, Request *req)
return true;
}
-
} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_LOCKED_MEM_HH__
diff --git a/src/arch/alpha/microcode_rom.hh b/src/arch/alpha/microcode_rom.hh
new file mode 100644
index 000000000..ef0602580
--- /dev/null
+++ b/src/arch/alpha/microcode_rom.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_ALPHA_MICROCODE_ROM_HH__
+#define __ARCH_ALPHA_MICROCODE_ROM_HH__
+
+#include "sim/microcode_rom.hh"
+
+namespace AlphaISA
+{
+ using ::MicrocodeRom;
+}
+
+#endif // __ARCH_ALPHA_MICROCODE_ROM_HH__
diff --git a/src/arch/alpha/miscregfile.cc b/src/arch/alpha/miscregfile.cc
index cb5875349..61a86f1fb 100644
--- a/src/arch/alpha/miscregfile.cc
+++ b/src/arch/alpha/miscregfile.cc
@@ -30,121 +30,121 @@
* Kevin Lim
*/
+#include <cassert>
+
#include "arch/alpha/miscregfile.hh"
#include "base/misc.hh"
-namespace AlphaISA
-{
+namespace AlphaISA {
- void
- MiscRegFile::serialize(std::ostream &os)
- {
- SERIALIZE_SCALAR(fpcr);
- SERIALIZE_SCALAR(uniq);
- SERIALIZE_SCALAR(lock_flag);
- SERIALIZE_SCALAR(lock_addr);
- SERIALIZE_ARRAY(ipr, NumInternalProcRegs);
- }
+void
+MiscRegFile::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(fpcr);
+ SERIALIZE_SCALAR(uniq);
+ SERIALIZE_SCALAR(lock_flag);
+ SERIALIZE_SCALAR(lock_addr);
+ SERIALIZE_ARRAY(ipr, NumInternalProcRegs);
+}
- void
- MiscRegFile::unserialize(Checkpoint *cp, const std::string &section)
- {
- UNSERIALIZE_SCALAR(fpcr);
- UNSERIALIZE_SCALAR(uniq);
- UNSERIALIZE_SCALAR(lock_flag);
- UNSERIALIZE_SCALAR(lock_addr);
- UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs);
- }
+void
+MiscRegFile::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(fpcr);
+ UNSERIALIZE_SCALAR(uniq);
+ UNSERIALIZE_SCALAR(lock_flag);
+ UNSERIALIZE_SCALAR(lock_addr);
+ UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs);
+}
- MiscReg
- MiscRegFile::readRegNoEffect(int misc_reg)
- {
- switch(misc_reg) {
- case MISCREG_FPCR:
- return fpcr;
- case MISCREG_UNIQ:
- return uniq;
- case MISCREG_LOCKFLAG:
- return lock_flag;
- case MISCREG_LOCKADDR:
- return lock_addr;
- case MISCREG_INTR:
- return intr_flag;
- default:
- assert(misc_reg < NumInternalProcRegs);
- return ipr[misc_reg];
- }
+MiscReg
+MiscRegFile::readRegNoEffect(int misc_reg)
+{
+ switch (misc_reg) {
+ case MISCREG_FPCR:
+ return fpcr;
+ case MISCREG_UNIQ:
+ return uniq;
+ case MISCREG_LOCKFLAG:
+ return lock_flag;
+ case MISCREG_LOCKADDR:
+ return lock_addr;
+ case MISCREG_INTR:
+ return intr_flag;
+ default:
+ assert(misc_reg < NumInternalProcRegs);
+ return ipr[misc_reg];
}
+}
- MiscReg
- MiscRegFile::readReg(int misc_reg, ThreadContext *tc)
- {
- switch(misc_reg) {
- case MISCREG_FPCR:
- return fpcr;
- case MISCREG_UNIQ:
- return uniq;
- case MISCREG_LOCKFLAG:
- return lock_flag;
- case MISCREG_LOCKADDR:
- return lock_addr;
- case MISCREG_INTR:
- return intr_flag;
- default:
- return readIpr(misc_reg, tc);
- }
+MiscReg
+MiscRegFile::readReg(int misc_reg, ThreadContext *tc)
+{
+ switch (misc_reg) {
+ case MISCREG_FPCR:
+ return fpcr;
+ case MISCREG_UNIQ:
+ return uniq;
+ case MISCREG_LOCKFLAG:
+ return lock_flag;
+ case MISCREG_LOCKADDR:
+ return lock_addr;
+ case MISCREG_INTR:
+ return intr_flag;
+ default:
+ return readIpr(misc_reg, tc);
}
+}
- void
- MiscRegFile::setRegNoEffect(int misc_reg, const MiscReg &val)
- {
- switch(misc_reg) {
- case MISCREG_FPCR:
- fpcr = val;
- return;
- case MISCREG_UNIQ:
- uniq = val;
- return;
- case MISCREG_LOCKFLAG:
- lock_flag = val;
- return;
- case MISCREG_LOCKADDR:
- lock_addr = val;
- return;
- case MISCREG_INTR:
- intr_flag = val;
- return;
- default:
- assert(misc_reg < NumInternalProcRegs);
- ipr[misc_reg] = val;
- return;
- }
+void
+MiscRegFile::setRegNoEffect(int misc_reg, const MiscReg &val)
+{
+ switch (misc_reg) {
+ case MISCREG_FPCR:
+ fpcr = val;
+ return;
+ case MISCREG_UNIQ:
+ uniq = val;
+ return;
+ case MISCREG_LOCKFLAG:
+ lock_flag = val;
+ return;
+ case MISCREG_LOCKADDR:
+ lock_addr = val;
+ return;
+ case MISCREG_INTR:
+ intr_flag = val;
+ return;
+ default:
+ assert(misc_reg < NumInternalProcRegs);
+ ipr[misc_reg] = val;
+ return;
}
+}
- void
- MiscRegFile::setReg(int misc_reg, const MiscReg &val,
- ThreadContext *tc)
- {
- switch(misc_reg) {
- case MISCREG_FPCR:
- fpcr = val;
- return;
- case MISCREG_UNIQ:
- uniq = val;
- return;
- case MISCREG_LOCKFLAG:
- lock_flag = val;
- return;
- case MISCREG_LOCKADDR:
- lock_addr = val;
- return;
- case MISCREG_INTR:
- intr_flag = val;
- return;
- default:
- setIpr(misc_reg, val, tc);
- return;
- }
+void
+MiscRegFile::setReg(int misc_reg, const MiscReg &val, ThreadContext *tc)
+{
+ switch (misc_reg) {
+ case MISCREG_FPCR:
+ fpcr = val;
+ return;
+ case MISCREG_UNIQ:
+ uniq = val;
+ return;
+ case MISCREG_LOCKFLAG:
+ lock_flag = val;
+ return;
+ case MISCREG_LOCKADDR:
+ lock_addr = val;
+ return;
+ case MISCREG_INTR:
+ intr_flag = val;
+ return;
+ default:
+ setIpr(misc_reg, val, tc);
+ return;
}
-
}
+
+} // namespace AlphaISA
diff --git a/src/arch/alpha/miscregfile.hh b/src/arch/alpha/miscregfile.hh
index 022b6404a..6105ce683 100644
--- a/src/arch/alpha/miscregfile.hh
+++ b/src/arch/alpha/miscregfile.hh
@@ -32,85 +32,79 @@
#ifndef __ARCH_ALPHA_MISCREGFILE_HH__
#define __ARCH_ALPHA_MISCREGFILE_HH__
+#include <iosfwd>
+
#include "arch/alpha/ipr.hh"
#include "arch/alpha/types.hh"
#include "sim/host.hh"
#include "sim/serialize.hh"
-#include <iostream>
-
class Checkpoint;
class ThreadContext;
-namespace AlphaISA
-{
- enum MiscRegIndex
- {
- MISCREG_FPCR = NumInternalProcRegs,
- MISCREG_UNIQ,
- MISCREG_LOCKFLAG,
- MISCREG_LOCKADDR,
- MISCREG_INTR
- };
-
- static inline std::string getMiscRegName(RegIndex)
- {
- return "";
- }
-
- 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
- int intr_flag;
-
- public:
- MiscRegFile()
- {
- initializeIprTable();
- }
+namespace AlphaISA {
- MiscReg readRegNoEffect(int misc_reg);
-
- MiscReg readReg(int misc_reg, ThreadContext *tc);
+enum MiscRegIndex
+{
+ MISCREG_FPCR = NumInternalProcRegs,
+ MISCREG_UNIQ,
+ MISCREG_LOCKFLAG,
+ MISCREG_LOCKADDR,
+ MISCREG_INTR
+};
+
+class MiscRegFile
+{
+ public:
+ friend class RegFile;
+ typedef uint64_t InternalProcReg;
- //These functions should be removed once the simplescalar cpu model
- //has been replaced.
- int getInstAsid();
- int getDataAsid();
+ 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
+ int intr_flag;
- void setRegNoEffect(int misc_reg, const MiscReg &val);
+ InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
- void setReg(int misc_reg, const MiscReg &val,
- ThreadContext *tc);
+ protected:
+ InternalProcReg readIpr(int idx, ThreadContext *tc);
+ void setIpr(int idx, InternalProcReg val, ThreadContext *tc);
- void clear()
- {
- fpcr = uniq = 0;
- lock_flag = 0;
- lock_addr = 0;
- intr_flag = 0;
- }
+ public:
+ MiscRegFile()
+ {
+ initializeIprTable();
+ }
- void serialize(std::ostream &os);
+ // These functions should be removed once the simplescalar cpu
+ // model has been replaced.
+ int getInstAsid();
+ int getDataAsid();
- void unserialize(Checkpoint *cp, const std::string &section);
- protected:
- typedef uint64_t InternalProcReg;
+ MiscReg readRegNoEffect(int misc_reg);
+ MiscReg readReg(int misc_reg, ThreadContext *tc);
- InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
+ void setRegNoEffect(int misc_reg, const MiscReg &val);
+ void setReg(int misc_reg, const MiscReg &val, ThreadContext *tc);
- private:
- InternalProcReg readIpr(int idx, ThreadContext *tc);
+ void
+ clear()
+ {
+ fpcr = 0;
+ uniq = 0;
+ lock_flag = 0;
+ lock_addr = 0;
+ intr_flag = 0;
+ }
- void setIpr(int idx, InternalProcReg val, ThreadContext *tc);
- friend class RegFile;
- };
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+};
- void copyIprs(ThreadContext *src, ThreadContext *dest);
+void copyIprs(ThreadContext *src, ThreadContext *dest);
-}
+} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_MISCREGFILE_HH__
diff --git a/src/arch/alpha/mmaped_ipr.hh b/src/arch/alpha/mmaped_ipr.hh
index 2b4ba8745..af2469ca7 100644
--- a/src/arch/alpha/mmaped_ipr.hh
+++ b/src/arch/alpha/mmaped_ipr.hh
@@ -39,9 +39,8 @@
#include "mem/packet.hh"
+namespace AlphaISA {
-namespace AlphaISA
-{
inline Tick
handleIprRead(ThreadContext *xc, Packet *pkt)
{
@@ -58,4 +57,4 @@ handleIprWrite(ThreadContext *xc, Packet *pkt)
} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_MMAPED_IPR_HH__
diff --git a/src/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc
index ed1d255a6..58a3d31eb 100644
--- a/src/arch/alpha/osfpal.cc
+++ b/src/arch/alpha/osfpal.cc
@@ -30,275 +30,273 @@
#include "arch/alpha/osfpal.hh"
-namespace {
- const char *strings[PAL::NumCodes] = {
+const char *
+PAL::name(int index)
+{
+ static const char *strings[PAL::NumCodes] = {
// Priviledged PAL instructions
- "halt", // 0x00
- "cflush", // 0x01
- "draina", // 0x02
- 0, // 0x03
- 0, // 0x04
- 0, // 0x05
- 0, // 0x06
- 0, // 0x07
- 0, // 0x08
- "cserve", // 0x09
- "swppal", // 0x0a
- 0, // 0x0b
- 0, // 0x0c
- "wripir", // 0x0d
- 0, // 0x0e
- 0, // 0x0f
- "rdmces", // 0x10
- "wrmces", // 0x11
- 0, // 0x12
- 0, // 0x13
- 0, // 0x14
- 0, // 0x15
- 0, // 0x16
- 0, // 0x17
- 0, // 0x18
- 0, // 0x19
- 0, // 0x1a
- 0, // 0x1b
- 0, // 0x1c
- 0, // 0x1d
- 0, // 0x1e
- 0, // 0x1f
- 0, // 0x20
- 0, // 0x21
- 0, // 0x22
- 0, // 0x23
- 0, // 0x24
- 0, // 0x25
- 0, // 0x26
- 0, // 0x27
- 0, // 0x28
- 0, // 0x29
- 0, // 0x2a
- "wrfen", // 0x2b
- 0, // 0x2c
- "wrvptptr", // 0x2d
- 0, // 0x2e
- 0, // 0x2f
- "swpctx", // 0x30
- "wrval", // 0x31
- "rdval", // 0x32
- "tbi", // 0x33
- "wrent", // 0x34
- "swpipl", // 0x35
- "rdps", // 0x36
- "wrkgp", // 0x37
- "wrusp", // 0x38
- "wrperfmon", // 0x39
- "rdusp", // 0x3a
- 0, // 0x3b
- "whami", // 0x3c
- "retsys", // 0x3d
- "wtint", // 0x3e
- "rti", // 0x3f
- 0, // 0x40
- 0, // 0x41
- 0, // 0x42
- 0, // 0x43
- 0, // 0x44
- 0, // 0x45
- 0, // 0x46
- 0, // 0x47
- 0, // 0x48
- 0, // 0x49
- 0, // 0x4a
- 0, // 0x4b
- 0, // 0x4c
- 0, // 0x4d
- 0, // 0x4e
- 0, // 0x4f
- 0, // 0x50
- 0, // 0x51
- 0, // 0x52
- 0, // 0x53
- 0, // 0x54
- 0, // 0x55
- 0, // 0x56
- 0, // 0x57
- 0, // 0x58
- 0, // 0x59
- 0, // 0x5a
- 0, // 0x5b
- 0, // 0x5c
- 0, // 0x5d
- 0, // 0x5e
- 0, // 0x5f
- 0, // 0x60
- 0, // 0x61
- 0, // 0x62
- 0, // 0x63
- 0, // 0x64
- 0, // 0x65
- 0, // 0x66
- 0, // 0x67
- 0, // 0x68
- 0, // 0x69
- 0, // 0x6a
- 0, // 0x6b
- 0, // 0x6c
- 0, // 0x6d
- 0, // 0x6e
- 0, // 0x6f
- 0, // 0x70
- 0, // 0x71
- 0, // 0x72
- 0, // 0x73
- 0, // 0x74
- 0, // 0x75
- 0, // 0x76
- 0, // 0x77
- 0, // 0x78
- 0, // 0x79
- 0, // 0x7a
- 0, // 0x7b
- 0, // 0x7c
- 0, // 0x7d
- 0, // 0x7e
- 0, // 0x7f
+ "halt", // 0x00
+ "cflush", // 0x01
+ "draina", // 0x02
+ 0, // 0x03
+ 0, // 0x04
+ 0, // 0x05
+ 0, // 0x06
+ 0, // 0x07
+ 0, // 0x08
+ "cserve", // 0x09
+ "swppal", // 0x0a
+ 0, // 0x0b
+ 0, // 0x0c
+ "wripir", // 0x0d
+ 0, // 0x0e
+ 0, // 0x0f
+ "rdmces", // 0x10
+ "wrmces", // 0x11
+ 0, // 0x12
+ 0, // 0x13
+ 0, // 0x14
+ 0, // 0x15
+ 0, // 0x16
+ 0, // 0x17
+ 0, // 0x18
+ 0, // 0x19
+ 0, // 0x1a
+ 0, // 0x1b
+ 0, // 0x1c
+ 0, // 0x1d
+ 0, // 0x1e
+ 0, // 0x1f
+ 0, // 0x20
+ 0, // 0x21
+ 0, // 0x22
+ 0, // 0x23
+ 0, // 0x24
+ 0, // 0x25
+ 0, // 0x26
+ 0, // 0x27
+ 0, // 0x28
+ 0, // 0x29
+ 0, // 0x2a
+ "wrfen", // 0x2b
+ 0, // 0x2c
+ "wrvptptr", // 0x2d
+ 0, // 0x2e
+ 0, // 0x2f
+ "swpctx", // 0x30
+ "wrval", // 0x31
+ "rdval", // 0x32
+ "tbi", // 0x33
+ "wrent", // 0x34
+ "swpipl", // 0x35
+ "rdps", // 0x36
+ "wrkgp", // 0x37
+ "wrusp", // 0x38
+ "wrperfmon", // 0x39
+ "rdusp", // 0x3a
+ 0, // 0x3b
+ "whami", // 0x3c
+ "retsys", // 0x3d
+ "wtint", // 0x3e
+ "rti", // 0x3f
+ 0, // 0x40
+ 0, // 0x41
+ 0, // 0x42
+ 0, // 0x43
+ 0, // 0x44
+ 0, // 0x45
+ 0, // 0x46
+ 0, // 0x47
+ 0, // 0x48
+ 0, // 0x49
+ 0, // 0x4a
+ 0, // 0x4b
+ 0, // 0x4c
+ 0, // 0x4d
+ 0, // 0x4e
+ 0, // 0x4f
+ 0, // 0x50
+ 0, // 0x51
+ 0, // 0x52
+ 0, // 0x53
+ 0, // 0x54
+ 0, // 0x55
+ 0, // 0x56
+ 0, // 0x57
+ 0, // 0x58
+ 0, // 0x59
+ 0, // 0x5a
+ 0, // 0x5b
+ 0, // 0x5c
+ 0, // 0x5d
+ 0, // 0x5e
+ 0, // 0x5f
+ 0, // 0x60
+ 0, // 0x61
+ 0, // 0x62
+ 0, // 0x63
+ 0, // 0x64
+ 0, // 0x65
+ 0, // 0x66
+ 0, // 0x67
+ 0, // 0x68
+ 0, // 0x69
+ 0, // 0x6a
+ 0, // 0x6b
+ 0, // 0x6c
+ 0, // 0x6d
+ 0, // 0x6e
+ 0, // 0x6f
+ 0, // 0x70
+ 0, // 0x71
+ 0, // 0x72
+ 0, // 0x73
+ 0, // 0x74
+ 0, // 0x75
+ 0, // 0x76
+ 0, // 0x77
+ 0, // 0x78
+ 0, // 0x79
+ 0, // 0x7a
+ 0, // 0x7b
+ 0, // 0x7c
+ 0, // 0x7d
+ 0, // 0x7e
+ 0, // 0x7f
// Unpriviledged PAL instructions
- "bpt", // 0x80
- "bugchk", // 0x81
- 0, // 0x82
- "callsys", // 0x83
- 0, // 0x84
- 0, // 0x85
- "imb", // 0x86
- 0, // 0x87
- 0, // 0x88
- 0, // 0x89
- 0, // 0x8a
- 0, // 0x8b
- 0, // 0x8c
- 0, // 0x8d
- 0, // 0x8e
- 0, // 0x8f
- 0, // 0x90
- 0, // 0x91
- "urti", // 0x92
- 0, // 0x93
- 0, // 0x94
- 0, // 0x95
- 0, // 0x96
- 0, // 0x97
- 0, // 0x98
- 0, // 0x99
- 0, // 0x9a
- 0, // 0x9b
- 0, // 0x9c
- 0, // 0x9d
- "rdunique", // 0x9e
- "wrunique", // 0x9f
- 0, // 0xa0
- 0, // 0xa1
- 0, // 0xa2
- 0, // 0xa3
- 0, // 0xa4
- 0, // 0xa5
- 0, // 0xa6
- 0, // 0xa7
- 0, // 0xa8
- 0, // 0xa9
- "gentrap", // 0xaa
- 0, // 0xab
- 0, // 0xac
- 0, // 0xad
- "clrfen", // 0xae
- 0, // 0xaf
- 0, // 0xb0
- 0, // 0xb1
- 0, // 0xb2
- 0, // 0xb3
- 0, // 0xb4
- 0, // 0xb5
- 0, // 0xb6
- 0, // 0xb7
- 0, // 0xb8
- 0, // 0xb9
- 0, // 0xba
- 0, // 0xbb
- 0, // 0xbc
- 0, // 0xbd
- "nphalt", // 0xbe
- "copypal", // 0xbf
+ "bpt", // 0x80
+ "bugchk", // 0x81
+ 0, // 0x82
+ "callsys", // 0x83
+ 0, // 0x84
+ 0, // 0x85
+ "imb", // 0x86
+ 0, // 0x87
+ 0, // 0x88
+ 0, // 0x89
+ 0, // 0x8a
+ 0, // 0x8b
+ 0, // 0x8c
+ 0, // 0x8d
+ 0, // 0x8e
+ 0, // 0x8f
+ 0, // 0x90
+ 0, // 0x91
+ "urti", // 0x92
+ 0, // 0x93
+ 0, // 0x94
+ 0, // 0x95
+ 0, // 0x96
+ 0, // 0x97
+ 0, // 0x98
+ 0, // 0x99
+ 0, // 0x9a
+ 0, // 0x9b
+ 0, // 0x9c
+ 0, // 0x9d
+ "rdunique", // 0x9e
+ "wrunique", // 0x9f
+ 0, // 0xa0
+ 0, // 0xa1
+ 0, // 0xa2
+ 0, // 0xa3
+ 0, // 0xa4
+ 0, // 0xa5
+ 0, // 0xa6
+ 0, // 0xa7
+ 0, // 0xa8
+ 0, // 0xa9
+ "gentrap", // 0xaa
+ 0, // 0xab
+ 0, // 0xac
+ 0, // 0xad
+ "clrfen", // 0xae
+ 0, // 0xaf
+ 0, // 0xb0
+ 0, // 0xb1
+ 0, // 0xb2
+ 0, // 0xb3
+ 0, // 0xb4
+ 0, // 0xb5
+ 0, // 0xb6
+ 0, // 0xb7
+ 0, // 0xb8
+ 0, // 0xb9
+ 0, // 0xba
+ 0, // 0xbb
+ 0, // 0xbc
+ 0, // 0xbd
+ "nphalt", // 0xbe
+ "copypal", // 0xbf
#if 0
- 0, // 0xc0
- 0, // 0xc1
- 0, // 0xc2
- 0, // 0xc3
- 0, // 0xc4
- 0, // 0xc5
- 0, // 0xc6
- 0, // 0xc7
- 0, // 0xc8
- 0, // 0xc9
- 0, // 0xca
- 0, // 0xcb
- 0, // 0xcc
- 0, // 0xcd
- 0, // 0xce
- 0, // 0xcf
- 0, // 0xd0
- 0, // 0xd1
- 0, // 0xd2
- 0, // 0xd3
- 0, // 0xd4
- 0, // 0xd5
- 0, // 0xd6
- 0, // 0xd7
- 0, // 0xd8
- 0, // 0xd9
- 0, // 0xda
- 0, // 0xdb
- 0, // 0xdc
- 0, // 0xdd
- 0, // 0xde
- 0, // 0xdf
- 0, // 0xe0
- 0, // 0xe1
- 0, // 0xe2
- 0, // 0xe3
- 0, // 0xe4
- 0, // 0xe5
- 0, // 0xe6
- 0, // 0xe7
- 0, // 0xe8
- 0, // 0xe9
- 0, // 0xea
- 0, // 0xeb
- 0, // 0xec
- 0, // 0xed
- 0, // 0xee
- 0, // 0xef
- 0, // 0xf0
- 0, // 0xf1
- 0, // 0xf2
- 0, // 0xf3
- 0, // 0xf4
- 0, // 0xf5
- 0, // 0xf6
- 0, // 0xf7
- 0, // 0xf8
- 0, // 0xf9
- 0, // 0xfa
- 0, // 0xfb
- 0, // 0xfc
- 0, // 0xfd
- 0, // 0xfe
- 0 // 0xff
+ 0, // 0xc0
+ 0, // 0xc1
+ 0, // 0xc2
+ 0, // 0xc3
+ 0, // 0xc4
+ 0, // 0xc5
+ 0, // 0xc6
+ 0, // 0xc7
+ 0, // 0xc8
+ 0, // 0xc9
+ 0, // 0xca
+ 0, // 0xcb
+ 0, // 0xcc
+ 0, // 0xcd
+ 0, // 0xce
+ 0, // 0xcf
+ 0, // 0xd0
+ 0, // 0xd1
+ 0, // 0xd2
+ 0, // 0xd3
+ 0, // 0xd4
+ 0, // 0xd5
+ 0, // 0xd6
+ 0, // 0xd7
+ 0, // 0xd8
+ 0, // 0xd9
+ 0, // 0xda
+ 0, // 0xdb
+ 0, // 0xdc
+ 0, // 0xdd
+ 0, // 0xde
+ 0, // 0xdf
+ 0, // 0xe0
+ 0, // 0xe1
+ 0, // 0xe2
+ 0, // 0xe3
+ 0, // 0xe4
+ 0, // 0xe5
+ 0, // 0xe6
+ 0, // 0xe7
+ 0, // 0xe8
+ 0, // 0xe9
+ 0, // 0xea
+ 0, // 0xeb
+ 0, // 0xec
+ 0, // 0xed
+ 0, // 0xee
+ 0, // 0xef
+ 0, // 0xf0
+ 0, // 0xf1
+ 0, // 0xf2
+ 0, // 0xf3
+ 0, // 0xf4
+ 0, // 0xf5
+ 0, // 0xf6
+ 0, // 0xf7
+ 0, // 0xf8
+ 0, // 0xf9
+ 0, // 0xfa
+ 0, // 0xfb
+ 0, // 0xfc
+ 0, // 0xfd
+ 0, // 0xfe
+ 0 // 0xff
#endif
};
-}
-const char *
-PAL::name(int index)
-{
if (index > NumCodes || index < 0)
return 0;
diff --git a/src/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh
index cf3940b85..2618e9dbd 100644
--- a/src/arch/alpha/osfpal.hh
+++ b/src/arch/alpha/osfpal.hh
@@ -28,8 +28,8 @@
* Authors: Nathan Binkert
*/
-#ifndef __OSFPAL_HH__
-#define __OSFPAL_HH__
+#ifndef __ARCH_ALPHA_OSFPAL_HH__
+#define __ARCH_ALPHA_OSFPAL_HH__
struct PAL
{
@@ -79,4 +79,4 @@ struct PAL
static const char *name(int index);
};
-#endif // __OSFPAL_HH__
+#endif // __ARCH_ALPHA_OSFPAL_HH__
diff --git a/src/arch/alpha/pagetable.cc b/src/arch/alpha/pagetable.cc
index 3f9537834..6640e72e2 100644
--- a/src/arch/alpha/pagetable.cc
+++ b/src/arch/alpha/pagetable.cc
@@ -31,33 +31,34 @@
#include "arch/alpha/pagetable.hh"
#include "sim/serialize.hh"
-namespace AlphaISA
+namespace AlphaISA {
+
+void
+TlbEntry::serialize(std::ostream &os)
{
- void
- TlbEntry::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);
- }
+ 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
- TlbEntry::unserialize(Checkpoint *cp, const std::string &section)
- {
- 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);
- }
+void
+TlbEntry::unserialize(Checkpoint *cp, const std::string &section)
+{
+ 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);
}
+
+} //namespace AlphaISA
diff --git a/src/arch/alpha/pagetable.hh b/src/arch/alpha/pagetable.hh
index 8ce5b4e5d..59df93bef 100644
--- a/src/arch/alpha/pagetable.hh
+++ b/src/arch/alpha/pagetable.hh
@@ -38,97 +38,109 @@
namespace AlphaISA {
- struct VAddr
+struct VAddr
+{
+ static const int ImplBits = 43;
+ static const Addr ImplMask = (ULL(1) << ImplBits) - 1;
+ static const Addr UnImplMask = ~ImplMask;
+
+ Addr addr;
+
+ VAddr(Addr a) : addr(a) {}
+ operator Addr() const { return addr; }
+ const VAddr &operator=(Addr a) { addr = a; return *this; }
+
+ Addr vpn() const { return (addr & ImplMask) >> PageShift; }
+ Addr page() const { return addr & PageMask; }
+ Addr offset() const { return addr & PageOffset; }
+
+ Addr level3() const
+ { return PteAddr(addr >> PageShift); }
+ Addr level2() const
+ { return PteAddr(addr >> (NPtePageShift + PageShift)); }
+ Addr level1() const
+ { return PteAddr(addr >> (2 * NPtePageShift + PageShift)); }
+};
+
+struct PageTableEntry
+{
+ PageTableEntry(uint64_t e) : entry(e) {}
+ uint64_t entry;
+ operator uint64_t() const { return entry; }
+ const PageTableEntry &operator=(uint64_t e) { entry = e; return *this; }
+ const PageTableEntry &operator=(const PageTableEntry &e)
+ { entry = e.entry; return *this; }
+
+ Addr _pfn() const { return (entry >> 32) & 0xffffffff; }
+ Addr _sw() const { return (entry >> 16) & 0xffff; }
+ int _rsv0() const { return (entry >> 14) & 0x3; }
+ bool _uwe() const { return (entry >> 13) & 0x1; }
+ bool _kwe() const { return (entry >> 12) & 0x1; }
+ int _rsv1() const { return (entry >> 10) & 0x3; }
+ bool _ure() const { return (entry >> 9) & 0x1; }
+ bool _kre() const { return (entry >> 8) & 0x1; }
+ bool _nomb() const { return (entry >> 7) & 0x1; }
+ int _gh() const { return (entry >> 5) & 0x3; }
+ bool _asm_() const { return (entry >> 4) & 0x1; }
+ bool _foe() const { return (entry >> 3) & 0x1; }
+ bool _fow() const { return (entry >> 2) & 0x1; }
+ bool _for() const { return (entry >> 1) & 0x1; }
+ bool valid() const { return (entry >> 0) & 0x1; }
+
+ Addr paddr() const { return _pfn() << PageShift; }
+};
+
+// ITB/DTB table entry
+struct TlbEntry
+{
+ Addr tag; // virtual page number tag
+ Addr ppn; // physical page number
+ uint8_t xre; // read permissions - VMEM_PERM_* mask
+ uint8_t xwe; // write permissions - VMEM_PERM_* mask
+ uint8_t asn; // address space number
+ bool asma; // address space match
+ bool fonr; // fault on read
+ bool fonw; // fault on write
+ bool valid; // valid page table entry
+
+
+ //Construct an entry that maps to physical address addr.
+ TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
{
- static const int ImplBits = 43;
- static const Addr ImplMask = (ULL(1) << ImplBits) - 1;
- static const Addr UnImplMask = ~ImplMask;
-
- VAddr(Addr a) : addr(a) {}
- Addr addr;
- operator Addr() const { return addr; }
- const VAddr &operator=(Addr a) { addr = a; return *this; }
-
- Addr vpn() const { return (addr & ImplMask) >> PageShift; }
- Addr page() const { return addr & PageMask; }
- Addr offset() const { return addr & PageOffset; }
-
- Addr level3() const
- { return AlphaISA::PteAddr(addr >> PageShift); }
- Addr level2() const
- { return AlphaISA::PteAddr(addr >> NPtePageShift + PageShift); }
- Addr level1() const
- { return AlphaISA::PteAddr(addr >> 2 * NPtePageShift + PageShift); }
- };
-
- struct PageTableEntry
+ VAddr vaddr(_vaddr);
+ VAddr paddr(_paddr);
+ tag = vaddr.vpn();
+ ppn = paddr.vpn();
+ xre = 15;
+ xwe = 15;
+ asn = _asn;
+ asma = false;
+ fonr = false;
+ fonw = false;
+ valid = true;
+ }
+
+ TlbEntry()
+ {}
+
+ void
+ updateVaddr(Addr new_vaddr)
{
- PageTableEntry(uint64_t e) : entry(e) {}
- uint64_t entry;
- operator uint64_t() const { return entry; }
- const PageTableEntry &operator=(uint64_t e) { entry = e; return *this; }
- const PageTableEntry &operator=(const PageTableEntry &e)
- { entry = e.entry; return *this; }
-
- Addr _pfn() const { return (entry >> 32) & 0xffffffff; }
- Addr _sw() const { return (entry >> 16) & 0xffff; }
- int _rsv0() const { return (entry >> 14) & 0x3; }
- bool _uwe() const { return (entry >> 13) & 0x1; }
- bool _kwe() const { return (entry >> 12) & 0x1; }
- int _rsv1() const { return (entry >> 10) & 0x3; }
- bool _ure() const { return (entry >> 9) & 0x1; }
- bool _kre() const { return (entry >> 8) & 0x1; }
- bool _nomb() const { return (entry >> 7) & 0x1; }
- int _gh() const { return (entry >> 5) & 0x3; }
- bool _asm_() const { return (entry >> 4) & 0x1; }
- bool _foe() const { return (entry >> 3) & 0x1; }
- bool _fow() const { return (entry >> 2) & 0x1; }
- bool _for() const { return (entry >> 1) & 0x1; }
- bool valid() const { return (entry >> 0) & 0x1; }
-
- Addr paddr() const { return _pfn() << PageShift; }
- };
-
- // ITB/DTB table entry
- struct TlbEntry
+ VAddr vaddr(new_vaddr);
+ tag = vaddr.vpn();
+ }
+
+ Addr
+ pageStart()
{
- //Construct an entry that maps to physical address addr.
- TlbEntry(Addr _asn, Addr _vaddr, Addr _paddr)
- {
- VAddr vaddr(_vaddr);
- VAddr paddr(_paddr);
- tag = vaddr.vpn();
- ppn = paddr.vpn();
- xre = 15;
- xwe = 15;
- asn = _asn;
- asma = false;
- fonr = false;
- fonw = false;
- valid = true;
- }
- TlbEntry()
- {}
-
- Addr tag; // virtual page number tag
- Addr ppn; // physical page number
- uint8_t xre; // read permissions - VMEM_PERM_* mask
- uint8_t xwe; // write permissions - VMEM_PERM_* mask
- uint8_t asn; // address space number
- bool asma; // address space match
- bool fonr; // fault on read
- bool fonw; // fault on write
- bool valid; // valid page table entry
-
- Addr pageStart()
- {
- return ppn << PageShift;
- }
-
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
- };
+ return ppn << PageShift;
+ }
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
};
+
+} // namespace AlphaISA
+
#endif // __ARCH_ALPHA_PAGETABLE_H__
diff --git a/src/arch/alpha/predecoder.hh b/src/arch/alpha/predecoder.hh
index 725b35b9d..5502342e1 100644
--- a/src/arch/alpha/predecoder.hh
+++ b/src/arch/alpha/predecoder.hh
@@ -38,62 +38,72 @@
class ThreadContext;
-namespace AlphaISA
+namespace AlphaISA {
+
+class Predecoder
{
- class Predecoder
+ protected:
+ ThreadContext *tc;
+
+ // The extended machine instruction being generated
+ ExtMachInst ext_inst;
+
+ public:
+ Predecoder(ThreadContext * _tc)
+ : tc(_tc)
+ {}
+
+ ThreadContext *
+ getTC()
{
- protected:
- ThreadContext * tc;
- //The extended machine instruction being generated
- ExtMachInst ext_inst;
-
- public:
- Predecoder(ThreadContext * _tc) : tc(_tc)
- {}
-
- ThreadContext * getTC()
- {
- return tc;
- }
-
- void setTC(ThreadContext * _tc)
- {
- tc = _tc;
- }
-
- void process()
- {
- }
-
- void reset()
- {}
-
- //Use this to give data to the predecoder. This should be used
- //when there is control flow.
- void moreBytes(Addr pc, Addr fetchPC, MachInst inst)
- {
- ext_inst = inst;
+ return tc;
+ }
+
+ void
+ setTC(ThreadContext * _tc)
+ {
+ tc = _tc;
+ }
+
+ void
+ process()
+ { }
+
+ void
+ reset()
+ { }
+
+ // Use this to give data to the predecoder. This should be used
+ // when there is control flow.
+ void
+ moreBytes(Addr pc, Addr fetchPC, MachInst inst)
+ {
+ ext_inst = inst;
#if FULL_SYSTEM
- ext_inst|=(static_cast<ExtMachInst>(pc & 0x1) << 32);
+ ext_inst |= (static_cast<ExtMachInst>(pc & 0x1) << 32);
#endif
- }
-
- bool needMoreBytes()
- {
- return true;
- }
-
- bool extMachInstReady()
- {
- return true;
- }
-
- //This returns a constant reference to the ExtMachInst to avoid a copy
- const ExtMachInst & getExtMachInst()
- {
- return ext_inst;
- }
- };
+ }
+
+ bool
+ needMoreBytes()
+ {
+ return true;
+ }
+
+ bool
+ extMachInstReady()
+ {
+ return true;
+ }
+
+ // This returns a constant reference to the ExtMachInst to avoid a copy
+ const ExtMachInst &
+ getExtMachInst()
+ {
+ return ext_inst;
+ }
};
+} // namespace AlphaISA
+
#endif // __ARCH_ALPHA_PREDECODER_HH__
diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc
index c2d23ecdd..9c6e62815 100644
--- a/src/arch/alpha/process.cc
+++ b/src/arch/alpha/process.cc
@@ -32,16 +32,20 @@
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/process.hh"
#include "base/loader/object_file.hh"
+#include "base/loader/elf_object.hh"
#include "base/misc.hh"
#include "cpu/thread_context.hh"
+#include "mem/page_table.hh"
+#include "sim/process_impl.hh"
#include "sim/system.hh"
-
using namespace AlphaISA;
using namespace std;
-AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams * params,
- ObjectFile *objFile)
+static const int SyscallSuccessReg = 19;
+
+AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams *params,
+ ObjectFile *objFile)
: LiveProcess(params, objFile)
{
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
@@ -61,20 +65,165 @@ AlphaLiveProcess::AlphaLiveProcess(LiveProcessParams * params,
}
void
+AlphaLiveProcess::argsInit(int intSize, int pageSize)
+{
+ objFile->loadSections(initVirtMem);
+
+ typedef AuxVector<uint64_t> auxv_t;
+ std::vector<auxv_t> auxv;
+
+ ElfObject * elfObject = dynamic_cast<ElfObject *>(objFile);
+ if(elfObject)
+ {
+ // modern glibc uses a bunch of auxiliary vectors to set up
+ // TLS as well as do a bunch of other stuff
+ // these vectors go on the bottom of the stack, below argc/argv/envp
+ // pointers but above actual arg strings
+ // I don't have all the ones glibc looks at here, but so far it doesn't
+ // seem to be a problem.
+ // check out _dl_aux_init() in glibc/elf/dl-support.c for details
+ // --Lisa
+ auxv.push_back(auxv_t(M5_AT_PAGESZ, AlphaISA::VMPageSize));
+ auxv.push_back(auxv_t(M5_AT_CLKTCK, 100));
+ auxv.push_back(auxv_t(M5_AT_PHDR, elfObject->programHeaderTable()));
+ DPRINTF(Loader, "auxv at PHDR %08p\n", elfObject->programHeaderTable());
+ auxv.push_back(auxv_t(M5_AT_PHNUM, elfObject->programHeaderCount()));
+ auxv.push_back(auxv_t(M5_AT_ENTRY, objFile->entryPoint()));
+ auxv.push_back(auxv_t(M5_AT_UID, uid()));
+ auxv.push_back(auxv_t(M5_AT_EUID, euid()));
+ auxv.push_back(auxv_t(M5_AT_GID, gid()));
+ auxv.push_back(auxv_t(M5_AT_EGID, egid()));
+
+ }
+
+ // Calculate how much space we need for arg & env & auxv arrays.
+ int argv_array_size = intSize * (argv.size() + 1);
+ int envp_array_size = intSize * (envp.size() + 1);
+ int auxv_array_size = intSize * 2 * (auxv.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 +
+ auxv_array_size +
+ arg_data_size +
+ env_data_size;
+
+ if (space_needed < 32*1024)
+ space_needed = 32*1024;
+
+ // set bottom of stack
+ stack_min = stack_base - space_needed;
+ // align it
+ stack_min = roundDown(stack_min, pageSize);
+ stack_size = stack_base - stack_min;
+ // map memory
+ pTable->allocate(stack_min, 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 auxv_array_base = envp_array_base + envp_array_size;
+ Addr arg_data_base = auxv_array_base + auxv_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);
+
+ //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);
+ }
+
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
+
+ setSyscallArg(tc, 0, argc);
+ setSyscallArg(tc, 1, argv_array_base);
+ tc->setIntReg(StackPointerReg, stack_min);
+
+ Addr prog_entry = objFile->entryPoint();
+ tc->setPC(prog_entry);
+ tc->setNextPC(prog_entry + sizeof(MachInst));
+
+#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
+ tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+#endif
+
+
+}
+
+void
AlphaLiveProcess::startup()
{
if (checkpointRestored)
return;
+ Process::startup();
+
argsInit(MachineBytes, VMPageSize);
- threadContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer());
- //Opperate in user mode
- threadContexts[0]->setMiscRegNoEffect(IPR_ICM, 0x18);
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
+ tc->setIntReg(GlobalPointerReg, objFile->globalPointer());
+ //Operate in user mode
+ tc->setMiscRegNoEffect(IPR_ICM, 0x18);
//No super page mapping
- threadContexts[0]->setMiscRegNoEffect(IPR_MCSR, 0);
+ tc->setMiscRegNoEffect(IPR_MCSR, 0);
//Set this to 0 for now, but it should be unique for each process
- threadContexts[0]->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57);
+ tc->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57);
}
+AlphaISA::IntReg
+AlphaLiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < 6);
+ return tc->readIntReg(FirstArgumentReg + i);
+}
+
+void
+AlphaLiveProcess::setSyscallArg(ThreadContext *tc,
+ int i, AlphaISA::IntReg val)
+{
+ assert(i < 6);
+ tc->setIntReg(FirstArgumentReg + i, val);
+}
+void
+AlphaLiveProcess::setSyscallReturn(ThreadContext *tc,
+ SyscallReturn return_value)
+{
+ // 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
+ tc->setIntReg(SyscallSuccessReg, 0);
+ tc->setIntReg(ReturnValueReg, return_value.value());
+ } else {
+ // got an error, return details
+ tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
+ tc->setIntReg(ReturnValueReg, -return_value.value());
+ }
+}
diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh
index c66b97d23..6d083c5ac 100644
--- a/src/arch/alpha/process.hh
+++ b/src/arch/alpha/process.hh
@@ -29,24 +29,24 @@
* Ali Saidi
*/
-#ifndef __ALPHA_PROCESS_HH__
-#define __ALPHA_PROCESS_HH__
+#ifndef __ARCH_ALPHA_PROCESS_HH__
+#define __ARCH_ALPHA_PROCESS_HH__
-#include <string>
-#include <vector>
#include "sim/process.hh"
-class ObjectFile;
-class System;
-
-
class AlphaLiveProcess : public LiveProcess
{
protected:
- AlphaLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
+ AlphaLiveProcess(LiveProcessParams *params, ObjectFile *objFile);
void startup();
-};
+ void argsInit(int intSize, int pageSize);
+
+ public:
+ AlphaISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, AlphaISA::IntReg val);
+ void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
+};
-#endif // __ALPHA_PROCESS_HH__
+#endif // __ARCH_ALPHA_PROCESS_HH__
diff --git a/src/arch/alpha/regfile.cc b/src/arch/alpha/regfile.cc
index 2653310d7..b3aa55b19 100644
--- a/src/arch/alpha/regfile.cc
+++ b/src/arch/alpha/regfile.cc
@@ -33,67 +33,68 @@
#include "arch/alpha/regfile.hh"
#include "cpu/thread_context.hh"
-namespace AlphaISA
+using namespace std;
+
+namespace AlphaISA {
+
+void
+RegFile::serialize(EventManager *em, ostream &os)
{
- void
- RegFile::serialize(std::ostream &os)
- {
- intRegFile.serialize(os);
- floatRegFile.serialize(os);
- miscRegFile.serialize(os);
- SERIALIZE_SCALAR(pc);
- SERIALIZE_SCALAR(npc);
+ intRegFile.serialize(os);
+ floatRegFile.serialize(os);
+ miscRegFile.serialize(os);
+ SERIALIZE_SCALAR(pc);
+ SERIALIZE_SCALAR(npc);
#if FULL_SYSTEM
- SERIALIZE_SCALAR(intrflag);
+ SERIALIZE_SCALAR(intrflag);
#endif
- }
+}
- void
- RegFile::unserialize(Checkpoint *cp, const std::string &section)
- {
- intRegFile.unserialize(cp, section);
- floatRegFile.unserialize(cp, section);
- miscRegFile.unserialize(cp, section);
- UNSERIALIZE_SCALAR(pc);
- UNSERIALIZE_SCALAR(npc);
+void
+RegFile::unserialize(EventManager *em, Checkpoint *cp, const string &section)
+{
+ intRegFile.unserialize(cp, section);
+ floatRegFile.unserialize(cp, section);
+ miscRegFile.unserialize(cp, section);
+ UNSERIALIZE_SCALAR(pc);
+ UNSERIALIZE_SCALAR(npc);
#if FULL_SYSTEM
- UNSERIALIZE_SCALAR(intrflag);
+ UNSERIALIZE_SCALAR(intrflag);
#endif
- }
+}
- void
- copyRegs(ThreadContext *src, ThreadContext *dest)
- {
- // First loop through the integer registers.
- for (int i = 0; i < NumIntRegs; ++i) {
- dest->setIntReg(i, src->readIntReg(i));
- }
+void
+copyRegs(ThreadContext *src, ThreadContext *dest)
+{
+ // First loop through the integer registers.
+ for (int i = 0; i < NumIntRegs; ++i)
+ dest->setIntReg(i, src->readIntReg(i));
- // Then loop through the floating point registers.
- for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
- dest->setFloatRegBits(i, src->readFloatRegBits(i));
- }
+ // Then loop through the floating point registers.
+ for (int i = 0; i < NumFloatRegs; ++i)
+ dest->setFloatRegBits(i, src->readFloatRegBits(i));
- // Copy misc. registers
- copyMiscRegs(src, dest);
+ // Copy misc. registers
+ copyMiscRegs(src, dest);
- // Lastly copy PC/NPC
- dest->setPC(src->readPC());
- dest->setNextPC(src->readNextPC());
- }
+ // Lastly copy PC/NPC
+ dest->setPC(src->readPC());
+ dest->setNextPC(src->readNextPC());
+}
- void
- copyMiscRegs(ThreadContext *src, ThreadContext *dest)
- {
- dest->setMiscRegNoEffect(AlphaISA::MISCREG_FPCR,
- src->readMiscRegNoEffect(AlphaISA::MISCREG_FPCR));
- dest->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ,
- src->readMiscRegNoEffect(AlphaISA::MISCREG_UNIQ));
- dest->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG,
- src->readMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG));
- dest->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKADDR,
- src->readMiscRegNoEffect(AlphaISA::MISCREG_LOCKADDR));
+void
+copyMiscRegs(ThreadContext *src, ThreadContext *dest)
+{
+ dest->setMiscRegNoEffect(MISCREG_FPCR,
+ src->readMiscRegNoEffect(MISCREG_FPCR));
+ dest->setMiscRegNoEffect(MISCREG_UNIQ,
+ src->readMiscRegNoEffect(MISCREG_UNIQ));
+ dest->setMiscRegNoEffect(MISCREG_LOCKFLAG,
+ src->readMiscRegNoEffect(MISCREG_LOCKFLAG));
+ dest->setMiscRegNoEffect(MISCREG_LOCKADDR,
+ src->readMiscRegNoEffect(MISCREG_LOCKADDR));
- copyIprs(src, dest);
- }
+ copyIprs(src, dest);
}
+
+} // namespace AlphaISA
diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh
index 792a518fb..e431e7570 100644
--- a/src/arch/alpha/regfile.hh
+++ b/src/arch/alpha/regfile.hh
@@ -43,163 +43,187 @@
//XXX These should be implemented by someone who knows the alpha stuff better
class Checkpoint;
+class EventManager;
class ThreadContext;
-namespace AlphaISA
-{
-
- class RegFile {
+namespace AlphaISA {
- protected:
- Addr pc; // program counter
- Addr npc; // next-cycle program counter
- Addr nnpc;
+class RegFile {
+ protected:
+ Addr pc; // program counter
+ Addr npc; // next-cycle program counter
+ Addr nnpc; // next next-cycle program counter
- public:
- Addr readPC()
- {
- return pc;
- }
-
- void setPC(Addr val)
- {
- pc = val;
- }
+ public:
+ Addr
+ readPC()
+ {
+ return pc;
+ }
- Addr readNextPC()
- {
- return npc;
- }
+ void
+ setPC(Addr val)
+ {
+ pc = val;
+ }
- void setNextPC(Addr val)
- {
- npc = val;
- }
+ Addr
+ readNextPC()
+ {
+ return npc;
+ }
- Addr readNextNPC()
- {
- return npc + sizeof(MachInst);
- }
+ void
+ setNextPC(Addr val)
+ {
+ npc = val;
+ }
- void setNextNPC(Addr val)
- { }
+ Addr
+ readNextNPC()
+ {
+ return npc + sizeof(MachInst);
+ }
- protected:
- IntRegFile intRegFile; // (signed) integer register file
- FloatRegFile floatRegFile; // floating point register file
- MiscRegFile miscRegFile; // control register file
+ void
+ setNextNPC(Addr val)
+ { }
- public:
+ 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
+ int intrflag; // interrupt flag
- void clear()
- {
- intRegFile.clear();
- floatRegFile.clear();
- miscRegFile.clear();
- }
-
- MiscReg readMiscRegNoEffect(int miscReg)
- {
- return miscRegFile.readRegNoEffect(miscReg);
- }
-
- MiscReg readMiscReg(int miscReg, ThreadContext *tc)
- {
- return miscRegFile.readReg(miscReg, tc);
- }
+ int
+ instAsid()
+ {
+ return miscRegFile.getInstAsid();
+ }
- void setMiscRegNoEffect(int miscReg, const MiscReg &val)
- {
- miscRegFile.setRegNoEffect(miscReg, val);
- }
+ int
+ dataAsid()
+ {
+ return miscRegFile.getDataAsid();
+ }
+#endif // FULL_SYSTEM
- void setMiscReg(int miscReg, const MiscReg &val,
- ThreadContext * tc)
- {
- miscRegFile.setReg(miscReg, val, tc);
- }
+ void
+ clear()
+ {
+ intRegFile.clear();
+ floatRegFile.clear();
+ miscRegFile.clear();
+ }
- FloatReg readFloatReg(int floatReg)
- {
- return floatRegFile.d[floatReg];
- }
+ MiscReg
+ readMiscRegNoEffect(int miscReg)
+ {
+ return miscRegFile.readRegNoEffect(miscReg);
+ }
- FloatReg readFloatReg(int floatReg, int width)
- {
- return readFloatReg(floatReg);
- }
+ MiscReg
+ readMiscReg(int miscReg, ThreadContext *tc)
+ {
+ return miscRegFile.readReg(miscReg, tc);
+ }
- FloatRegBits readFloatRegBits(int floatReg)
- {
- return floatRegFile.q[floatReg];
- }
+ void
+ setMiscRegNoEffect(int miscReg, const MiscReg &val)
+ {
+ miscRegFile.setRegNoEffect(miscReg, val);
+ }
- FloatRegBits readFloatRegBits(int floatReg, int width)
- {
- return readFloatRegBits(floatReg);
- }
+ void
+ setMiscReg(int miscReg, const MiscReg &val, ThreadContext *tc)
+ {
+ miscRegFile.setReg(miscReg, val, tc);
+ }
- void setFloatReg(int floatReg, const FloatReg &val)
- {
- floatRegFile.d[floatReg] = val;
- }
+ FloatReg
+ readFloatReg(int floatReg)
+ {
+ return floatRegFile.d[floatReg];
+ }
- void setFloatReg(int floatReg, const FloatReg &val, int width)
- {
- setFloatReg(floatReg, val);
- }
+ FloatReg
+ readFloatReg(int floatReg, int width)
+ {
+ return readFloatReg(floatReg);
+ }
- void setFloatRegBits(int floatReg, const FloatRegBits &val)
- {
- floatRegFile.q[floatReg] = val;
- }
+ FloatRegBits
+ readFloatRegBits(int floatReg)
+ {
+ return floatRegFile.q[floatReg];
+ }
- void setFloatRegBits(int floatReg, const FloatRegBits &val, int width)
- {
- setFloatRegBits(floatReg, val);
- }
+ FloatRegBits
+ readFloatRegBits(int floatReg, int width)
+ {
+ return readFloatRegBits(floatReg);
+ }
- IntReg readIntReg(int intReg)
- {
- return intRegFile.readReg(intReg);
- }
+ void
+ setFloatReg(int floatReg, const FloatReg &val)
+ {
+ floatRegFile.d[floatReg] = val;
+ }
- void setIntReg(int intReg, const IntReg &val)
- {
- intRegFile.setReg(intReg, val);
- }
+ void
+ setFloatReg(int floatReg, const FloatReg &val, int width)
+ {
+ setFloatReg(floatReg, val);
+ }
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
+ void
+ setFloatRegBits(int floatReg, const FloatRegBits &val)
+ {
+ floatRegFile.q[floatReg] = val;
+ }
- void changeContext(RegContextParam param, RegContextVal val)
- {
- //This would be an alternative place to call/implement
- //the swapPALShadow function
- }
- };
+ void
+ setFloatRegBits(int floatReg, const FloatRegBits &val, int width)
+ {
+ setFloatRegBits(floatReg, val);
+ }
- static inline int flattenIntIndex(ThreadContext * tc, int reg)
+ IntReg
+ readIntReg(int intReg)
{
- return reg;
+ return intRegFile.readReg(intReg);
}
- static inline int flattenFloatIndex(ThreadContext * tc, int reg)
+ void
+ setIntReg(int intReg, const IntReg &val)
{
- return reg;
+ intRegFile.setReg(intReg, val);
}
- void copyRegs(ThreadContext *src, ThreadContext *dest);
+ void serialize(EventManager *em, std::ostream &os);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section);
+};
+
+static inline int
+flattenIntIndex(ThreadContext * tc, int reg)
+{
+ return reg;
+}
+
+static inline int
+flattenFloatIndex(ThreadContext * tc, int reg)
+{
+ return reg;
+}
+
+void copyRegs(ThreadContext *src, ThreadContext *dest);
+
+void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
- void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_REGFILE_HH__
diff --git a/src/arch/alpha/remote_gdb.cc b/src/arch/alpha/remote_gdb.cc
index ea5db36f4..c47293b98 100644
--- a/src/arch/alpha/remote_gdb.cc
+++ b/src/arch/alpha/remote_gdb.cc
@@ -30,7 +30,7 @@
/*
* Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -38,8 +38,8 @@
*
* 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.
+ * 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
@@ -51,8 +51,8 @@
* 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.
+ * 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.
@@ -69,7 +69,7 @@
* 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
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
*/
/*-
@@ -89,8 +89,8 @@
* 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.
+ * 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.
@@ -117,9 +117,9 @@
*/
#include <sys/signal.h>
+#include <unistd.h>
#include <string>
-#include <unistd.h>
#include "config/full_system.hh"
#if FULL_SYSTEM
@@ -140,19 +140,17 @@
#include "sim/system.hh"
using namespace std;
-using namespace TheISA;
+using namespace AlphaISA;
-RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
- : BaseRemoteGDB(_system, c, KGDB_NUMREGS)
+RemoteGDB::RemoteGDB(System *_system, ThreadContext *tc)
+ : BaseRemoteGDB(_system, tc, KGDB_NUMREGS)
{
memset(gdbregs.regs, 0, gdbregs.bytes());
}
-///////////////////////////////////////////////////////////
-// RemoteGDB::acc
-//
-// Determine if the mapping at va..(va+len) is valid.
-//
+/*
+ * Determine if the mapping at va..(va+len) is valid.
+ */
bool
RemoteGDB::acc(Addr va, size_t len)
{
@@ -161,12 +159,12 @@ RemoteGDB::acc(Addr va, size_t len)
#else
Addr last_va;
- va = TheISA::TruncPage(va);
- last_va = TheISA::RoundPage(va + len);
+ va = TruncPage(va);
+ last_va = RoundPage(va + len);
do {
- if (TheISA::IsK0Seg(va)) {
- if (va < (TheISA::K0SegBase + pmem->size())) {
+ if (IsK0Seg(va)) {
+ if (va < (K0SegBase + pmem->size())) {
DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= "
"%#x < K0SEG + size\n", va);
return true;
@@ -177,23 +175,25 @@ RemoteGDB::acc(Addr va, size_t len)
}
}
- /**
- * 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.
- */
+ /**
+ * 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)
+ if (PcPAL(va) || va < 0x10000)
return true;
- Addr ptbr = context->readMiscRegNoEffect(AlphaISA::IPR_PALtemp20);
- TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va);
+ Addr ptbr = context->readMiscRegNoEffect(IPR_PALtemp20);
+ PageTableEntry pte =
+ kernel_pte_lookup(context->getPhysPort(), ptbr, va);
if (!pte.valid()) {
DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va);
return false;
}
- va += TheISA::PageBytes;
+ va += PageBytes;
} while (va < last_va);
DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va);
@@ -201,11 +201,10 @@ RemoteGDB::acc(Addr va, size_t len)
#endif
}
-///////////////////////////////////////////////////////////
-// RemoteGDB::getregs
-//
-// Translate the kernel debugger register format into
-// the GDB register format.
+/*
+ * Translate the kernel debugger register format into the GDB register
+ * format.
+ */
void
RemoteGDB::getregs()
{
@@ -214,45 +213,43 @@ RemoteGDB::getregs()
gdbregs.regs[KGDB_REG_PC] = context->readPC();
// @todo: Currently this is very Alpha specific.
- if (AlphaISA::PcPAL(gdbregs.regs[KGDB_REG_PC])) {
- for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
- gdbregs.regs[i] = context->readIntReg(AlphaISA::reg_redir[i]);
+ if (PcPAL(gdbregs.regs[KGDB_REG_PC])) {
+ for (int i = 0; i < NumIntArchRegs; ++i) {
+ gdbregs.regs[i] = context->readIntReg(reg_redir[i]);
}
} else {
- for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ for (int i = 0; i < NumIntArchRegs; ++i) {
gdbregs.regs[i] = context->readIntReg(i);
}
}
#ifdef KGDB_FP_REGS
- for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ for (int i = 0; i < NumFloatArchRegs; ++i) {
gdbregs.regs[i + KGDB_REG_F0] = context->readFloatRegBits(i);
}
#endif
}
-///////////////////////////////////////////////////////////
-// RemoteGDB::setregs
-//
-// Translate the GDB register format into the kernel
-// debugger register format.
-//
+/*
+ * 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.regs[KGDB_REG_PC])) {
- for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
- context->setIntReg(AlphaISA::reg_redir[i], gdbregs.regs[i]);
+ if (PcPAL(gdbregs.regs[KGDB_REG_PC])) {
+ for (int i = 0; i < NumIntArchRegs; ++i) {
+ context->setIntReg(reg_redir[i], gdbregs.regs[i]);
}
} else {
- for (int i = 0; i < TheISA::NumIntArchRegs; ++i) {
+ for (int i = 0; i < NumIntArchRegs; ++i) {
context->setIntReg(i, gdbregs.regs[i]);
}
}
#ifdef KGDB_FP_REGS
- for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) {
+ for (int i = 0; i < NumFloatArchRegs; ++i) {
context->setFloatRegBits(i, gdbregs.regs[i + KGDB_REG_F0]);
}
#endif
diff --git a/src/arch/alpha/remote_gdb.hh b/src/arch/alpha/remote_gdb.hh
index 7bef183c3..43d0580d8 100644
--- a/src/arch/alpha/remote_gdb.hh
+++ b/src/arch/alpha/remote_gdb.hh
@@ -44,31 +44,29 @@ class System;
class ThreadContext;
class PhysicalMemory;
-namespace AlphaISA
-{
- class RemoteGDB : public BaseRemoteGDB
- {
- protected:
- // Machine memory
- bool write(Addr addr, size_t size, const char *data);
+namespace AlphaISA {
- public:
- RemoteGDB(System *system, ThreadContext *context);
+class RemoteGDB : public BaseRemoteGDB
+{
+ protected:
+ Addr notTakenBkpt;
+ Addr takenBkpt;
- bool acc(Addr addr, size_t len);
+ protected:
+ void getregs();
+ void setregs();
- protected:
- void getregs();
- void setregs();
+ void clearSingleStep();
+ void setSingleStep();
- void clearSingleStep();
- void setSingleStep();
+ // Machine memory
+ bool acc(Addr addr, size_t len);
+ bool write(Addr addr, size_t size, const char *data);
- protected:
+ public:
+ RemoteGDB(System *system, ThreadContext *context);
+};
- Addr notTakenBkpt;
- Addr takenBkpt;
- };
-}
+} // namespace AlphaISA
-#endif /* __ARCH_ALPHA_REMOTE_GDB_H__ */
+#endif // __ARCH_ALPHA_REMOTE_GDB_HH__
diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc
index c16498e72..1b5a9be34 100644
--- a/src/arch/alpha/stacktrace.cc
+++ b/src/arch/alpha/stacktrace.cc
@@ -41,330 +41,326 @@
using namespace std;
-namespace AlphaISA
+namespace AlphaISA {
+
+ProcessInfo::ProcessInfo(ThreadContext *_tc)
+ : tc(_tc)
{
- ProcessInfo::ProcessInfo(ThreadContext *_tc)
- : tc(_tc)
- {
- Addr addr = 0;
+ Addr addr = 0;
+ VirtualPort *vp = tc->getVirtPort();
+ SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
- VirtualPort *vp;
+ if (!symtab->findAddress("thread_info_size", addr))
+ panic("thread info not compiled into kernel\n");
+ thread_info_size = vp->readGtoH<int32_t>(addr);
- vp = tc->getVirtPort();
+ if (!symtab->findAddress("task_struct_size", addr))
+ panic("thread info not compiled into kernel\n");
+ task_struct_size = vp->readGtoH<int32_t>(addr);
- if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
- panic("thread info not compiled into kernel\n");
- thread_info_size = vp->readGtoH<int32_t>(addr);
+ if (!symtab->findAddress("thread_info_task", addr))
+ panic("thread info not compiled into kernel\n");
+ task_off = vp->readGtoH<int32_t>(addr);
- if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
- panic("thread info not compiled into kernel\n");
- task_struct_size = vp->readGtoH<int32_t>(addr);
+ if (!symtab->findAddress("task_struct_pid", addr))
+ panic("thread info not compiled into kernel\n");
+ pid_off = vp->readGtoH<int32_t>(addr);
- if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
- panic("thread info not compiled into kernel\n");
- task_off = vp->readGtoH<int32_t>(addr);
+ if (!symtab->findAddress("task_struct_comm", addr))
+ panic("thread info not compiled into kernel\n");
+ name_off = vp->readGtoH<int32_t>(addr);
+}
- if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
- panic("thread info not compiled into kernel\n");
- pid_off = vp->readGtoH<int32_t>(addr);
+Addr
+ProcessInfo::task(Addr ksp) const
+{
+ Addr base = ksp & ~0x3fff;
+ if (base == ULL(0xfffffc0000000000))
+ return 0;
- if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
- panic("thread info not compiled into kernel\n");
- name_off = vp->readGtoH<int32_t>(addr);
+ Addr tsk;
- tc->delVirtPort(vp);
- }
+ VirtualPort *vp;
- Addr
- ProcessInfo::task(Addr ksp) const
- {
- Addr base = ksp & ~0x3fff;
- if (base == ULL(0xfffffc0000000000))
- return 0;
+ vp = tc->getVirtPort();
+ tsk = vp->readGtoH<Addr>(base + task_off);
- Addr tsk;
+ return tsk;
+}
- VirtualPort *vp;
+int
+ProcessInfo::pid(Addr ksp) const
+{
+ Addr task = this->task(ksp);
+ if (!task)
+ return -1;
- vp = tc->getVirtPort();
- tsk = vp->readGtoH<Addr>(base + task_off);
- tc->delVirtPort(vp);
+ uint16_t pd;
- return tsk;
- }
+ VirtualPort *vp;
- int
- ProcessInfo::pid(Addr ksp) const
- {
- Addr task = this->task(ksp);
- if (!task)
- return -1;
+ vp = tc->getVirtPort();
+ pd = vp->readGtoH<uint16_t>(task + pid_off);
- uint16_t pd;
+ return pd;
+}
- VirtualPort *vp;
+string
+ProcessInfo::name(Addr ksp) const
+{
+ Addr task = this->task(ksp);
+ if (!task)
+ return "console";
- vp = tc->getVirtPort();
- pd = vp->readGtoH<uint16_t>(task + pid_off);
- tc->delVirtPort(vp);
+ char comm[256];
+ CopyStringOut(tc, comm, task + name_off, sizeof(comm));
+ if (!comm[0])
+ return "startup";
- return pd;
- }
+ return comm;
+}
- string
- ProcessInfo::name(Addr ksp) const
- {
- Addr task = this->task(ksp);
- if (!task)
- return "console";
+StackTrace::StackTrace()
+ : tc(0), stack(64)
+{
+}
- char comm[256];
- CopyStringOut(tc, comm, task + name_off, sizeof(comm));
- if (!comm[0])
- return "startup";
+StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
+ : tc(0), stack(64)
+{
+ trace(_tc, inst);
+}
- return comm;
- }
+StackTrace::~StackTrace()
+{
+}
- StackTrace::StackTrace()
- : tc(0), stack(64)
- {
- }
+void
+StackTrace::trace(ThreadContext *_tc, bool is_call)
+{
+ tc = _tc;
- StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
- : tc(0), stack(64)
- {
- trace(_tc, inst);
- }
+ System *sys = tc->getSystemPtr();
- StackTrace::~StackTrace()
- {
- }
+ bool usermode =
+ (tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0;
- void
- StackTrace::trace(ThreadContext *_tc, bool is_call)
- {
- tc = _tc;
+ Addr pc = tc->readNextPC();
+ bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd;
- bool usermode = (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
+ if (usermode) {
+ stack.push_back(user);
+ return;
+ }
- Addr pc = tc->readNextPC();
- bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
- pc <= tc->getSystemPtr()->kernelEnd;
+ if (!kernel) {
+ stack.push_back(console);
+ return;
+ }
- if (usermode) {
- stack.push_back(user);
- return;
- }
+ SymbolTable *symtab = sys->kernelSymtab;
+ Addr ksp = tc->readIntReg(StackPointerReg);
+ Addr bottom = ksp & ~0x3fff;
- if (!kernel) {
- stack.push_back(console);
- return;
- }
+ if (is_call) {
+ Addr addr;
+ if (!symtab->findNearestAddr(pc, addr))
+ panic("could not find address %#x", pc);
+
+ stack.push_back(addr);
+ pc = tc->readPC();
+ }
- SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
- Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
- Addr bottom = ksp & ~0x3fff;
+ while (ksp > bottom) {
Addr addr;
+ if (!symtab->findNearestAddr(pc, addr))
+ panic("could not find symbol for pc=%#x", pc);
+ assert(pc >= addr && "symbol botch: callpc < func");
- if (is_call) {
- if (!symtab->findNearestAddr(pc, addr))
- panic("could not find address %#x", pc);
+ stack.push_back(addr);
- stack.push_back(addr);
- pc = tc->readPC();
- }
+ if (isEntry(addr))
+ return;
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))
+ if (decodePrologue(ksp, pc, addr, size, ra)) {
+ if (!ra)
return;
- if (decodePrologue(ksp, pc, addr, size, ra)) {
- if (!ra)
- return;
-
- if (size <= 0) {
- stack.push_back(unknown);
- return;
- }
-
- pc = ra;
- ksp += size;
- } else {
+ if (size <= 0) {
stack.push_back(unknown);
return;
}
- bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
- pc <= tc->getSystemPtr()->kernelEnd;
- if (!kernel)
- return;
-
- if (stack.size() >= 1000)
- panic("unwinding too far");
+ pc = ra;
+ ksp += size;
+ } else {
+ stack.push_back(unknown);
+ return;
}
- panic("unwinding too far");
+ bool kernel = sys->kernelStart <= pc && pc <= sys->kernelEnd;
+ if (!kernel)
+ return;
+
+ if (stack.size() >= 1000)
+ panic("unwinding too far");
}
- bool
- StackTrace::isEntry(Addr addr)
- {
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp12))
- return true;
+ panic("unwinding too far");
+}
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp7))
- return true;
+bool
+StackTrace::isEntry(Addr addr)
+{
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp12))
+ return true;
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp11))
- return true;
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp7))
+ return true;
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp21))
- return true;
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp11))
+ return true;
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp9))
- return true;
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp21))
+ return true;
- if (addr == tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp2))
- return true;
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp9))
+ return true;
- return false;
- }
+ if (addr == tc->readMiscRegNoEffect(IPR_PALtemp2))
+ return true;
- 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 false;
+}
- return true;
- }
+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;
- bool
- StackTrace::decodeSave(MachInst inst, int &reg, 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;
+}
- return true;
+bool
+StackTrace::decodeSave(MachInst inst, int &reg, 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;
}
- /*
- * 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(tc, (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(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
- if (!ra) {
- // panic("no return address value pc=%#x\n", pc);
- 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(tc, (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(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
+ if (!ra) {
+ // panic("no return address value pc=%#x\n", pc);
+ return false;
}
}
}
-
- return true;
}
+ return true;
+}
+
#if TRACING_ON
- void
- StackTrace::dump()
- {
- StringWrap name(tc->getCpuPtr()->name());
- SymbolTable *symtab = tc->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);
- }
+void
+StackTrace::dump()
+{
+ StringWrap name(tc->getCpuPtr()->name());
+ SymbolTable *symtab = tc->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
}
+#endif
+
+} // namespace AlphaISA
diff --git a/src/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh
index 834abbc2f..db42c4399 100644
--- a/src/arch/alpha/stacktrace.hh
+++ b/src/arch/alpha/stacktrace.hh
@@ -36,90 +36,90 @@
class ThreadContext;
-namespace AlphaISA
-{
- class StackTrace;
+namespace AlphaISA {
- class ProcessInfo
- {
- private:
- ThreadContext *tc;
+class StackTrace;
+
+class ProcessInfo
+{
+ private:
+ ThreadContext *tc;
- int thread_info_size;
- int task_struct_size;
- int task_off;
- int pid_off;
- int name_off;
+ int thread_info_size;
+ int task_struct_size;
+ int task_off;
+ int pid_off;
+ int name_off;
- public:
- ProcessInfo(ThreadContext *_tc);
+ public:
+ ProcessInfo(ThreadContext *_tc);
- Addr task(Addr ksp) const;
- int pid(Addr ksp) const;
- std::string name(Addr ksp) const;
- };
+ Addr task(Addr ksp) const;
+ int pid(Addr ksp) const;
+ std::string name(Addr ksp) const;
+};
- class StackTrace
- {
- protected:
- typedef TheISA::MachInst MachInst;
- private:
- ThreadContext *tc;
- std::vector<Addr> stack;
+class StackTrace
+{
+ private:
+ ThreadContext *tc;
+ std::vector<Addr> stack;
- private:
- bool isEntry(Addr addr);
- bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra);
- bool decodeSave(MachInst inst, int &reg, int &disp);
- bool decodeStack(MachInst inst, int &disp);
+ private:
+ bool isEntry(Addr addr);
+ bool decodePrologue(Addr sp, Addr callpc, Addr func, int &size, Addr &ra);
+ bool decodeSave(MachInst inst, int &reg, int &disp);
+ bool decodeStack(MachInst inst, int &disp);
- void trace(ThreadContext *tc, bool is_call);
+ void trace(ThreadContext *tc, bool is_call);
- public:
- StackTrace();
- StackTrace(ThreadContext *tc, StaticInstPtr inst);
- ~StackTrace();
+ public:
+ StackTrace();
+ StackTrace(ThreadContext *tc, StaticInstPtr inst);
+ ~StackTrace();
- void clear()
- {
- tc = 0;
- stack.clear();
- }
+ void
+ clear()
+ {
+ tc = 0;
+ stack.clear();
+ }
- bool valid() const { return tc != NULL; }
- bool trace(ThreadContext *tc, StaticInstPtr inst);
+ bool valid() const { return tc != NULL; }
+ bool trace(ThreadContext *tc, StaticInstPtr inst);
- public:
- const std::vector<Addr> &getstack() const { return stack; }
+ public:
+ const std::vector<Addr> &getstack() const { return stack; }
- static const int user = 1;
- static const int console = 2;
- static const int unknown = 3;
+ static const int user = 1;
+ static const int console = 2;
+ static const int unknown = 3;
#if TRACING_ON
- private:
- void dump();
+ private:
+ void dump();
- public:
- void dprintf() { if (DTRACE(Stack)) dump(); }
+ public:
+ void dprintf() { if (DTRACE(Stack)) dump(); }
#else
- public:
- void dprintf() {}
+ public:
+ void dprintf() {}
#endif
- };
+};
- inline bool
- StackTrace::trace(ThreadContext *tc, StaticInstPtr inst)
- {
- if (!inst->isCall() && !inst->isReturn())
- return false;
+inline bool
+StackTrace::trace(ThreadContext *tc, StaticInstPtr inst)
+{
+ if (!inst->isCall() && !inst->isReturn())
+ return false;
- if (valid())
- clear();
+ if (valid())
+ clear();
- trace(tc, !inst->isReturn());
- return true;
- }
+ trace(tc, !inst->isReturn());
+ return true;
}
+} // namespace AlphaISA
+
#endif // __ARCH_ALPHA_STACKTRACE_HH__
diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc
index 2af62ceea..72d918870 100644
--- a/src/arch/alpha/system.cc
+++ b/src/arch/alpha/system.cc
@@ -42,8 +42,7 @@
#include "params/AlphaSystem.hh"
#include "sim/byteswap.hh"
-
-using namespace LittleEndianGuest;
+using namespace AlphaISA;
AlphaSystem::AlphaSystem(Params *p)
: System(p)
@@ -67,8 +66,8 @@ AlphaSystem::AlphaSystem(Params *p)
// Load program sections into memory
- pal->loadSections(&functionalPort, AlphaISA::LoadAddrMask);
- console->loadSections(&functionalPort, AlphaISA::LoadAddrMask);
+ pal->loadSections(&functionalPort, LoadAddrMask);
+ console->loadSections(&functionalPort, LoadAddrMask);
// load symbols
if (!console->loadGlobalSymbols(consoleSymtab))
@@ -117,7 +116,6 @@ AlphaSystem::AlphaSystem(Params *p)
virtPort.write(addr+0x58, data);
} else
panic("could not find hwrpb\n");
-
}
AlphaSystem::~AlphaSystem()
@@ -142,9 +140,9 @@ AlphaSystem::~AlphaSystem()
* 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
+ * 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
@@ -172,11 +170,11 @@ AlphaSystem::fixFuncEventAddr(Addr addr)
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));
+ uint32_t i2 = virtPort.read<uint32_t>(addr + sizeof(MachInst));
if ((i1 & inst_mask) == gp_ldah_pattern &&
(i2 & inst_mask) == gp_lda_pattern) {
- Addr new_addr = addr + 2* sizeof(AlphaISA::MachInst);
+ Addr new_addr = addr + 2 * sizeof(MachInst);
DPRINTF(Loader, "fixFuncEventAddr: %p -> %p", addr, new_addr);
return new_addr;
} else {
@@ -184,15 +182,15 @@ AlphaSystem::fixFuncEventAddr(Addr addr)
}
}
-
void
AlphaSystem::setAlphaAccess(Addr access)
{
Addr addr = 0;
if (consoleSymtab->findAddress("m5AlphaAccess", addr)) {
- virtPort.write(addr, htog(EV5::Phys2K0Seg(access)));
- } else
+ virtPort.write(addr, htog(Phys2K0Seg(access)));
+ } else {
panic("could not find m5AlphaAccess\n");
+ }
}
void
@@ -203,7 +201,6 @@ AlphaSystem::serialize(std::ostream &os)
palSymtab->serialize("pal_symtab", os);
}
-
void
AlphaSystem::unserialize(Checkpoint *cp, const std::string &section)
{
diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh
index a934550b7..da42ab263 100644
--- a/src/arch/alpha/system.hh
+++ b/src/arch/alpha/system.hh
@@ -49,10 +49,10 @@ class AlphaSystem : public System
AlphaSystem(Params *p);
~AlphaSystem();
-/**
- * Serialization stuff
- */
public:
+ /**
+ * Serialization stuff
+ */
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
@@ -77,26 +77,28 @@ class AlphaSystem : public System
/** 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 *addPalFuncEvent(const char *lbl)
+ T *
+ addPalFuncEvent(const char *lbl)
{
return addFuncEvent<T>(palSymtab, lbl);
}
/** Add a function-based event to the console code. */
template <class T>
- T *addConsoleFuncEvent(const char *lbl)
+ T *
+ addConsoleFuncEvent(const char *lbl)
{
return addFuncEvent<T>(consoleSymtab, lbl);
}
virtual Addr fixFuncEventAddr(Addr addr);
-
};
-#endif
+#endif // __ARCH_ALPHA_SYSTEM_HH__
diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc
index 77bf5e285..2b0afacfe 100644
--- a/src/arch/alpha/tlb.cc
+++ b/src/arch/alpha/tlb.cc
@@ -43,19 +43,20 @@
#include "cpu/thread_context.hh"
using namespace std;
-using namespace EV5;
namespace AlphaISA {
+
///////////////////////////////////////////////////////////////////////
//
// Alpha TLB
//
+
#ifdef DEBUG
bool uncacheBit39 = false;
bool uncacheBit40 = false;
#endif
-#define MODE2MASK(X) (1 << (X))
+#define MODE2MASK(X) (1 << (X))
TLB::TLB(const Params *p)
: BaseTLB(p), size(p->size), nlu(0)
@@ -114,20 +115,20 @@ TLB::lookup(Addr vpn, uint8_t asn)
return retval;
}
-
Fault
-TLB::checkCacheability(RequestPtr &req)
+TLB::checkCacheability(RequestPtr &req, bool itb)
{
-// 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.
- */
+ // 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
@@ -141,13 +142,20 @@ TLB::checkCacheability(RequestPtr &req)
return new UnimpFault("IPR memory space not implemented!");
} else {
// mark request as uncacheable
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
#if !ALPHA_TLASER
- // Clear bits 42:35 of the physical address (10-2 in Tsunami manual)
+ // Clear bits 42:35 of the physical address (10-2 in
+ // Tsunami manual)
req->setPaddr(req->getPaddr() & PAddrUncachedMask);
#endif
}
+ // We shouldn't be able to read from an uncachable address in Alpha as
+ // we don't have a ROM and we don't want to try to fetch from a device
+ // register as we destroy any data that is clear-on-read.
+ if (req->isUncacheable() && itb)
+ return new UnimpFault("CPU trying to fetch from uncached I/O");
+
}
return NoFault;
}
@@ -216,7 +224,8 @@ TLB::flushProcesses()
++i;
if (!entry->asma) {
- DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index, entry->tag, entry->ppn);
+ DPRINTF(TLB, "flush @%d: %#x -> %#x\n", index,
+ entry->tag, entry->ppn);
entry->valid = false;
lookupTable.erase(cur);
}
@@ -279,7 +288,6 @@ TLB::unserialize(Checkpoint *cp, const string &section)
}
}
-
///////////////////////////////////////////////////////////////////////
//
// Alpha ITB
@@ -308,13 +316,12 @@ ITB::regStats()
accesses = hits + misses;
}
-
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
+ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
{
//If this is a pal pc, then set PHYSICAL
- if(FULL_SYSTEM && PcPAL(req->getPC()))
- req->setFlags(req->getFlags() | PHYSICAL);
+ if (FULL_SYSTEM && PcPAL(req->getPC()))
+ req->setFlags(Request::PHYSICAL);
if (PcPAL(req->getPC())) {
// strip off PAL PC marker (lsb is 1)
@@ -323,7 +330,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
return NoFault;
}
- if (req->getFlags() & PHYSICAL) {
+ if (req->getFlags() & Request::PHYSICAL) {
req->setPaddr(req->getVaddr());
} else {
// verify that this is a good virtual address
@@ -390,15 +397,23 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
if (req->getPaddr() & ~PAddrImplMask)
return genMachineCheckFault();
- return checkCacheability(req);
+ return checkCacheability(req, true);
}
+void
+ITB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc), req, tc, false);
+}
+
///////////////////////////////////////////////////////////////////////
//
// Alpha DTB
//
- DTB::DTB(const Params *p)
+DTB::DTB(const Params *p)
: TLB(p)
{}
@@ -472,14 +487,13 @@ DTB::regStats()
}
Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
{
Addr pc = tc->readPC();
mode_type mode =
(mode_type)DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM));
-
/**
* Check for alignment faults
*/
@@ -491,13 +505,13 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
}
if (PcPAL(pc)) {
- mode = (req->getFlags() & ALTMODE) ?
+ mode = (req->getFlags() & Request::ALTMODE) ?
(mode_type)ALT_MODE_AM(
tc->readMiscRegNoEffect(IPR_ALT_MODE))
: mode_kernel;
}
- if (req->getFlags() & PHYSICAL) {
+ if (req->getFlags() & Request::PHYSICAL) {
req->setPaddr(req->getVaddr());
} else {
// verify that this is a good virtual address
@@ -517,14 +531,15 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
if (VAddrSpaceEV6(req->getVaddr()) == 0x7e)
#endif
{
-
// only valid in kernel mode
if (DTB_CM_CM(tc->readMiscRegNoEffect(IPR_DTB_CM)) !=
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);
+
+ return new DtbAcvFault(req->getVaddr(), req->getFlags(),
+ flags);
}
req->setPaddr(req->getVaddr() & PAddrImplMask);
@@ -553,7 +568,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
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) ?
+ return (req->getFlags() & Request::VPTE) ?
(Fault)(new PDtbMissFault(req->getVaddr(), req->getFlags(),
flags)) :
(Fault)(new NDtbMissFault(req->getVaddr(), req->getFlags(),
@@ -570,25 +585,28 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
uint64_t flags = MM_STAT_WR_MASK |
MM_STAT_ACV_MASK |
(entry->fonw ? MM_STAT_FONW_MASK : 0);
- return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ return new DtbPageFault(req->getVaddr(), req->getFlags(),
+ flags);
}
if (entry->fonw) {
write_acv++;
- uint64_t flags = MM_STAT_WR_MASK |
- MM_STAT_FONW_MASK;
- return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ uint64_t flags = MM_STAT_WR_MASK | MM_STAT_FONW_MASK;
+ return new DtbPageFault(req->getVaddr(), req->getFlags(),
+ flags);
}
} else {
if (!(entry->xre & MODE2MASK(mode))) {
read_acv++;
uint64_t flags = MM_STAT_ACV_MASK |
(entry->fonr ? MM_STAT_FONR_MASK : 0);
- return new DtbAcvFault(req->getVaddr(), req->getFlags(), flags);
+ return new DtbAcvFault(req->getVaddr(), req->getFlags(),
+ flags);
}
if (entry->fonr) {
read_acv++;
uint64_t flags = MM_STAT_FONR_MASK;
- return new DtbPageFault(req->getVaddr(), req->getFlags(), flags);
+ return new DtbPageFault(req->getVaddr(), req->getFlags(),
+ flags);
}
}
}
@@ -606,6 +624,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
return checkCacheability(req);
}
+void
+DTB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc, write), req, tc, write);
+}
+
TlbEntry &
TLB::index(bool advance)
{
diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh
index e61ae5c6d..643889534 100644
--- a/src/arch/alpha/tlb.hh
+++ b/src/arch/alpha/tlb.hh
@@ -29,8 +29,8 @@
* Steve Reinhardt
*/
-#ifndef __ALPHA_MEMORY_HH__
-#define __ALPHA_MEMORY_HH__
+#ifndef __ARCH_ALPHA_TLB_HH__
+#define __ARCH_ALPHA_TLB_HH__
#include <map>
@@ -48,110 +48,120 @@
class ThreadContext;
-namespace AlphaISA
+namespace AlphaISA {
+
+class TlbEntry;
+
+class TLB : public BaseTLB
{
- class TlbEntry;
+ protected:
+ typedef std::multimap<Addr, int> PageTable;
+ PageTable lookupTable; // Quick lookup into page table
+
+ TlbEntry *table; // the Page Table
+ int size; // TLB Size
+ int nlu; // not last used entry (for replacement)
+
+ void nextnlu() { if (++nlu >= size) nlu = 0; }
+ TlbEntry *lookup(Addr vpn, uint8_t asn);
+
+ public:
+ typedef AlphaTLBParams Params;
+ TLB(const Params *p);
+ virtual ~TLB();
+
+ int getsize() const { return size; }
- class TLB : public BaseTLB
+ TlbEntry &index(bool advance = true);
+ void insert(Addr vaddr, TlbEntry &entry);
+
+ void flushAll();
+ void flushProcesses();
+ void flushAddr(Addr addr, uint8_t asn);
+
+ void
+ demapPage(Addr vaddr, uint64_t asn)
{
- protected:
- typedef std::multimap<Addr, int> PageTable;
- PageTable lookupTable; // Quick lookup into page table
-
- TlbEntry *table; // the Page Table
- int size; // TLB Size
- int nlu; // not last used entry (for replacement)
-
- void nextnlu() { if (++nlu >= size) nlu = 0; }
- TlbEntry *lookup(Addr vpn, uint8_t asn);
-
- public:
- typedef AlphaTLBParams Params;
- TLB(const Params *p);
- virtual ~TLB();
-
- int getsize() const { return size; }
-
- TlbEntry &index(bool advance = true);
- void insert(Addr vaddr, TlbEntry &entry);
-
- void flushAll();
- void flushProcesses();
- void flushAddr(Addr addr, uint8_t asn);
-
- void demapPage(Addr vaddr, uint64_t asn)
- {
- assert(asn < (1 << 8));
- flushAddr(vaddr, 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 &section);
-
- // Most recently used page table entries
- TlbEntry *EntryCache[3];
- inline void flushCache()
- {
- memset(EntryCache, 0, 3 * sizeof(TlbEntry*));
- }
-
- inline TlbEntry* updateCache(TlbEntry *entry) {
- EntryCache[2] = EntryCache[1];
- EntryCache[1] = EntryCache[0];
- EntryCache[0] = entry;
- return entry;
- }
- };
-
- class ITB : public TLB
+ assert(asn < (1 << 8));
+ flushAddr(vaddr, asn);
+ }
+
+ // static helper functions... really EV5 VM traits
+ static bool
+ validVirtualAddress(Addr vaddr)
{
- protected:
- mutable Stats::Scalar<> hits;
- mutable Stats::Scalar<> misses;
- mutable Stats::Scalar<> acv;
- mutable Stats::Formula accesses;
+ // unimplemented bits must be all 0 or all 1
+ Addr unimplBits = vaddr & VAddrUnImplMask;
+ return unimplBits == 0 || unimplBits == VAddrUnImplMask;
+ }
- public:
- typedef AlphaITBParams Params;
- ITB(const Params *p);
- virtual void regStats();
+ static Fault checkCacheability(RequestPtr &req, bool itb = false);
- Fault translate(RequestPtr &req, ThreadContext *tc);
- };
+ // Checkpointing
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
- class DTB : public TLB
+ // Most recently used page table entries
+ TlbEntry *EntryCache[3];
+ inline void
+ flushCache()
{
- 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:
- typedef AlphaDTBParams Params;
- DTB(const Params *p);
- virtual void regStats();
-
- Fault translate(RequestPtr &req, ThreadContext *tc, bool write);
- };
-}
-
-#endif // __ALPHA_MEMORY_HH__
+ memset(EntryCache, 0, 3 * sizeof(TlbEntry*));
+ }
+
+ inline TlbEntry *
+ updateCache(TlbEntry *entry) {
+ EntryCache[2] = EntryCache[1];
+ EntryCache[1] = EntryCache[0];
+ EntryCache[0] = entry;
+ return entry;
+ }
+};
+
+class ITB : public TLB
+{
+ protected:
+ mutable Stats::Scalar hits;
+ mutable Stats::Scalar misses;
+ mutable Stats::Scalar acv;
+ mutable Stats::Formula accesses;
+
+ public:
+ typedef AlphaITBParams Params;
+ ITB(const Params *p);
+ virtual void regStats();
+
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation);
+};
+
+class DTB : public TLB
+{
+ 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:
+ typedef AlphaDTBParams Params;
+ DTB(const Params *p);
+ virtual void regStats();
+
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write);
+};
+
+} // namespace AlphaISA
+
+#endif // __ARCH_ALPHA_TLB_HH__
diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc
index 6823d820a..8fa3cdeda 100644
--- a/src/arch/alpha/tru64/process.cc
+++ b/src/arch/alpha/tru64/process.cc
@@ -32,10 +32,8 @@
#include "arch/alpha/tru64/tru64.hh"
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/tru64/process.hh"
-
#include "cpu/thread_context.hh"
#include "kern/tru64/tru64.hh"
-
#include "sim/process.hh"
#include "sim/syscall_emul.hh"
@@ -47,7 +45,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<AlphaTru64::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<AlphaTru64::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "OSF1");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -64,34 +62,35 @@ static SyscallReturn
getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
- unsigned nbytes = tc->getSyscallArg(2);
+ unsigned op = process->getSyscallArg(tc, 0);
+ unsigned nbytes = process->getSyscallArg(tc, 2);
switch (op) {
case AlphaTru64::GSI_MAX_CPU: {
- TypedBufferArg<uint32_t> max_cpu(tc->getSyscallArg(1));
+ TypedBufferArg<uint32_t> max_cpu(process->getSyscallArg(tc, 1));
*max_cpu = htog((uint32_t)process->numCpus());
max_cpu.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_CPUS_IN_BOX: {
- TypedBufferArg<uint32_t> cpus_in_box(tc->getSyscallArg(1));
+ TypedBufferArg<uint32_t> cpus_in_box(process->getSyscallArg(tc, 1));
*cpus_in_box = htog((uint32_t)process->numCpus());
cpus_in_box.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_PHYSMEM: {
- TypedBufferArg<uint64_t> physmem(tc->getSyscallArg(1));
- *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB
+ TypedBufferArg<uint64_t> physmem(process->getSyscallArg(tc, 1));
+ *physmem = htog((uint64_t)1024 * 1024); // physical memory in KB
physmem.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_CPU_INFO: {
- TypedBufferArg<AlphaTru64::cpu_info> infop(tc->getSyscallArg(1));
+ TypedBufferArg<AlphaTru64::cpu_info>
+ infop(process->getSyscallArg(tc, 1));
infop->current_cpu = htog(0);
infop->cpus_in_box = htog(process->numCpus());
@@ -108,14 +107,14 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
}
case AlphaTru64::GSI_PROC_TYPE: {
- TypedBufferArg<uint64_t> proc_type(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> proc_type(process->getSyscallArg(tc, 1));
*proc_type = htog((uint64_t)11);
proc_type.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_PLATFORM_NAME: {
- BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+ BufferArg bufArg(process->getSyscallArg(tc, 1), nbytes);
strncpy((char *)bufArg.bufferPtr(),
"COMPAQ Professional Workstation XP1000",
nbytes);
@@ -124,7 +123,7 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
}
case AlphaTru64::GSI_CLK_TCK: {
- TypedBufferArg<uint64_t> clk_hz(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> clk_hz(process->getSyscallArg(tc, 1));
*clk_hz = htog((uint64_t)1024);
clk_hz.copyOut(tc->getMemPort());
return 1;
@@ -143,12 +142,12 @@ static SyscallReturn
setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
+ unsigned op = process->getSyscallArg(tc, 0);
switch (op) {
case AlphaTru64::SSI_IEEE_FP_CONTROL:
warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n",
- tc->getSyscallArg(1));
+ process->getSyscallArg(tc, 1));
break;
default:
@@ -159,26 +158,24 @@ setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
return 0;
}
-
/// Target table() handler.
-static
-SyscallReturn tableFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
- ThreadContext *tc)
+static SyscallReturn
+tableFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
+ ThreadContext *tc)
{
using namespace std;
- using namespace TheISA;
- int id = tc->getSyscallArg(0); // table ID
- int index = tc->getSyscallArg(1); // index into table
+ int id = process->getSyscallArg(tc, 0); // table ID
+ int index = process->getSyscallArg(tc, 1); // index into table
// arg 2 is buffer pointer; type depends on table ID
- int nel = tc->getSyscallArg(3); // number of elements
- int lel = tc->getSyscallArg(4); // expected element size
+ int nel = process->getSyscallArg(tc, 3); // number of elements
+ int lel = process->getSyscallArg(tc, 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(tc->getSyscallArg(2));
+ TypedBufferArg<Tru64::tbl_sysinfo> elp(process->getSyscallArg(tc, 2));
const int clk_hz = one_million;
elp->si_user = htog(curTick / (Clock::Frequency / clk_hz));
@@ -219,7 +216,7 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", unimplementedFunc),
/* 16 */ SyscallDesc("chown", unimplementedFunc),
- /* 17 */ SyscallDesc("obreak", obreakFunc),
+ /* 17 */ SyscallDesc("obreak", brkFunc),
/* 18 */ SyscallDesc("pre_F64_getfsstat", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidPseudoFunc),
@@ -260,9 +257,9 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = {
/* 55 */ SyscallDesc("reboot", unimplementedFunc),
/* 56 */ SyscallDesc("revoke", unimplementedFunc),
/* 57 */ SyscallDesc("symlink", unimplementedFunc),
- /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", readlinkFunc),
/* 59 */ SyscallDesc("execve", unimplementedFunc),
- /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", umaskFunc),
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
/* 62 */ SyscallDesc("old_fstat", unimplementedFunc),
/* 63 */ SyscallDesc("getpgrp", unimplementedFunc),
@@ -339,7 +336,7 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = {
/* 133 */ SyscallDesc("sendto", unimplementedFunc),
/* 134 */ SyscallDesc("shutdown", unimplementedFunc),
/* 135 */ SyscallDesc("socketpair", unimplementedFunc),
- /* 136 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 136 */ SyscallDesc("mkdir", mkdirFunc),
/* 137 */ SyscallDesc("rmdir", unimplementedFunc),
/* 138 */ SyscallDesc("utimes", unimplementedFunc),
/* 139 */ SyscallDesc("obsolete 4.2 sigreturn", unimplementedFunc),
@@ -472,15 +469,14 @@ SyscallDesc AlphaTru64Process::syscallDescs[] = {
/* 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),
+ /* 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),
@@ -507,7 +503,8 @@ SyscallDesc AlphaTru64Process::machSyscallDescs[] = {
/* 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),
+ /* 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),
@@ -572,9 +569,8 @@ AlphaTru64Process::getDesc(int callnum)
return &syscallDescs[callnum];
}
-
-AlphaTru64Process::AlphaTru64Process(LiveProcessParams * params,
- ObjectFile *objFile)
+AlphaTru64Process::AlphaTru64Process(LiveProcessParams *params,
+ ObjectFile *objFile)
: AlphaLiveProcess(params, objFile),
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
index 16bc499c6..6d7a76555 100644
--- a/src/arch/alpha/tru64/process.hh
+++ b/src/arch/alpha/tru64/process.hh
@@ -28,12 +28,13 @@
* Authors: Steve Reinhardt
*/
-#ifndef __ALPHA_TRU64_PROCESS_HH__
-#define __ALPHA_TRU64_PROCESS_HH__
+#ifndef __ARCH_ALPHA_TRU64_PROCESS_HH__
+#define __ARCH_ALPHA_TRU64_PROCESS_HH__
#include "arch/alpha/process.hh"
namespace AlphaISA {
+
/// A process with emulated Alpha Tru64 syscalls.
class AlphaTru64Process : public AlphaLiveProcess
{
@@ -51,9 +52,9 @@ class AlphaTru64Process : public AlphaLiveProcess
const int Num_Syscall_Descs;
const int Num_Mach_Syscall_Descs;
- virtual SyscallDesc* getDesc(int callnum);
+ virtual SyscallDesc *getDesc(int callnum);
};
} // namespace AlphaISA
-#endif // __ALPHA_TRU64_PROCESS_HH__
+#endif // __ARCH_ALPHA_TRU64_PROCESS_HH__
diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc
index 56b04846f..c72e975f0 100644
--- a/src/arch/alpha/tru64/tru64.cc
+++ b/src/arch/alpha/tru64/tru64.cc
@@ -33,34 +33,34 @@
// 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 },
+ { 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 },
+ { AlphaTru64::TGT_O_NONBLOCK, _O_NONBLOCK },
#endif
#ifdef _O_NOCTTY
- { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY },
+ { AlphaTru64::TGT_O_NOCTTY, _O_NOCTTY },
#endif
#ifdef _O_SYNC
- { AlphaTru64::TGT_O_SYNC, _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 },
+ { 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 },
+ { AlphaTru64::TGT_O_SYNC, O_SYNC },
#endif
#endif /* _MSC_VER */
};
diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh
index 90e5f12dc..4ba35fc50 100644
--- a/src/arch/alpha/tru64/tru64.hh
+++ b/src/arch/alpha/tru64/tru64.hh
@@ -28,14 +28,13 @@
* Authors: Korey Sewell
*/
-#ifndef __ALPHA_ALPHA_TRU64_HH
-#define __ALPHA_ALPHA_TRU64_HH
+#ifndef __ALPHA_ALPHA_TRU64_TRU64_HH__
+#define __ALPHA_ALPHA_TRU64_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.
@@ -46,21 +45,21 @@ class AlphaTru64 : public Tru64
//@{
/// 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
+ 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().
@@ -68,13 +67,13 @@ class AlphaTru64 : public Tru64
//@{
/// 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_PLATFORM_NAME = 103; //!< platform name 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 # CPUs on 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
//@}
//@{
@@ -124,6 +123,4 @@ class AlphaTru64 : public Tru64
};
};
-
-
-#endif
+#endif // __ALPHA_ALPHA_TRU64_TRU64_HH__
diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh
index f6648b776..7905114b8 100644
--- a/src/arch/alpha/types.hh
+++ b/src/arch/alpha/types.hh
@@ -32,47 +32,43 @@
#ifndef __ARCH_ALPHA_TYPES_HH__
#define __ARCH_ALPHA_TYPES_HH__
-#include <inttypes.h>
+#include "sim/host.hh"
-namespace AlphaISA
-{
-
- typedef uint32_t MachInst;
- typedef uint64_t ExtMachInst;
- typedef uint8_t RegIndex;
+namespace AlphaISA {
- typedef uint64_t IntReg;
- typedef uint64_t LargestRead;
+typedef uint32_t MachInst;
+typedef uint64_t ExtMachInst;
+typedef uint8_t RegIndex;
- // floating point register file entry type
- typedef double FloatReg;
- typedef uint64_t FloatRegBits;
+typedef uint64_t IntReg;
+typedef uint64_t LargestRead;
- // control register file contents
- typedef uint64_t MiscReg;
+// floating point register file entry type
+typedef double FloatReg;
+typedef uint64_t FloatRegBits;
- typedef union {
- IntReg intreg;
- FloatReg fpreg;
- MiscReg ctrlreg;
- } AnyReg;
+// control register file contents
+typedef uint64_t MiscReg;
- enum RegContextParam
- {
- CONTEXT_PALMODE
- };
+union AnyReg
+{
+ IntReg intreg;
+ FloatReg fpreg;
+ MiscReg ctrlreg;
+};
- typedef bool RegContextVal;
+enum annotes
+{
+ ANNOTE_NONE = 0,
+ // An impossible number for instruction annotations
+ ITOUCH_ANNOTE = 0xffffffff,
+};
- enum annotes {
- ANNOTE_NONE = 0,
- // An impossible number for instruction annotations
- ITOUCH_ANNOTE = 0xffffffff,
- };
+struct CoreSpecific
+{
+ int core_type;
+};
- struct CoreSpecific {
- int core_type;
- };
} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_TYPES_HH__
diff --git a/src/arch/alpha/utility.cc b/src/arch/alpha/utility.cc
index f1864203b..763da0d4f 100644
--- a/src/arch/alpha/utility.cc
+++ b/src/arch/alpha/utility.cc
@@ -36,28 +36,28 @@
#include "mem/vport.hh"
#endif
-namespace AlphaISA
-{
+namespace AlphaISA {
-uint64_t getArgument(ThreadContext *tc, int number, bool fp)
+uint64_t
+getArgument(ThreadContext *tc, int number, bool fp)
{
#if FULL_SYSTEM
+ const int NumArgumentRegs = 6;
if (number < NumArgumentRegs) {
if (fp)
- return tc->readFloatRegBits(ArgumentReg[number]);
+ return tc->readFloatRegBits(16 + number);
else
- return tc->readIntReg(ArgumentReg[number]);
+ return tc->readIntReg(16 + number);
} else {
Addr sp = tc->readIntReg(StackPointerReg);
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
uint64_t arg = vp->read<uint64_t>(sp +
(number-NumArgumentRegs) * sizeof(uint64_t));
- tc->delVirtPort(vp);
return arg;
}
#else
panic("getArgument() is Full system only\n");
- M5_DUMMY_RETURN
+ M5_DUMMY_RETURN;
#endif
}
diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh
index 11357bc44..76c6c5726 100644
--- a/src/arch/alpha/utility.hh
+++ b/src/arch/alpha/utility.hh
@@ -32,127 +32,137 @@
#ifndef __ARCH_ALPHA_UTILITY_HH__
#define __ARCH_ALPHA_UTILITY_HH__
-#include "config/full_system.hh"
#include "arch/alpha/types.hh"
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/regfile.hh"
#include "base/misc.hh"
+#include "config/full_system.hh"
#include "cpu/thread_context.hh"
-namespace AlphaISA
+namespace AlphaISA {
+
+uint64_t getArgument(ThreadContext *tc, int number, bool fp);
+
+inline bool
+inUserMode(ThreadContext *tc)
+{
+ return (tc->readMiscRegNoEffect(IPR_DTB_CM) & 0x18) != 0;
+}
+
+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;
+}
- uint64_t getArgument(ThreadContext *tc, int number, bool fp);
-
- static inline bool
- inUserMode(ThreadContext *tc)
- {
- return (tc->readMiscRegNoEffect(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
- }
-
- 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 &reg_file,
- int regnum);
-
- void restoreMachineReg(RegFile &regs, const AnyReg &reg,
- int regnum);
-
- /**
- * Function to insure ISA semantics about 0 registers.
- * @param tc The thread context.
- */
- template <class TC>
- void zeroRegisters(TC *tc);
-
- // Alpha IPR register accessors
- inline bool PcPAL(Addr addr) { return addr & 0x3; }
- inline void startupCPU(ThreadContext *tc, int cpuId) {
- tc->activate(0);
- }
-
- ////////////////////////////////////////////////////////////////////////
- //
- // 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 initIPRs(ThreadContext *tc, int cpuId);
+// 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 &reg_file, int regnum);
+void restoreMachineReg(RegFile &regs, const AnyReg &reg, int regnum);
+
+/**
+ * Function to insure ISA semantics about 0 registers.
+ * @param tc The thread context.
+ */
+template <class TC>
+void zeroRegisters(TC *tc);
+
+// Alpha IPR register accessors
+inline bool PcPAL(Addr addr) { return addr & 0x3; }
+inline void startupCPU(ThreadContext *tc, int cpuId) { tc->activate(0); }
+
+////////////////////////////////////////////////////////////////////////
+//
+// 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 initIPRs(ThreadContext *tc, int cpuId);
#if FULL_SYSTEM
- void initCPU(ThreadContext *tc, int cpuId);
-
- /**
- * Function to check for and process any interrupts.
- * @param tc The thread context.
- */
- template <class TC>
- void processInterrupts(TC *tc);
+void initCPU(ThreadContext *tc, int cpuId);
+
+/**
+ * Function to check for and process any interrupts.
+ * @param tc The thread context.
+ */
+template <class TC>
+void processInterrupts(TC *tc);
#endif
} // namespace AlphaISA
-#endif
+#endif // __ARCH_ALPHA_UTILITY_HH__
diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc
index 6ffbea181..4a043d8d1 100644
--- a/src/arch/alpha/vtophys.cc
+++ b/src/arch/alpha/vtophys.cc
@@ -40,27 +40,28 @@
#include "mem/vport.hh"
using namespace std;
-using namespace AlphaISA;
-AlphaISA::PageTableEntry
-AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr)
+namespace AlphaISA {
+
+PageTableEntry
+kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, VAddr vaddr)
{
Addr level1_pte = ptbr + vaddr.level1();
- AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte);
+ 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);
+ 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);
+ PageTableEntry level3 = mem->read<uint64_t>(level3_pte);
if (!level3.valid()) {
DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr);
return 0;
@@ -69,13 +70,13 @@ AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vadd
}
Addr
-AlphaISA::vtophys(Addr vaddr)
+vtophys(Addr vaddr)
{
Addr paddr = 0;
- if (AlphaISA::IsUSeg(vaddr))
+ if (IsUSeg(vaddr))
DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
- else if (AlphaISA::IsK0Seg(vaddr))
- paddr = AlphaISA::K0Seg2Phys(vaddr);
+ else if (IsK0Seg(vaddr))
+ paddr = K0Seg2Phys(vaddr);
else
panic("vtophys: ptbr is not set on virtual lookup");
@@ -85,22 +86,22 @@ AlphaISA::vtophys(Addr vaddr)
}
Addr
-AlphaISA::vtophys(ThreadContext *tc, Addr addr)
+vtophys(ThreadContext *tc, Addr addr)
{
- AlphaISA::VAddr vaddr = addr;
- Addr ptbr = tc->readMiscRegNoEffect(AlphaISA::IPR_PALtemp20);
+ VAddr vaddr = addr;
+ Addr ptbr = tc->readMiscRegNoEffect(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)) {
+ if (PcPAL(vaddr) && (vaddr < PalMax)) {
paddr = vaddr & ~ULL(1);
} else {
- if (AlphaISA::IsK0Seg(vaddr)) {
- paddr = AlphaISA::K0Seg2Phys(vaddr);
+ if (IsK0Seg(vaddr)) {
+ paddr = K0Seg2Phys(vaddr);
} else if (!ptbr) {
paddr = vaddr;
} else {
- AlphaISA::PageTableEntry pte =
+ PageTableEntry pte =
kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr);
if (pte.valid())
paddr = pte.paddr() | vaddr.offset();
@@ -113,3 +114,4 @@ AlphaISA::vtophys(ThreadContext *tc, Addr addr)
return paddr;
}
+} // namespace AlphaISA
diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh
index bd2ee8468..b13afd090 100644
--- a/src/arch/alpha/vtophys.hh
+++ b/src/arch/alpha/vtophys.hh
@@ -41,12 +41,13 @@ class FunctionalPort;
namespace AlphaISA {
- PageTableEntry
- kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr);
+PageTableEntry kernel_pte_lookup(FunctionalPort *mem, Addr ptbr,
+ VAddr vaddr);
- Addr vtophys(Addr vaddr);
- Addr vtophys(ThreadContext *tc, Addr vaddr);
+Addr vtophys(Addr vaddr);
+Addr vtophys(ThreadContext *tc, Addr vaddr);
+
+} // namespace AlphaISA
-};
#endif // __ARCH_ALPHA_VTOPHYS_H__
diff --git a/src/arch/arm/ArmTLB.py b/src/arch/arm/ArmTLB.py
index 21253edef..fa9faaddf 100644
--- a/src/arch/arm/ArmTLB.py
+++ b/src/arch/arm/ArmTLB.py
@@ -34,25 +34,21 @@ from m5.params import *
class ArmTLB(SimObject):
abstract = True
type = 'ArmTLB'
- cxx_namespace = 'ArmISA'
- cxx_class = 'TLB'
+ cxx_class = 'ArmISA::TLB'
size = Param.Int("TLB size")
class ArmDTB(ArmTLB):
type = 'ArmDTB'
- cxx_namespace = 'ArmISA'
- cxx_class = 'DTB'
+ cxx_class = 'ArmISA::DTB'
size = 64
class ArmITB(ArmTLB):
type = 'ArmITB'
- cxx_namespace = 'ArmISA'
- cxx_class = 'ITB'
+ cxx_class = 'ArmISA::ITB'
size = 64
class ArmUTB(ArmTLB):
type = 'ArmUTB'
- cxx_namespace = 'ArmISA'
- cxx_class = 'UTB'
+ cxx_class = 'ArmISA::UTB'
size = 64
diff --git a/src/arch/arm/isa_traits.hh b/src/arch/arm/isa_traits.hh
index 253114ad1..cf07699ce 100644
--- a/src/arch/arm/isa_traits.hh
+++ b/src/arch/arm/isa_traits.hh
@@ -131,9 +131,6 @@ namespace ArmISA
const int ZeroReg = NumIntArchRegs;
const int AddrReg = ZeroReg + 1; // Used to generate address for uops
- const int ArgumentReg[] = {0, 1, 2, 3};
- const int NumArgumentRegs = sizeof(ArgumentReg)/ sizeof(const int);
-
const int SyscallNumReg = ReturnValueReg;
const int SyscallPseudoReturnReg = ReturnValueReg;
const int SyscallSuccessReg = ReturnValueReg;
diff --git a/src/arch/arm/linux/process.cc b/src/arch/arm/linux/process.cc
index 6d3153063..46b2f9bee 100644
--- a/src/arch/arm/linux/process.cc
+++ b/src/arch/arm/linux/process.cc
@@ -49,7 +49,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -79,7 +79,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<ArmLinux>),
/* 16 */ SyscallDesc("lchown", chownFunc),
- /* 17 */ SyscallDesc("break", obreakFunc), //???
+ /* 17 */ SyscallDesc("break", brkFunc), //???
/* 18 */ SyscallDesc("unused#18", unimplementedFunc), //???
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -107,7 +107,7 @@ SyscallDesc ArmLinuxProcess::syscallDescs[] = {
/* 42 */ SyscallDesc("pipe", unimplementedFunc),
/* 43 */ SyscallDesc("times", unimplementedFunc),
/* 44 */ SyscallDesc("prof", unimplementedFunc),
- /* 45 */ SyscallDesc("brk", obreakFunc),
+ /* 45 */ SyscallDesc("brk", brkFunc),
/* 46 */ SyscallDesc("setgid", unimplementedFunc),
/* 47 */ SyscallDesc("getgid", getgidFunc),
/* 48 */ SyscallDesc("signal", ignoreFunc),
diff --git a/src/arch/arm/process.cc b/src/arch/arm/process.cc
index 00ba414ba..365d5b22c 100644
--- a/src/arch/arm/process.cc
+++ b/src/arch/arm/process.cc
@@ -43,8 +43,7 @@
using namespace std;
using namespace ArmISA;
-ArmLiveProcess::ArmLiveProcess(LiveProcessParams * params,
- ObjectFile *objFile)
+ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile)
: LiveProcess(params, objFile)
{
stack_base = 0xc0000000L;
@@ -147,12 +146,35 @@ ArmLiveProcess::argsInit(int intSize, int pageSize)
initVirtMem->writeBlob(0xffff0fe0, insns, 8);
*/
- threadContexts[0]->setIntReg(ArgumentReg1, argc);
- threadContexts[0]->setIntReg(ArgumentReg2, argv_array_base);
- threadContexts[0]->setIntReg(StackPointerReg, stack_min);
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
+
+ tc->setIntReg(ArgumentReg1, argc);
+ tc->setIntReg(ArgumentReg2, argv_array_base);
+ tc->setIntReg(StackPointerReg, stack_min);
Addr prog_entry = objFile->entryPoint();
- threadContexts[0]->setPC(prog_entry);
- threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ tc->setPC(prog_entry);
+ tc->setNextPC(prog_entry + sizeof(MachInst));
+}
+
+ArmISA::IntReg
+ArmLiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < 4);
+ return tc->readIntReg(ArgumentReg0 + i);
}
+void
+ArmLiveProcess::setSyscallArg(ThreadContext *tc,
+ int i, ArmISA::IntReg val)
+{
+ assert(i < 4);
+ tc->setIntReg(ArgumentReg0 + i, val);
+}
+
+void
+ArmLiveProcess::setSyscallReturn(ThreadContext *tc,
+ SyscallReturn return_value)
+{
+ tc->setIntReg(ReturnValueReg, return_value.value());
+}
diff --git a/src/arch/arm/process.hh b/src/arch/arm/process.hh
index b97f4b0d2..8954d3719 100644
--- a/src/arch/arm/process.hh
+++ b/src/arch/arm/process.hh
@@ -53,6 +53,9 @@ class ArmLiveProcess : public LiveProcess
public:
void argsInit(int intSize, int pageSize);
+ ArmISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, ArmISA::IntReg val);
+ void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
};
#endif // __ARM_PROCESS_HH__
diff --git a/src/arch/arm/regfile/regfile.cc b/src/arch/arm/regfile/regfile.cc
index 5de0b3076..a4d6e9a4a 100644
--- a/src/arch/arm/regfile/regfile.cc
+++ b/src/arch/arm/regfile/regfile.cc
@@ -55,7 +55,7 @@ MiscRegFile::copyMiscRegs(ThreadContext *tc)
}
void
-RegFile::serialize(std::ostream &os)
+RegFile::serialize(EventManager *em, ostream &os)
{
intRegFile.serialize(os);
//SERIALIZE_ARRAY(floatRegFile, NumFloatRegs);
@@ -69,7 +69,7 @@ RegFile::serialize(std::ostream &os)
}
void
-RegFile::unserialize(Checkpoint *cp, const std::string &section)
+RegFile::unserialize(EventManager *em, Checkpoint *cp, const string &section)
{
intRegFile.unserialize(cp, section);
//UNSERIALIZE_ARRAY(floatRegFile);
diff --git a/src/arch/arm/regfile/regfile.hh b/src/arch/arm/regfile/regfile.hh
index 86799f18d..7f4d21353 100644
--- a/src/arch/arm/regfile/regfile.hh
+++ b/src/arch/arm/regfile/regfile.hh
@@ -38,11 +38,13 @@
#include "sim/faults.hh"
class Checkpoint;
+class EventManager;
class ThreadContext;
namespace ArmISA
{
- class RegFile {
+ class RegFile
+ {
protected:
IntRegFile intRegFile; // (signed) integer register file
FloatRegFile floatRegFile; // floating point register file
@@ -176,8 +178,9 @@ namespace ArmISA
//nnpc = val;
}
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
+ void serialize(EventManager *em, std::ostream &os);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section);
void changeContext(RegContextParam param, RegContextVal val)
{
diff --git a/src/arch/arm/tlb.cc b/src/arch/arm/tlb.cc
index d0cc57a1d..78eebddfe 100644
--- a/src/arch/arm/tlb.cc
+++ b/src/arch/arm/tlb.cc
@@ -29,6 +29,7 @@
*
* Authors: Nathan Binkert
* Steve Reinhardt
+ * Jaidev Patwardhan
* Stephen Hines
*/
@@ -149,7 +150,7 @@ TLB::checkCacheability(RequestPtr &req)
// or by the TLB entry
if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
// mark request as uncacheable
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(req->getFlags() | Request::UNCACHEABLE);
}
return NoFault;
}
@@ -278,7 +279,7 @@ TLB::regStats()
}
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
+ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
{
#if !FULL_SYSTEM
Process * p = tc->getProcessPtr();
@@ -293,8 +294,17 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
#endif
}
+void
+ITB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc), req, tc, false);
+}
+
+
Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
{
#if !FULL_SYSTEM
Process * p = tc->getProcessPtr();
@@ -309,6 +319,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
#endif
}
+void
+DTB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc, write), req, tc, write);
+}
+
///////////////////////////////////////////////////////////////////////
//
// Arm ITB
diff --git a/src/arch/arm/tlb.hh b/src/arch/arm/tlb.hh
index 59fe1a60d..fea317ef3 100644
--- a/src/arch/arm/tlb.hh
+++ b/src/arch/arm/tlb.hh
@@ -62,6 +62,12 @@ struct TlbEntry
TlbEntry() {}
TlbEntry(Addr asn, Addr vaddr, Addr paddr) : _pageStart(paddr) {}
+ void
+ updateVaddr(Addr new_vaddr)
+ {
+ panic("unimplemented");
+ }
+
Addr pageStart()
{
return _pageStart;
@@ -92,14 +98,14 @@ class TLB : public BaseTLB
void nextnlu() { if (++nlu >= size) nlu = 0; }
ArmISA::PTE *lookup(Addr vpn, uint8_t asn) const;
- 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;
+ 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 invalids;
@@ -136,23 +142,30 @@ class TLB : public BaseTLB
void regStats();
};
-class ITB : public TLB {
+class ITB : public TLB
+{
public:
typedef ArmTLBParams Params;
ITB(const Params *p);
- Fault translate(RequestPtr &req, ThreadContext *tc);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation);
};
-class DTB : public TLB {
+class DTB : public TLB
+{
public:
typedef ArmTLBParams Params;
DTB(const Params *p);
- Fault translate(RequestPtr &req, ThreadContext *tc, bool write = false);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write);
};
-class UTB : public ITB, public DTB {
+class UTB : public ITB, public DTB
+{
public:
typedef ArmTLBParams Params;
UTB(const Params *p);
diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py
index bbdd95bb0..25cf84b30 100755
--- a/src/arch/isa_parser.py
+++ b/src/arch/isa_parser.py
@@ -116,7 +116,7 @@ t_SEMI = r';'
t_DOT = r'\.'
t_COLON = r':'
t_DBLCOLON = r'::'
-t_ASTERISK = r'\*'
+t_ASTERISK = r'\*'
# Identifiers and reserved words
reserved_map = { }
@@ -480,7 +480,7 @@ def p_excess_args_param(t):
#
# A decode block looks like:
-# decode <field1> [, <field2>]* [default <inst>] { ... }
+# decode <field1> [, <field2>]* [default <inst>] { ... }
#
def p_decode_block(t):
'decode_block : DECODE ID opt_default LBRACE decode_stmt_list RBRACE'
@@ -1149,7 +1149,7 @@ def buildOperandTypeMap(userDict, lineno):
ctype = 'uint%d_t' % size
is_signed = 0
elif desc == 'float':
- is_signed = 1 # shouldn't really matter
+ is_signed = 1 # shouldn't really matter
if size == 32:
ctype = 'float'
elif size == 64:
@@ -1595,9 +1595,9 @@ def buildOperandNameMap(userDict, lineno):
operands = userDict.keys()
operandsREString = (r'''
- (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
+ (?<![\w\.]) # neg. lookbehind assertion: prevent partial matches
((%s)(?:\.(\w+))?) # match: operand with optional '.' then suffix
- (?![\w\.]) # neg. lookahead assertion: prevent partial matches
+ (?![\w\.]) # neg. lookahead assertion: prevent partial matches
'''
% string.join(operands, '|'))
diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh
index c10ce7350..de070bbf9 100644
--- a/src/arch/isa_specific.hh
+++ b/src/arch/isa_specific.hh
@@ -38,7 +38,7 @@
//To use them, do something like:
//
//#if THE_ISA == YOUR_FAVORITE_ISA
-// conditional_code
+// conditional_code
//#endif
//
//Note that this is how this file sets up the TheISA macro.
diff --git a/src/arch/micro_asm.py b/src/arch/micro_asm.py
index 36c9919c0..3433a8076 100644
--- a/src/arch/micro_asm.py
+++ b/src/arch/micro_asm.py
@@ -141,7 +141,7 @@ def handle_statement(parser, container, statement):
try:
for label in statement.labels:
container.labels[label.text] = microop
- if label.extern:
+ if label.is_extern:
container.externs[label.text] = microop
container.add_microop(statement.mnemonic, microop)
except:
@@ -242,7 +242,10 @@ def t_params_PARAMS(t):
def t_asm_ID(t):
r'[A-Za-z_]\w*'
t.type = reserved_map.get(t.value, 'ID')
- t.lexer.begin('params')
+ # If the ID is really "extern", we shouldn't start looking for parameters
+ # yet. The real ID, the label itself, is coming up.
+ if t.type != 'EXTERN':
+ t.lexer.begin('params')
return t
# If there is a label and you're -not- in the assembler (which would be caught
diff --git a/src/arch/mips/MipsInterrupts.py b/src/arch/mips/MipsInterrupts.py
new file mode 100644
index 000000000..06cd54263
--- /dev/null
+++ b/src/arch/mips/MipsInterrupts.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+
+class MipsInterrupts(SimObject):
+ type = 'MipsInterrupts'
+ cxx_class = 'MipsISA::Interrupts'
diff --git a/src/arch/mips/MipsTLB.py b/src/arch/mips/MipsTLB.py
index ce8847365..41d46c572 100644
--- a/src/arch/mips/MipsTLB.py
+++ b/src/arch/mips/MipsTLB.py
@@ -32,28 +32,25 @@
from m5.SimObject import SimObject
from m5.params import *
-class MipsTLB(SimObject):
- abstract = True
+from BaseTLB import BaseTLB
+
+class MipsTLB(BaseTLB):
type = 'MipsTLB'
- cxx_namespace = 'MipsISA'
- cxx_class = 'TLB'
+ abstract = True
size = Param.Int("TLB size")
class MipsDTB(MipsTLB):
type = 'MipsDTB'
- cxx_namespace = 'MipsISA'
- cxx_class = 'DTB'
+ cxx_class = 'MipsISA::DTB'
size = 64
class MipsITB(MipsTLB):
type = 'MipsITB'
- cxx_namespace = 'MipsISA'
- cxx_class = 'ITB'
+ cxx_class = 'MipsISA::ITB'
size = 64
class MipsUTB(MipsTLB):
type = 'MipsUTB'
- cxx_namespace = 'MipsISA'
- cxx_class = 'UTB'
+ cxx_class = 'MipsISA::UTB'
size = 64
diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript
index 8be445c99..0b470def6 100644
--- a/src/arch/mips/SConscript
+++ b/src/arch/mips/SConscript
@@ -48,6 +48,7 @@ if env['TARGET_ISA'] == 'mips':
if env['FULL_SYSTEM']:
SimObject('MipsSystem.py')
+ SimObject('MipsInterrupts.py')
Source('idle_event.cc')
Source('mips_core_specific.cc')
Source('vtophys.cc')
diff --git a/src/arch/mips/bare_iron/system.hh b/src/arch/mips/bare_iron/system.hh
index ab4e02344..e593f832c 100755
--- a/src/arch/mips/bare_iron/system.hh
+++ b/src/arch/mips/bare_iron/system.hh
@@ -39,8 +39,6 @@ class IdleStartEvent;
#include "arch/mips/system.hh"
#include "params/BareIronMipsSystem.hh"
-using namespace MipsISA;
-
/**
* This class contains linux specific system code (Loading, Events).
* It points to objects that are the system binaries to load and patches them
diff --git a/src/arch/mips/dsp.cc b/src/arch/mips/dsp.cc
index 8e2db3f0b..6e4f7afea 100755
--- a/src/arch/mips/dsp.cc
+++ b/src/arch/mips/dsp.cc
@@ -40,92 +40,84 @@ using namespace MipsISA;
using namespace std;
int32_t
-MipsISA::bitrev( int32_t value )
+MipsISA::bitrev(int32_t value)
{
int32_t result = 0;
- int i, shift;
+ int shift;
- for( i=0; i<16; i++ )
- {
- shift = 2*i - 15;
+ for (int i = 0; i < 16; i++) {
+ shift = 2 * i - 15;
- if( shift < 0 )
- result |= (value & 1L<<i) << -shift;
+ if (shift < 0)
+ result |= (value & 1 << i) << -shift;
else
- result |= (value & 1L<<i) >> shift;
+ result |= (value & 1 << i) >> shift;
}
return result;
}
uint64_t
-MipsISA::dspSaturate( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow )
+MipsISA::dspSaturate(uint64_t value, int32_t fmt, int32_t sign,
+ uint32_t *overflow)
{
- int64_t svalue;
+ int64_t svalue = (int64_t)value;
- svalue = (int64_t)value;
-
- switch( sign )
- {
+ switch (sign) {
case SIGNED:
- if( svalue > (int64_t)FIXED_SMAX[fmt] )
- {
+ if (svalue > (int64_t)FIXED_SMAX[fmt]) {
*overflow = 1;
svalue = (int64_t)FIXED_SMAX[fmt];
- }
- else if( svalue < (int64_t)FIXED_SMIN[fmt] )
- {
+ } else if (svalue < (int64_t)FIXED_SMIN[fmt]) {
*overflow = 1;
svalue = (int64_t)FIXED_SMIN[fmt];
}
break;
case UNSIGNED:
- if( svalue > (int64_t)FIXED_UMAX[fmt] )
- {
+ if (svalue > (int64_t)FIXED_UMAX[fmt]) {
*overflow = 1;
svalue = FIXED_UMAX[fmt];
- }
- else if( svalue < (int64_t)FIXED_UMIN[fmt] )
- {
+ } else if (svalue < (int64_t)FIXED_UMIN[fmt]) {
*overflow = 1;
svalue = FIXED_UMIN[fmt];
}
break;
}
- return( (uint64_t)svalue );
+ return (uint64_t)svalue;
}
uint64_t
-MipsISA::checkOverflow( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow )
+MipsISA::checkOverflow(uint64_t value, int32_t fmt, int32_t sign,
+ uint32_t *overflow)
{
- int64_t svalue;
-
- svalue = (int64_t)value;
+ int64_t svalue = (int64_t)value;
- switch( sign )
+ switch (sign)
{
case SIGNED:
- if( svalue > (int64_t)FIXED_SMAX[fmt] || svalue < (int64_t)FIXED_SMIN[fmt] )
+ if (svalue > (int64_t)FIXED_SMAX[fmt] ||
+ svalue < (int64_t)FIXED_SMIN[fmt])
*overflow = 1;
break;
case UNSIGNED:
- if( svalue > (int64_t)FIXED_UMAX[fmt] || svalue < (int64_t)FIXED_UMIN[fmt] )
+ if (svalue > (int64_t)FIXED_UMAX[fmt] ||
+ svalue < (int64_t)FIXED_UMIN[fmt])
*overflow = 1;
break;
}
- return( (uint64_t)svalue );
+ return (uint64_t)svalue;
}
uint64_t
-MipsISA::signExtend( uint64_t value, int32_t fmt )
+MipsISA::signExtend(uint64_t value, int32_t fmt)
{
int32_t signpos = SIMD_NBITS[fmt];
- uint64_t sign = uint64_t(1)<<(signpos-1);
+ uint64_t sign = uint64_t(1) << (signpos - 1);
uint64_t ones = ~(0ULL);
- if( value & sign )
+ if (value & sign)
value |= (ones << signpos); // extend with ones
else
value &= (ones >> (64 - signpos)); // extend with zeros
@@ -134,231 +126,230 @@ MipsISA::signExtend( uint64_t value, int32_t fmt )
}
uint64_t
-MipsISA::addHalfLsb( uint64_t value, int32_t lsbpos )
+MipsISA::addHalfLsb(uint64_t value, int32_t lsbpos)
{
- return( value += ULL(1) << (lsbpos-1) );
+ return value += ULL(1) << (lsbpos - 1);
}
int32_t
-MipsISA::dspAbs( int32_t a, int32_t fmt, uint32_t *dspctl )
+MipsISA::dspAbs(int32_t a, int32_t fmt, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
int64_t svalue;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
+ for (int i = 0; i < nvals; i++) {
svalue = (int64_t)a_values[i];
- if( a_values[i] == FIXED_SMIN[fmt] )
- {
+ if (a_values[i] == FIXED_SMIN[fmt]) {
a_values[i] = FIXED_SMAX[fmt];
ouflag = 1;
- }
- else if( svalue < 0 )
- {
- a_values[i] = uint64_t( 0 - svalue );
+ } else if (svalue < 0) {
+ a_values[i] = uint64_t(0 - svalue);
}
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspAdd( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl )
+MipsISA::dspAdd(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
+ for (int i = 0; i < nvals; i++)
{
- if( saturate )
- a_values[i] = dspSaturate( a_values[i] + b_values[i], fmt, sign, &ouflag );
+ if (saturate)
+ a_values[i] = dspSaturate(a_values[i] + b_values[i], fmt, sign,
+ &ouflag);
else
- a_values[i] = checkOverflow( a_values[i] + b_values[i], fmt, sign, &ouflag );
+ a_values[i] = checkOverflow(a_values[i] + b_values[i], fmt, sign,
+ &ouflag);
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspAddh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign )
+MipsISA::dspAddh(int32_t a, int32_t b, int32_t fmt, int32_t round,
+ int32_t sign)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
- {
- if( round )
- a_values[i] = addHalfLsb( a_values[i] + b_values[i], 1 ) >> 1;
+ for (int i = 0; i < nvals; i++) {
+ if (round)
+ a_values[i] = addHalfLsb(a_values[i] + b_values[i], 1) >> 1;
else
- a_values[i] = ( a_values[i] + b_values[i] ) >> 1;
+ a_values[i] = (a_values[i] + b_values[i]) >> 1;
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspSub( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl )
+MipsISA::dspSub(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
- {
- if( saturate )
- a_values[i] = dspSaturate( a_values[i] - b_values[i], fmt, sign, &ouflag );
+ for (int i = 0; i < nvals; i++) {
+ if (saturate)
+ a_values[i] = dspSaturate(a_values[i] - b_values[i], fmt, sign,
+ &ouflag);
else
- a_values[i] = checkOverflow( a_values[i] - b_values[i], fmt, sign, &ouflag );
+ a_values[i] = checkOverflow(a_values[i] - b_values[i], fmt, sign,
+ &ouflag);
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<4)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 4) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspSubh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign )
+MipsISA::dspSubh(int32_t a, int32_t b, int32_t fmt, int32_t round,
+ int32_t sign)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
+ for (int i = 0; i < nvals; i++)
{
- if( round )
- a_values[i] = addHalfLsb( a_values[i] - b_values[i], 1 ) >> 1;
+ if (round)
+ a_values[i] = addHalfLsb(a_values[i] - b_values[i], 1) >> 1;
else
- a_values[i] = ( a_values[i] - b_values[i] ) >> 1;
+ a_values[i] = (a_values[i] - b_values[i]) >> 1;
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspShll( int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl )
+MipsISA::dspShll(int32_t a, uint32_t sa, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
- sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 );
- simdUnpack( a, a_values, fmt, sign );
+ sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0);
+ simdUnpack(a, a_values, fmt, sign);
- for( i=0; i<nvals; i++ )
+ for (int i = 0; i < nvals; i++)
{
- if( saturate )
- a_values[i] = dspSaturate( a_values[i] << sa, fmt, sign, &ouflag );
+ if (saturate)
+ a_values[i] = dspSaturate(a_values[i] << sa, fmt, sign, &ouflag);
else
- a_values[i] = checkOverflow( a_values[i] << sa, fmt, sign, &ouflag );
+ a_values[i] = checkOverflow(a_values[i] << sa, fmt, sign, &ouflag);
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<6)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 6) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspShrl( int32_t a, uint32_t sa, int32_t fmt, int32_t sign )
+MipsISA::dspShrl(int32_t a, uint32_t sa, int32_t fmt, int32_t sign)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
- sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 );
+ sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0);
- simdUnpack( a, a_values, fmt, UNSIGNED );
+ simdUnpack(a, a_values, fmt, UNSIGNED);
- for( i=0; i<nvals; i++ )
+ for (int i = 0; i < nvals; i++)
a_values[i] = a_values[i] >> sa;
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspShra( int32_t a, uint32_t sa, int32_t fmt, int32_t round, int32_t sign, uint32_t *dspctl )
+MipsISA::dspShra(int32_t a, uint32_t sa, int32_t fmt, int32_t round,
+ int32_t sign, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
- sa = bits( sa, SIMD_LOG2N[fmt]-1, 0 );
+ sa = bits(sa, SIMD_LOG2N[fmt] - 1, 0);
- simdUnpack( a, a_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- if( round )
- a_values[i] = addHalfLsb( a_values[i], sa ) >> sa;
+ for (int i = 0; i < nvals; i++) {
+ if (round)
+ a_values[i] = addHalfLsb(a_values[i], sa) >> sa;
else
a_values[i] = a_values[i] >> sa;
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t round, uint32_t *dspctl )
+MipsISA::dspMulq(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t round, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int sa = SIMD_NBITS[fmt];
int32_t result;
@@ -367,102 +358,104 @@ MipsISA::dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t r
uint64_t b_values[SIMD_MAX_VALS];
int64_t temp;
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- if( round )
- temp = (int64_t)addHalfLsb( a_values[i] * b_values[i] << 1, sa ) >> sa;
+ for (int i = 0; i < nvals; i++) {
+ if (round)
+ temp =
+ (int64_t)addHalfLsb(a_values[i] * b_values[i] << 1, sa) >> sa;
else
temp = (int64_t)(a_values[i] * b_values[i]) >> (sa - 1);
- if( a_values[i] == FIXED_SMIN[fmt] &&
- b_values[i] == FIXED_SMIN[fmt] )
- {
+ if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) {
ouflag = 1;
- if( saturate )
+ if (saturate)
temp = FIXED_SMAX[fmt];
}
a_values[i] = temp;
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspMul( int32_t a, int32_t b, int32_t fmt, int32_t saturate, uint32_t *dspctl )
+MipsISA::dspMul(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
+ for (int i = 0; i < nvals; i++)
{
- if( saturate )
- a_values[i] = dspSaturate( a_values[i] * b_values[i], fmt, SIGNED, &ouflag );
+ if (saturate)
+ a_values[i] = dspSaturate(a_values[i] * b_values[i], fmt, SIGNED,
+ &ouflag);
else
- a_values[i] = checkOverflow( a_values[i] * b_values[i], fmt, SIGNED, &ouflag );
+ a_values[i] = checkOverflow(a_values[i] * b_values[i], fmt, SIGNED,
+ &ouflag);
}
- simdPack( a_values, &result, fmt );
+ simdPack(a_values, &result, fmt);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspMuleu( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl )
+MipsISA::dspMuleu(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[SIMD_FMT_PH];
int32_t result;
uint32_t ouflag = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, SIMD_FMT_QB, UNSIGNED );
- simdUnpack( b, b_values, SIMD_FMT_PH, UNSIGNED );
+ simdUnpack(a, a_values, SIMD_FMT_QB, UNSIGNED);
+ simdUnpack(b, b_values, SIMD_FMT_PH, UNSIGNED);
- switch( mode )
- {
+ switch (mode) {
case MODE_L:
- for( i=0; i<nvals; i++ )
- b_values[i] = dspSaturate( a_values[i+2] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag );
+ for (int i = 0; i < nvals; i++)
+ b_values[i] = dspSaturate(a_values[i + 2] * b_values[i],
+ SIMD_FMT_PH, UNSIGNED, &ouflag);
break;
case MODE_R:
- for( i=0; i<nvals; i++ )
- b_values[i] = dspSaturate( a_values[i] * b_values[i], SIMD_FMT_PH, UNSIGNED, &ouflag );
+ for (int i = 0; i < nvals; i++)
+ b_values[i] = dspSaturate(a_values[i] * b_values[i], SIMD_FMT_PH,
+ UNSIGNED, &ouflag);
break;
}
- simdPack( b_values, &result, SIMD_FMT_PH );
+ simdPack(b_values, &result, SIMD_FMT_PH);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl )
+MipsISA::dspMuleq(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[SIMD_FMT_W];
int32_t result;
uint32_t ouflag = 0;
@@ -470,36 +463,36 @@ MipsISA::dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl )
uint64_t b_values[SIMD_MAX_VALS];
uint64_t c_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, SIMD_FMT_PH, SIGNED );
- simdUnpack( b, b_values, SIMD_FMT_PH, SIGNED );
+ simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED);
+ simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED);
- switch( mode )
- {
+ switch (mode) {
case MODE_L:
- for( i=0; i<nvals; i++ )
- c_values[i] = dspSaturate( a_values[i+1] * b_values[i+1] << 1,
- SIMD_FMT_W, SIGNED, &ouflag );
+ for (int i = 0; i < nvals; i++)
+ c_values[i] = dspSaturate(a_values[i + 1] * b_values[i + 1] << 1,
+ SIMD_FMT_W, SIGNED, &ouflag);
break;
case MODE_R:
- for( i=0; i<nvals; i++ )
- c_values[i] = dspSaturate( a_values[i] * b_values[i] << 1,
- SIMD_FMT_W, SIGNED, &ouflag );
+ for (int i = 0; i < nvals; i++)
+ c_values[i] = dspSaturate(a_values[i] * b_values[i] << 1,
+ SIMD_FMT_W, SIGNED, &ouflag);
break;
}
- simdPack( c_values, &result, SIMD_FMT_W );
+ simdPack(c_values, &result, SIMD_FMT_W);
- if( ouflag )
- writeDSPControl( dspctl, (ouflag<<5)<<DSP_CTL_POS[DSP_OUFLAG], 1<<DSP_OUFLAG);
+ if (ouflag)
+ writeDSPControl(dspctl, (ouflag << 5) << DSP_CTL_POS[DSP_OUFLAG],
+ 1 << DSP_OUFLAG);
- return( result );
+ return result;
}
int64_t
-MipsISA::dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt,
- int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl )
+MipsISA::dspDpaq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode,
+ uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[infmt];
int64_t result = 0;
int64_t temp = 0;
@@ -507,74 +500,66 @@ MipsISA::dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, infmt, SIGNED );
- simdUnpack( b, b_values, infmt, SIGNED );
+ simdUnpack(a, a_values, infmt, SIGNED);
+ simdUnpack(b, b_values, infmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- switch( mode )
- {
+ for (int i = 0; i < nvals; i++) {
+ switch (mode) {
case MODE_X:
- if( a_values[nvals-1-i] == FIXED_SMIN[infmt] &&
- b_values[i] == FIXED_SMIN[infmt] )
- {
+ if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] &&
+ b_values[i] == FIXED_SMIN[infmt]) {
result += FIXED_SMAX[outfmt];
ouflag = 1;
}
else
- result += a_values[nvals-1-i] * b_values[i] << 1;
+ result += a_values[nvals - 1 - i] * b_values[i] << 1;
break;
default:
- if( a_values[i] == FIXED_SMIN[infmt] &&
- b_values[i] == FIXED_SMIN[infmt] )
- {
+ if (a_values[i] == FIXED_SMIN[infmt] &&
+ b_values[i] == FIXED_SMIN[infmt]) {
result += FIXED_SMAX[outfmt];
ouflag = 1;
- }
- else
+ } else {
result += a_values[i] * b_values[i] << 1;
+ }
break;
}
}
- if( postsat )
- {
- if( outfmt == SIMD_FMT_L )
- {
- int signa = bits( dspac, 63, 63 );
- int signb = bits( result, 63, 63 );
+ if (postsat) {
+ if (outfmt == SIMD_FMT_L) {
+ int signa = bits(dspac, 63, 63);
+ int signb = bits(result, 63, 63);
temp = dspac + result;
- if( ( signa == signb ) &&
- ( bits( temp, 63, 63 ) != signa ) )
- {
+ if (signa == signb && bits(temp, 63, 63) != signa) {
ouflag = 1;
- if( signa )
+ if (signa)
dspac = FIXED_SMIN[outfmt];
else
dspac = FIXED_SMAX[outfmt];
- }
- else
+ } else {
dspac = temp;
+ }
+ } else {
+ dspac = dspSaturate(dspac + result, outfmt, SIGNED, &ouflag);
}
- else
- dspac = dspSaturate( dspac + result, outfmt, SIGNED, &ouflag );
- }
- else
+ } else {
dspac += result;
+ }
- if( ouflag )
- *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 );
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1);
- return( dspac );
+ return dspac;
}
int64_t
-MipsISA::dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt,
- int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl )
+MipsISA::dspDpsq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode,
+ uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[infmt];
int64_t result = 0;
int64_t temp = 0;
@@ -582,93 +567,82 @@ MipsISA::dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, infmt, SIGNED );
- simdUnpack( b, b_values, infmt, SIGNED );
+ simdUnpack(a, a_values, infmt, SIGNED);
+ simdUnpack(b, b_values, infmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- switch( mode )
- {
+ for (int i = 0; i < nvals; i++) {
+ switch (mode) {
case MODE_X:
- if( a_values[nvals-1-i] == FIXED_SMIN[infmt] &&
- b_values[i] == FIXED_SMIN[infmt] )
- {
+ if (a_values[nvals - 1 - i] == FIXED_SMIN[infmt] &&
+ b_values[i] == FIXED_SMIN[infmt]) {
result += FIXED_SMAX[outfmt];
ouflag = 1;
+ } else {
+ result += a_values[nvals - 1 - i] * b_values[i] << 1;
}
- else
- result += a_values[nvals-1-i] * b_values[i] << 1;
break;
default:
- if( a_values[i] == FIXED_SMIN[infmt] &&
- b_values[i] == FIXED_SMIN[infmt] )
- {
+ if (a_values[i] == FIXED_SMIN[infmt] &&
+ b_values[i] == FIXED_SMIN[infmt]) {
result += FIXED_SMAX[outfmt];
ouflag = 1;
- }
- else
+ } else {
result += a_values[i] * b_values[i] << 1;
+ }
break;
}
}
- if( postsat )
- {
- if( outfmt == SIMD_FMT_L )
- {
- int signa = bits( dspac, 63, 63 );
- int signb = bits( -result, 63, 63 );
+ if (postsat) {
+ if (outfmt == SIMD_FMT_L) {
+ int signa = bits(dspac, 63, 63);
+ int signb = bits(-result, 63, 63);
temp = dspac - result;
- if( ( signa == signb ) &&
- ( bits( temp, 63, 63 ) != signa ) )
- {
+ if (signa == signb && bits(temp, 63, 63) != signa) {
ouflag = 1;
- if( signa )
+ if (signa)
dspac = FIXED_SMIN[outfmt];
else
dspac = FIXED_SMAX[outfmt];
- }
- else
+ } else {
dspac = temp;
+ }
+ } else {
+ dspac = dspSaturate(dspac - result, outfmt, SIGNED, &ouflag);
}
- else
- dspac = dspSaturate( dspac - result, outfmt, SIGNED, &ouflag );
- }
- else
+ } else {
dspac -= result;
+ }
- if( ouflag )
- *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 );
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1);
- return( dspac );
+ return dspac;
}
int64_t
-MipsISA::dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac,
- int32_t fmt, int32_t sign, int32_t mode )
+MipsISA::dspDpa(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t fmt, int32_t sign, int32_t mode)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<2; i++ )
- {
- switch( mode )
- {
+ for (int i = 0; i < 2; i++) {
+ switch (mode) {
case MODE_L:
- dspac += a_values[nvals-1-i] * b_values[nvals-1-i];
+ dspac += a_values[nvals - 1 - i] * b_values[nvals - 1 - i];
break;
case MODE_R:
- dspac += a_values[nvals-3-i] * b_values[nvals-3-i];
+ dspac += a_values[nvals - 3 - i] * b_values[nvals - 3 - i];
break;
case MODE_X:
- dspac += a_values[nvals-1-i] * b_values[i];
+ dspac += a_values[nvals - 1 - i] * b_values[i];
break;
}
}
@@ -677,29 +651,26 @@ MipsISA::dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac,
}
int64_t
-MipsISA::dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac,
- int32_t fmt, int32_t sign, int32_t mode )
+MipsISA::dspDps(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t fmt, int32_t sign, int32_t mode)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<2; i++ )
- {
- switch( mode )
- {
+ for (int i = 0; i < 2; i++) {
+ switch (mode) {
case MODE_L:
- dspac -= a_values[nvals-1-i] * b_values[nvals-1-i];
+ dspac -= a_values[nvals - 1 - i] * b_values[nvals - 1 - i];
break;
case MODE_R:
- dspac -= a_values[nvals-3-i] * b_values[nvals-3-i];
+ dspac -= a_values[nvals - 3 - i] * b_values[nvals - 3 - i];
break;
case MODE_X:
- dspac -= a_values[nvals-1-i] * b_values[i];
+ dspac -= a_values[nvals - 1 - i] * b_values[i];
break;
}
}
@@ -708,36 +679,33 @@ MipsISA::dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac,
}
int64_t
-MipsISA::dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac,
- int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl )
+MipsISA::dspMaq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl)
{
- int i = 0;
- int nvals = SIMD_NVALS[fmt-1];
+ int nvals = SIMD_NVALS[fmt - 1];
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
int64_t temp = 0;
uint32_t ouflag = 0;
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- switch( mode )
- {
+ for (int i = 0; i < nvals; i++) {
+ switch (mode) {
case MODE_L:
- temp = a_values[i+1] * b_values[i+1] << 1;
- if( a_values[i+1] == FIXED_SMIN[fmt] && b_values[i+1] == FIXED_SMIN[fmt] )
- {
- temp = (int64_t)FIXED_SMAX[fmt-1];
+ temp = a_values[i + 1] * b_values[i + 1] << 1;
+ if (a_values[i + 1] == FIXED_SMIN[fmt] &&
+ b_values[i + 1] == FIXED_SMIN[fmt]) {
+ temp = (int64_t)FIXED_SMAX[fmt - 1];
ouflag = 1;
}
break;
case MODE_R:
temp = a_values[i] * b_values[i] << 1;
- if( a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt] )
- {
- temp = (int64_t)FIXED_SMAX[fmt-1];
+ if (a_values[i] == FIXED_SMIN[fmt] &&
+ b_values[i] == FIXED_SMIN[fmt]) {
+ temp = (int64_t)FIXED_SMAX[fmt - 1];
ouflag = 1;
}
break;
@@ -745,23 +713,23 @@ MipsISA::dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac,
temp += dspac;
- if( saturate )
- temp = dspSaturate( temp, fmt-1, SIGNED, &ouflag );
- if( ouflag )
- *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 );
+ if (saturate)
+ temp = dspSaturate(temp, fmt - 1, SIGNED, &ouflag);
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1);
}
return temp;
}
int64_t
-MipsISA::dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt )
+MipsISA::dspMulsa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt)
{
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
dspac += a_values[1] * b_values[1] - a_values[0] * b_values[0];
@@ -769,132 +737,140 @@ MipsISA::dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt
}
int64_t
-MipsISA::dspMulsaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, uint32_t *dspctl )
+MipsISA::dspMulsaq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t fmt, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
int64_t temp[2];
uint32_t ouflag = 0;
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- for( i=nvals-1; i>-1; i-- )
- {
+ for (int i = nvals - 1; i > -1; i--) {
temp[i] = a_values[i] * b_values[i] << 1;
- if( a_values[i] == FIXED_SMIN[fmt] &&
- b_values[i] == FIXED_SMIN[fmt] )
- {
- temp[i] = FIXED_SMAX[fmt-1];
+ if (a_values[i] == FIXED_SMIN[fmt] && b_values[i] == FIXED_SMIN[fmt]) {
+ temp[i] = FIXED_SMAX[fmt - 1];
ouflag = 1;
}
}
dspac += temp[1] - temp[0];
- if( ouflag )
- *dspctl = insertBits( *dspctl, 16+ac, 16+ac, 1 );
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 16 + ac, 16 + ac, 1);
return dspac;
}
void
-MipsISA::dspCmp( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl )
+MipsISA::dspCmp(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op,
+ uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int ccond = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
- {
+ for (int i = 0; i < nvals; i++) {
int cc = 0;
- switch( op )
- {
- case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break;
- case CMP_LT: cc = ( a_values[i] < b_values[i] ); break;
- case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break;
+ switch (op) {
+ case CMP_EQ:
+ cc = (a_values[i] == b_values[i]);
+ break;
+ case CMP_LT:
+ cc = (a_values[i] < b_values[i]);
+ break;
+ case CMP_LE:
+ cc = (a_values[i] <= b_values[i]);
+ break;
}
- ccond |= cc << ( DSP_CTL_POS[DSP_CCOND] + i );
+ ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i);
}
- writeDSPControl( dspctl, ccond, 1<<DSP_CCOND );
+ writeDSPControl(dspctl, ccond, 1 << DSP_CCOND);
}
int32_t
-MipsISA::dspCmpg( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op )
+MipsISA::dspCmpg(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
- {
+ for (int i = 0; i < nvals; i++) {
int cc = 0;
- switch( op )
- {
- case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break;
- case CMP_LT: cc = ( a_values[i] < b_values[i] ); break;
- case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break;
+ switch (op) {
+ case CMP_EQ:
+ cc = (a_values[i] == b_values[i]);
+ break;
+ case CMP_LT:
+ cc = (a_values[i] < b_values[i]);
+ break;
+ case CMP_LE:
+ cc = (a_values[i] <= b_values[i]);
+ break;
}
result |= cc << i;
}
- return( result );
+ return result;
}
int32_t
-MipsISA::dspCmpgd( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl )
+MipsISA::dspCmpgd(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op,
+ uint32_t *dspctl)
{
- int i = 0;;
int nvals = SIMD_NVALS[fmt];
int32_t result = 0;
int ccond = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, sign );
- simdUnpack( b, b_values, fmt, sign );
+ simdUnpack(a, a_values, fmt, sign);
+ simdUnpack(b, b_values, fmt, sign);
- for( i=0; i<nvals; i++ )
- {
- int cc = 0;;
+ for (int i = 0; i < nvals; i++) {
+ int cc = 0;
- switch( op )
- {
- case CMP_EQ: cc = ( a_values[i] == b_values[i] ); break;
- case CMP_LT: cc = ( a_values[i] < b_values[i] ); break;
- case CMP_LE: cc = ( a_values[i] <= b_values[i] ); break;
+ switch (op) {
+ case CMP_EQ:
+ cc = (a_values[i] == b_values[i]);
+ break;
+ case CMP_LT:
+ cc = (a_values[i] < b_values[i]);
+ break;
+ case CMP_LE:
+ cc = (a_values[i] <= b_values[i]);
+ break;
}
result |= cc << i;
- ccond |= cc << ( DSP_CTL_POS[DSP_CCOND] + i );
+ ccond |= cc << (DSP_CTL_POS[DSP_CCOND] + i);
}
- writeDSPControl( dspctl, ccond, 1<<DSP_CCOND );
+ writeDSPControl(dspctl, ccond, 1 << DSP_CCOND);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int32_t outsign, int32_t mode )
+MipsISA::dspPrece(int32_t a, int32_t infmt, int32_t insign, int32_t outfmt,
+ int32_t outsign, int32_t mode)
{
- int i = 0;
int sa = 0;
int ninvals = SIMD_NVALS[infmt];
int noutvals = SIMD_NVALS[outfmt];
@@ -902,62 +878,68 @@ MipsISA::dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int
uint64_t in_values[SIMD_MAX_VALS];
uint64_t out_values[SIMD_MAX_VALS];
- if( insign == SIGNED && outsign == SIGNED )
+ if (insign == SIGNED && outsign == SIGNED)
sa = SIMD_NBITS[infmt];
- else if( insign == UNSIGNED && outsign == SIGNED )
+ else if (insign == UNSIGNED && outsign == SIGNED)
sa = SIMD_NBITS[infmt] - 1;
- else if( insign == UNSIGNED && outsign == UNSIGNED )
+ else if (insign == UNSIGNED && outsign == UNSIGNED)
sa = 0;
- simdUnpack( a, in_values, infmt, insign );
+ simdUnpack(a, in_values, infmt, insign);
- for( i=0; i<noutvals; i++ )
- {
- switch( mode )
- {
- case MODE_L: out_values[i] = in_values[i+(ninvals>>1)] << sa; break;
- case MODE_R: out_values[i] = in_values[i] << sa; break;
- case MODE_LA: out_values[i] = in_values[(i<<1)+1] << sa; break;
- case MODE_RA: out_values[i] = in_values[i<<1] << sa; break;
+ for (int i = 0; i<noutvals; i++) {
+ switch (mode) {
+ case MODE_L:
+ out_values[i] = in_values[i + (ninvals >> 1)] << sa;
+ break;
+ case MODE_R:
+ out_values[i] = in_values[i] << sa;
+ break;
+ case MODE_LA:
+ out_values[i] = in_values[(i << 1) + 1] << sa;
+ break;
+ case MODE_RA:
+ out_values[i] = in_values[i << 1] << sa;
+ break;
}
}
- simdPack( out_values, &result, outfmt );
+ simdPack(out_values, &result, outfmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspPrecrqu( int32_t a, int32_t b, uint32_t *dspctl )
+MipsISA::dspPrecrqu(int32_t a, int32_t b, uint32_t *dspctl)
{
- int i = 0;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
uint64_t r_values[SIMD_MAX_VALS];
uint32_t ouflag = 0;
int32_t result = 0;
- simdUnpack( a, a_values, SIMD_FMT_PH, SIGNED );
- simdUnpack( b, b_values, SIMD_FMT_PH, SIGNED );
+ simdUnpack(a, a_values, SIMD_FMT_PH, SIGNED);
+ simdUnpack(b, b_values, SIMD_FMT_PH, SIGNED);
- for( i=0; i<2; i++ )
- {
- r_values[i] = dspSaturate( (int64_t)b_values[i] >> SIMD_NBITS[SIMD_FMT_QB] - 1,
- SIMD_FMT_QB, UNSIGNED, &ouflag );
- r_values[i+2] = dspSaturate( (int64_t)a_values[i] >> SIMD_NBITS[SIMD_FMT_QB] - 1,
- SIMD_FMT_QB, UNSIGNED, &ouflag );
+ for (int i = 0; i<2; i++) {
+ r_values[i] =
+ dspSaturate((int64_t)b_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1),
+ SIMD_FMT_QB, UNSIGNED, &ouflag);
+ r_values[i + 2] =
+ dspSaturate((int64_t)a_values[i] >> (SIMD_NBITS[SIMD_FMT_QB] - 1),
+ SIMD_FMT_QB, UNSIGNED, &ouflag);
}
- simdPack( r_values, &result, SIMD_FMT_QB );
+ simdPack(r_values, &result, SIMD_FMT_QB);
- if( ouflag )
- *dspctl = insertBits( *dspctl, 22, 22, 1 );
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 22, 22, 1);
return result;
}
int32_t
-MipsISA::dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl )
+MipsISA::dspPrecrq(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl)
{
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
@@ -965,245 +947,226 @@ MipsISA::dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl )
uint32_t ouflag = 0;
int32_t result;
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- r_values[1] = dspSaturate( (int64_t)addHalfLsb( a_values[0], 16 ) >> 16,
- fmt+1, SIGNED, &ouflag );
- r_values[0] = dspSaturate( (int64_t)addHalfLsb( b_values[0], 16 ) >> 16,
- fmt+1, SIGNED, &ouflag );
+ r_values[1] = dspSaturate((int64_t)addHalfLsb(a_values[0], 16) >> 16,
+ fmt + 1, SIGNED, &ouflag);
+ r_values[0] = dspSaturate((int64_t)addHalfLsb(b_values[0], 16) >> 16,
+ fmt + 1, SIGNED, &ouflag);
- simdPack( r_values, &result, fmt+1 );
+ simdPack(r_values, &result, fmt + 1);
- if( ouflag )
- *dspctl = insertBits( *dspctl, 22, 22, 1 );
+ if (ouflag)
+ *dspctl = insertBits(*dspctl, 22, 22, 1);
return result;
}
int32_t
-MipsISA::dspPrecrSra( int32_t a, int32_t b, int32_t sa, int32_t fmt, int32_t round )
+MipsISA::dspPrecrSra(int32_t a, int32_t b, int32_t sa, int32_t fmt,
+ int32_t round)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
uint64_t c_values[SIMD_MAX_VALS];
int32_t result = 0;
- simdUnpack( a, a_values, fmt, SIGNED );
- simdUnpack( b, b_values, fmt, SIGNED );
+ simdUnpack(a, a_values, fmt, SIGNED);
+ simdUnpack(b, b_values, fmt, SIGNED);
- for( i=0; i<nvals; i++ )
- {
- if( round )
- {
- c_values[i] = addHalfLsb( b_values[i], sa ) >> sa;
- c_values[i+1] = addHalfLsb( a_values[i], sa ) >> sa;
- }
- else
- {
+ for (int i = 0; i < nvals; i++) {
+ if (round) {
+ c_values[i] = addHalfLsb(b_values[i], sa) >> sa;
+ c_values[i + 1] = addHalfLsb(a_values[i], sa) >> sa;
+ } else {
c_values[i] = b_values[i] >> sa;
- c_values[i+1] = a_values[i] >> sa;
+ c_values[i + 1] = a_values[i] >> sa;
}
}
- simdPack( c_values, &result, fmt+1 );
+ simdPack(c_values, &result, fmt + 1);
return result;
}
int32_t
-MipsISA::dspPick( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl )
+MipsISA::dspPick(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
uint64_t c_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, UNSIGNED );
- simdUnpack( b, b_values, fmt, UNSIGNED );
+ simdUnpack(a, a_values, fmt, UNSIGNED);
+ simdUnpack(b, b_values, fmt, UNSIGNED);
- for( i=0; i<nvals; i++ )
- {
+ for (int i = 0; i < nvals; i++) {
int condbit = DSP_CTL_POS[DSP_CCOND] + i;
- if( bits( *dspctl, condbit, condbit ) == 1 )
+ if (bits(*dspctl, condbit, condbit) == 1)
c_values[i] = a_values[i];
else
c_values[i] = b_values[i];
}
- simdPack( c_values, &result, fmt );
+ simdPack(c_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspPack( int32_t a, int32_t b, int32_t fmt )
+MipsISA::dspPack(int32_t a, int32_t b, int32_t fmt)
{
int32_t result;
uint64_t a_values[SIMD_MAX_VALS];
uint64_t b_values[SIMD_MAX_VALS];
uint64_t c_values[SIMD_MAX_VALS];
- simdUnpack( a, a_values, fmt, UNSIGNED );
- simdUnpack( b, b_values, fmt, UNSIGNED );
+ simdUnpack(a, a_values, fmt, UNSIGNED);
+ simdUnpack(b, b_values, fmt, UNSIGNED);
c_values[0] = b_values[1];
c_values[1] = a_values[0];
- simdPack( c_values, &result, fmt );
+ simdPack(c_values, &result, fmt);
- return( result );
+ return result;
}
int32_t
-MipsISA::dspExtr( int64_t dspac, int32_t fmt, int32_t sa, int32_t round, int32_t saturate, uint32_t *dspctl )
+MipsISA::dspExtr(int64_t dspac, int32_t fmt, int32_t sa, int32_t round,
+ int32_t saturate, uint32_t *dspctl)
{
int32_t result = 0;
uint32_t ouflag = 0;
int64_t temp = 0;
- sa = bits( sa, 4, 0 );
+ sa = bits(sa, 4, 0);
- if( sa > 0 )
- {
- if( round )
- {
- temp = (int64_t)addHalfLsb( dspac, sa );
+ if (sa > 0) {
+ if (round) {
+ temp = (int64_t)addHalfLsb(dspac, sa);
- if( dspac > 0 && temp < 0 )
- {
+ if (dspac > 0 && temp < 0) {
ouflag = 1;
- if( saturate )
+ if (saturate)
temp = FIXED_SMAX[SIMD_FMT_L];
}
temp = temp >> sa;
- }
- else
+ } else {
temp = dspac >> sa;
- }
- else
+ }
+ } else {
temp = dspac;
+ }
- dspac = checkOverflow( dspac, fmt, SIGNED, &ouflag );
+ dspac = checkOverflow(dspac, fmt, SIGNED, &ouflag);
- if( ouflag )
- {
- *dspctl = insertBits( *dspctl, 23, 23, ouflag );
+ if (ouflag) {
+ *dspctl = insertBits(*dspctl, 23, 23, ouflag);
- if( saturate )
- result = (int32_t)dspSaturate( temp, fmt, SIGNED, &ouflag );
+ if (saturate)
+ result = (int32_t)dspSaturate(temp, fmt, SIGNED, &ouflag);
else
result = (int32_t)temp;
- }
- else
+ } else {
result = (int32_t)temp;
+ }
- return( result );
+ return result;
}
int32_t
-MipsISA::dspExtp( int64_t dspac, int32_t size, uint32_t *dspctl )
+MipsISA::dspExtp(int64_t dspac, int32_t size, uint32_t *dspctl)
{
int32_t pos = 0;
int32_t result = 0;
- pos = bits( *dspctl, 5, 0 );
- size = bits( size, 4, 0 );
+ pos = bits(*dspctl, 5, 0);
+ size = bits(size, 4, 0);
- if( pos - (size+1) >= -1 )
- {
- result = bits( dspac, pos, pos-size );
- *dspctl = insertBits( *dspctl, 14, 14, 0 );
- }
- else
- {
+ if (pos - (size + 1) >= -1) {
+ result = bits(dspac, pos, pos - size);
+ *dspctl = insertBits(*dspctl, 14, 14, 0);
+ } else {
result = 0;
- *dspctl = insertBits( *dspctl, 14, 14, 1 );
+ *dspctl = insertBits(*dspctl, 14, 14, 1);
}
- return( result );
+ return result;
}
int32_t
-MipsISA::dspExtpd( int64_t dspac, int32_t size, uint32_t *dspctl )
+MipsISA::dspExtpd(int64_t dspac, int32_t size, uint32_t *dspctl)
{
int32_t pos = 0;
int32_t result = 0;
- pos = bits( *dspctl, 5, 0 );
- size = bits( size, 4, 0 );
-
- if( pos - (size+1) >= -1 )
- {
- result = bits( dspac, pos, pos-size );
- *dspctl = insertBits( *dspctl, 14, 14, 0 );
- if( pos - (size+1) >= 0 )
- *dspctl = insertBits( *dspctl, 5, 0, pos - (size+1) );
- else if( (pos - (size+1)) == -1 )
- *dspctl = insertBits( *dspctl, 5, 0, 63 );
- }
- else
- {
+ pos = bits(*dspctl, 5, 0);
+ size = bits(size, 4, 0);
+
+ if (pos - (size + 1) >= -1) {
+ result = bits(dspac, pos, pos - size);
+ *dspctl = insertBits(*dspctl, 14, 14, 0);
+ if (pos - (size + 1) >= 0)
+ *dspctl = insertBits(*dspctl, 5, 0, pos - (size + 1));
+ else if ((pos - (size + 1)) == -1)
+ *dspctl = insertBits(*dspctl, 5, 0, 63);
+ } else {
result = 0;
- *dspctl = insertBits( *dspctl, 14, 14, 1 );
+ *dspctl = insertBits(*dspctl, 14, 14, 1);
}
- return( result );
+ return result;
}
void
-MipsISA::simdPack( uint64_t *values_ptr, int32_t *reg, int32_t fmt )
+MipsISA::simdPack(uint64_t *values_ptr, int32_t *reg, int32_t fmt)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int nbits = SIMD_NBITS[fmt];
*reg = 0;
- for( i=0; i<nvals; i++ )
- *reg |= (int32_t)bits( values_ptr[i], nbits-1, 0 ) << nbits*i;
+ for (int i = 0; i < nvals; i++)
+ *reg |= (int32_t)bits(values_ptr[i], nbits - 1, 0) << nbits * i;
}
void
-MipsISA::simdUnpack( int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign )
+MipsISA::simdUnpack(int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign)
{
- int i = 0;
int nvals = SIMD_NVALS[fmt];
int nbits = SIMD_NBITS[fmt];
- switch( sign )
- {
- case SIGNED:
- for( i=0; i<nvals; i++ )
- {
- values_ptr[i] = (uint64_t)bits( reg, nbits*(i+1)-1, nbits*i );
- values_ptr[i] = signExtend( values_ptr[i], fmt );
+ switch (sign) {
+ case SIGNED:
+ for (int i = 0; i < nvals; i++) {
+ uint64_t tmp = (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i);
+ values_ptr[i] = signExtend(tmp, fmt);
}
break;
- case UNSIGNED:
- for( i=0; i<nvals; i++ )
- {
- values_ptr[i] = (uint64_t)bits( reg, nbits*(i+1)-1, nbits*i );
+ case UNSIGNED:
+ for (int i = 0; i < nvals; i++) {
+ values_ptr[i] =
+ (uint64_t)bits(reg, nbits * (i + 1) - 1, nbits * i);
}
break;
}
}
void
-MipsISA::writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask )
+MipsISA::writeDSPControl(uint32_t *dspctl, uint32_t value, uint32_t mask)
{
uint32_t fmask = 0;
- if( mask & 0x01 ) fmask |= DSP_CTL_MASK[DSP_POS];
- if( mask & 0x02 ) fmask |= DSP_CTL_MASK[DSP_SCOUNT];
- if( mask & 0x04 ) fmask |= DSP_CTL_MASK[DSP_C];
- if( mask & 0x08 ) fmask |= DSP_CTL_MASK[DSP_OUFLAG];
- if( mask & 0x10 ) fmask |= DSP_CTL_MASK[DSP_CCOND];
- if( mask & 0x20 ) fmask |= DSP_CTL_MASK[DSP_EFI];
+ if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS];
+ if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT];
+ if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C];
+ if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG];
+ if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND];
+ if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI];
*dspctl &= ~fmask;
value &= fmask;
@@ -1211,16 +1174,16 @@ MipsISA::writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask )
}
uint32_t
-MipsISA::readDSPControl( uint32_t *dspctl, uint32_t mask )
+MipsISA::readDSPControl(uint32_t *dspctl, uint32_t mask)
{
uint32_t fmask = 0;
- if( mask & 0x01 ) fmask |= DSP_CTL_MASK[DSP_POS];
- if( mask & 0x02 ) fmask |= DSP_CTL_MASK[DSP_SCOUNT];
- if( mask & 0x04 ) fmask |= DSP_CTL_MASK[DSP_C];
- if( mask & 0x08 ) fmask |= DSP_CTL_MASK[DSP_OUFLAG];
- if( mask & 0x10 ) fmask |= DSP_CTL_MASK[DSP_CCOND];
- if( mask & 0x20 ) fmask |= DSP_CTL_MASK[DSP_EFI];
+ if (mask & 0x01) fmask |= DSP_CTL_MASK[DSP_POS];
+ if (mask & 0x02) fmask |= DSP_CTL_MASK[DSP_SCOUNT];
+ if (mask & 0x04) fmask |= DSP_CTL_MASK[DSP_C];
+ if (mask & 0x08) fmask |= DSP_CTL_MASK[DSP_OUFLAG];
+ if (mask & 0x10) fmask |= DSP_CTL_MASK[DSP_CCOND];
+ if (mask & 0x20) fmask |= DSP_CTL_MASK[DSP_EFI];
- return( *dspctl & fmask );
+ return *dspctl & fmask;
}
diff --git a/src/arch/mips/dsp.hh b/src/arch/mips/dsp.hh
index fb8d5c4f6..fde4b332a 100755
--- a/src/arch/mips/dsp.hh
+++ b/src/arch/mips/dsp.hh
@@ -41,131 +41,164 @@ class ThreadContext;
namespace MipsISA {
- // SIMD formats
- enum {
- SIMD_FMT_L, // long word
- SIMD_FMT_W, // word
- SIMD_FMT_PH, // paired halfword
- SIMD_FMT_QB, // quad byte
- SIMD_NUM_FMTS
- };
-
- // DSPControl Fields
- enum {
- DSP_POS, // insertion bitfield position
- DSP_SCOUNT, // insertion bitfield size
- DSP_C, // carry bit
- DSP_OUFLAG, // overflow-underflow flag
- DSP_CCOND, // condition code
- DSP_EFI, // extract fail indicator bit
- DSP_NUM_FIELDS
- };
-
- // compare instruction operations
- enum {
- CMP_EQ, // equal
- CMP_LT, // less than
- CMP_LE // less than or equal
- };
-
- // SIMD operation order modes
- enum {
- MODE_L, // left
- MODE_R, // right
- MODE_LA, // left-alternate
- MODE_RA, // right-alternate
- MODE_X // cross
- };
-
- // dsp operation parameters
- enum { UNSIGNED, SIGNED };
- enum { NOSATURATE, SATURATE };
- enum { NOROUND, ROUND };
-
- // DSPControl field positions and masks
- const uint32_t DSP_CTL_POS[DSP_NUM_FIELDS] = { 0, 7, 13, 16, 24, 14 };
- const uint32_t DSP_CTL_MASK[DSP_NUM_FIELDS] = { 0x0000003f, 0x00001f80, 0x00002000,
- 0x00ff0000, 0x0f000000, 0x00004000 };
-
- // SIMD format constants
- const uint32_t SIMD_MAX_VALS = 4; // maximum values per register
- const uint32_t SIMD_NVALS[SIMD_NUM_FMTS] = { 1, 1, 2, 4 }; // number of values in fmt
- const uint32_t SIMD_NBITS[SIMD_NUM_FMTS] = { 64, 32, 16, 8 }; // number of bits per value
- const uint32_t SIMD_LOG2N[SIMD_NUM_FMTS] = { 6, 5, 4, 3 }; // log2( bits per value )
-
- // DSP maximum values
- const uint64_t FIXED_L_SMAX = ULL(0x7fffffffffffffff);
- const uint64_t FIXED_W_SMAX = ULL(0x000000007fffffff);
- const uint64_t FIXED_H_SMAX = ULL(0x0000000000007fff);
- const uint64_t FIXED_B_SMAX = ULL(0x000000000000007f);
- const uint64_t FIXED_L_UMAX = ULL(0xffffffffffffffff);
- const uint64_t FIXED_W_UMAX = ULL(0x00000000ffffffff);
- const uint64_t FIXED_H_UMAX = ULL(0x000000000000ffff);
- const uint64_t FIXED_B_UMAX = ULL(0x00000000000000ff);
- const uint64_t FIXED_SMAX[SIMD_NUM_FMTS] = { FIXED_L_SMAX, FIXED_W_SMAX, FIXED_H_SMAX, FIXED_B_SMAX };
- const uint64_t FIXED_UMAX[SIMD_NUM_FMTS] = { FIXED_L_UMAX, FIXED_W_UMAX, FIXED_H_UMAX, FIXED_B_UMAX };
-
- // DSP minimum values
- const uint64_t FIXED_L_SMIN = ULL(0x8000000000000000);
- const uint64_t FIXED_W_SMIN = ULL(0xffffffff80000000);
- const uint64_t FIXED_H_SMIN = ULL(0xffffffffffff8000);
- const uint64_t FIXED_B_SMIN = ULL(0xffffffffffffff80);
- const uint64_t FIXED_L_UMIN = ULL(0x0000000000000000);
- const uint64_t FIXED_W_UMIN = ULL(0x0000000000000000);
- const uint64_t FIXED_H_UMIN = ULL(0x0000000000000000);
- const uint64_t FIXED_B_UMIN = ULL(0x0000000000000000);
- const uint64_t FIXED_SMIN[SIMD_NUM_FMTS] = { FIXED_L_SMIN, FIXED_W_SMIN, FIXED_H_SMIN, FIXED_B_SMIN };
- const uint64_t FIXED_UMIN[SIMD_NUM_FMTS] = { FIXED_L_UMIN, FIXED_W_UMIN, FIXED_H_UMIN, FIXED_B_UMIN };
-
- // DSP utility functions
- int32_t bitrev( int32_t value );
- uint64_t dspSaturate( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow );
- uint64_t checkOverflow( uint64_t value, int32_t fmt, int32_t sign, uint32_t *overflow );
- uint64_t signExtend( uint64_t value, int32_t signpos );
- uint64_t addHalfLsb( uint64_t value, int32_t lsbpos );
- int32_t dspAbs( int32_t a, int32_t fmt, uint32_t *dspctl );
- int32_t dspAdd( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl );
- int32_t dspAddh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign );
- int32_t dspSub( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl );
- int32_t dspSubh( int32_t a, int32_t b, int32_t fmt, int32_t round, int32_t sign );
- int32_t dspShll( int32_t a, uint32_t sa, int32_t fmt, int32_t saturate, int32_t sign, uint32_t *dspctl );
- int32_t dspShrl( int32_t a, uint32_t sa, int32_t fmt, int32_t sign );
- int32_t dspShra( int32_t a, uint32_t sa, int32_t fmt, int32_t round, int32_t sign, uint32_t *dspctl );
- int32_t dspMul( int32_t a, int32_t b, int32_t fmt, int32_t saturate, uint32_t *dspctl );
- int32_t dspMulq( int32_t a, int32_t b, int32_t fmt, int32_t saturate, int32_t round, uint32_t *dspctl );
- int32_t dspMuleu( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl );
- int32_t dspMuleq( int32_t a, int32_t b, int32_t mode, uint32_t *dspctl );
- int64_t dspDpaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt,
- int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl );
- int64_t dspDpsq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t infmt,
- int32_t outfmt, int32_t postsat, int32_t mode, uint32_t *dspctl );
- int64_t dspDpa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode );
- int64_t dspDps( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, int32_t sign, int32_t mode );
- int64_t dspMaq( int64_t dspac, int32_t a, int32_t b, int32_t ac,
- int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl );
- int64_t dspMulsa( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt );
- int64_t dspMulsaq( int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt, uint32_t *dspctl );
- void dspCmp( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl );
- int32_t dspCmpg( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op );
- int32_t dspCmpgd( int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op, uint32_t *dspctl );
- int32_t dspPrece( int32_t a, int32_t infmt, int32_t insign, int32_t outfmt, int32_t outsign, int32_t mode );
- int32_t dspPrecrqu( int32_t a, int32_t b, uint32_t *dspctl );
- int32_t dspPrecrq( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl );
- int32_t dspPrecrSra( int32_t a, int32_t b, int32_t sa, int32_t fmt, int32_t round );
- int32_t dspPick( int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl );
- int32_t dspPack( int32_t a, int32_t b, int32_t fmt );
- int32_t dspExtr( int64_t dspac, int32_t fmt, int32_t sa, int32_t round,
- int32_t saturate, uint32_t *dspctl );
- int32_t dspExtp( int64_t dspac, int32_t size, uint32_t *dspctl );
- int32_t dspExtpd( int64_t dspac, int32_t size, uint32_t *dspctl );
-
- // SIMD pack/unpack utility functions
- void simdPack( uint64_t *values_ptr, int32_t *reg, int32_t fmt );
- void simdUnpack( int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign );
-
- // DSPControl r/w utility functions
- void writeDSPControl( uint32_t *dspctl, uint32_t value, uint32_t mask );
- uint32_t readDSPControl( uint32_t *dspctl, uint32_t mask );
+// SIMD formats
+enum {
+ SIMD_FMT_L, // long word
+ SIMD_FMT_W, // word
+ SIMD_FMT_PH, // paired halfword
+ SIMD_FMT_QB, // quad byte
+ SIMD_NUM_FMTS
};
-#endif
+// DSPControl Fields
+enum {
+ DSP_POS, // insertion bitfield position
+ DSP_SCOUNT, // insertion bitfield size
+ DSP_C, // carry bit
+ DSP_OUFLAG, // overflow-underflow flag
+ DSP_CCOND, // condition code
+ DSP_EFI, // extract fail indicator bit
+ DSP_NUM_FIELDS
+};
+
+// compare instruction operations
+enum {
+ CMP_EQ, // equal
+ CMP_LT, // less than
+ CMP_LE // less than or equal
+};
+
+// SIMD operation order modes
+enum {
+ MODE_L, // left
+ MODE_R, // right
+ MODE_LA, // left-alternate
+ MODE_RA, // right-alternate
+ MODE_X // cross
+};
+
+// dsp operation parameters
+enum { UNSIGNED, SIGNED };
+enum { NOSATURATE, SATURATE };
+enum { NOROUND, ROUND };
+
+// DSPControl field positions and masks
+const uint32_t DSP_CTL_POS[DSP_NUM_FIELDS] = { 0, 7, 13, 16, 24, 14 };
+const uint32_t DSP_CTL_MASK[DSP_NUM_FIELDS] =
+{ 0x0000003f, 0x00001f80, 0x00002000,
+ 0x00ff0000, 0x0f000000, 0x00004000 };
+
+/*
+ * SIMD format constants
+ */
+
+// maximum values per register
+const uint32_t SIMD_MAX_VALS = 4;
+// number of values in fmt
+const uint32_t SIMD_NVALS[SIMD_NUM_FMTS] = { 1, 1, 2, 4 };
+// number of bits per value
+const uint32_t SIMD_NBITS[SIMD_NUM_FMTS] = { 64, 32, 16, 8 };
+// log2(bits per value)
+const uint32_t SIMD_LOG2N[SIMD_NUM_FMTS] = { 6, 5, 4, 3 };
+
+
+// DSP maximum values
+const uint64_t FIXED_L_SMAX = ULL(0x7fffffffffffffff);
+const uint64_t FIXED_W_SMAX = ULL(0x000000007fffffff);
+const uint64_t FIXED_H_SMAX = ULL(0x0000000000007fff);
+const uint64_t FIXED_B_SMAX = ULL(0x000000000000007f);
+const uint64_t FIXED_L_UMAX = ULL(0xffffffffffffffff);
+const uint64_t FIXED_W_UMAX = ULL(0x00000000ffffffff);
+const uint64_t FIXED_H_UMAX = ULL(0x000000000000ffff);
+const uint64_t FIXED_B_UMAX = ULL(0x00000000000000ff);
+const uint64_t FIXED_SMAX[SIMD_NUM_FMTS] =
+{ FIXED_L_SMAX, FIXED_W_SMAX, FIXED_H_SMAX, FIXED_B_SMAX };
+const uint64_t FIXED_UMAX[SIMD_NUM_FMTS] =
+{ FIXED_L_UMAX, FIXED_W_UMAX, FIXED_H_UMAX, FIXED_B_UMAX };
+
+// DSP minimum values
+const uint64_t FIXED_L_SMIN = ULL(0x8000000000000000);
+const uint64_t FIXED_W_SMIN = ULL(0xffffffff80000000);
+const uint64_t FIXED_H_SMIN = ULL(0xffffffffffff8000);
+const uint64_t FIXED_B_SMIN = ULL(0xffffffffffffff80);
+const uint64_t FIXED_L_UMIN = ULL(0x0000000000000000);
+const uint64_t FIXED_W_UMIN = ULL(0x0000000000000000);
+const uint64_t FIXED_H_UMIN = ULL(0x0000000000000000);
+const uint64_t FIXED_B_UMIN = ULL(0x0000000000000000);
+const uint64_t FIXED_SMIN[SIMD_NUM_FMTS] =
+{ FIXED_L_SMIN, FIXED_W_SMIN, FIXED_H_SMIN, FIXED_B_SMIN };
+const uint64_t FIXED_UMIN[SIMD_NUM_FMTS] =
+{ FIXED_L_UMIN, FIXED_W_UMIN, FIXED_H_UMIN, FIXED_B_UMIN };
+
+// DSP utility functions
+int32_t bitrev(int32_t value);
+uint64_t dspSaturate(uint64_t value, int32_t fmt, int32_t sign,
+ uint32_t *overflow);
+uint64_t checkOverflow(uint64_t value, int32_t fmt, int32_t sign,
+ uint32_t *overflow);
+uint64_t signExtend(uint64_t value, int32_t signpos);
+uint64_t addHalfLsb(uint64_t value, int32_t lsbpos);
+int32_t dspAbs(int32_t a, int32_t fmt, uint32_t *dspctl);
+int32_t dspAdd(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl);
+int32_t dspAddh(int32_t a, int32_t b, int32_t fmt, int32_t round,
+ int32_t sign);
+int32_t dspSub(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl);
+int32_t dspSubh(int32_t a, int32_t b, int32_t fmt, int32_t round,
+ int32_t sign);
+int32_t dspShll(int32_t a, uint32_t sa, int32_t fmt, int32_t saturate,
+ int32_t sign, uint32_t *dspctl);
+int32_t dspShrl(int32_t a, uint32_t sa, int32_t fmt, int32_t sign);
+int32_t dspShra(int32_t a, uint32_t sa, int32_t fmt, int32_t round,
+ int32_t sign, uint32_t *dspctl);
+int32_t dspMul(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ uint32_t *dspctl);
+int32_t dspMulq(int32_t a, int32_t b, int32_t fmt, int32_t saturate,
+ int32_t round, uint32_t *dspctl);
+int32_t dspMuleu(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl);
+int32_t dspMuleq(int32_t a, int32_t b, int32_t mode, uint32_t *dspctl);
+int64_t dspDpaq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode,
+ uint32_t *dspctl);
+int64_t dspDpsq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t infmt, int32_t outfmt, int32_t postsat, int32_t mode,
+ uint32_t *dspctl);
+int64_t dspDpa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt,
+ int32_t sign, int32_t mode);
+int64_t dspDps(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt,
+ int32_t sign, int32_t mode);
+int64_t dspMaq(int64_t dspac, int32_t a, int32_t b, int32_t ac,
+ int32_t fmt, int32_t mode, int32_t saturate, uint32_t *dspctl);
+int64_t dspMulsa(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt);
+int64_t dspMulsaq(int64_t dspac, int32_t a, int32_t b, int32_t ac, int32_t fmt,
+ uint32_t *dspctl);
+void dspCmp(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op,
+ uint32_t *dspctl);
+int32_t dspCmpg(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op);
+int32_t dspCmpgd(int32_t a, int32_t b, int32_t fmt, int32_t sign, int32_t op,
+ uint32_t *dspctl);
+int32_t dspPrece(int32_t a, int32_t infmt, int32_t insign, int32_t outfmt,
+ int32_t outsign, int32_t mode);
+int32_t dspPrecrqu(int32_t a, int32_t b, uint32_t *dspctl);
+int32_t dspPrecrq(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl);
+int32_t dspPrecrSra(int32_t a, int32_t b, int32_t sa, int32_t fmt,
+ int32_t round);
+int32_t dspPick(int32_t a, int32_t b, int32_t fmt, uint32_t *dspctl);
+int32_t dspPack(int32_t a, int32_t b, int32_t fmt);
+int32_t dspExtr(int64_t dspac, int32_t fmt, int32_t sa, int32_t round,
+ int32_t saturate, uint32_t *dspctl);
+int32_t dspExtp(int64_t dspac, int32_t size, uint32_t *dspctl);
+int32_t dspExtpd(int64_t dspac, int32_t size, uint32_t *dspctl);
+
+// SIMD pack/unpack utility functions
+void simdPack(uint64_t *values_ptr, int32_t *reg, int32_t fmt);
+void simdUnpack(int32_t reg, uint64_t *values_ptr, int32_t fmt, int32_t sign);
+
+// DSPControl r/w utility functions
+void writeDSPControl(uint32_t *dspctl, uint32_t value, uint32_t mask);
+uint32_t readDSPControl(uint32_t *dspctl, uint32_t mask);
+
+} /* namespace MipsISA */
+
+#endif // __ARCH_MIPS_DSP_HH__
diff --git a/src/arch/mips/idle_event.cc b/src/arch/mips/idle_event.cc
index d1d4f7c63..0aea08834 100644
--- a/src/arch/mips/idle_event.cc
+++ b/src/arch/mips/idle_event.cc
@@ -34,7 +34,7 @@
#include "arch/mips/kernel_stats.hh"
#include "cpu/thread_context.hh"
-using namespace TheISA;
+using namespace MipsISA;
void
IdleStartEvent::process(ThreadContext *tc)
diff --git a/src/arch/mips/interrupts.cc b/src/arch/mips/interrupts.cc
index c91ee1e99..99f96fafc 100755
--- a/src/arch/mips/interrupts.cc
+++ b/src/arch/mips/interrupts.cc
@@ -76,7 +76,7 @@ static inline void setCauseIP_(ThreadContext *tc, uint8_t val) {
intstatus &= ~(1 << int_num);
}
- void Interrupts::clear_all()
+ void Interrupts::clearAll()
{
DPRINTF(Interrupt, "Interrupts all cleared\n");
intstatus = 0;
@@ -156,12 +156,6 @@ static inline void setCauseIP_(ThreadContext *tc, uint8_t val) {
return false;
}
-
- uint64_t Interrupts::get_vec(int int_num)
- {
- panic("MipsISA::Interrupts::get_vec() is not implemented. \n");
- M5_DUMMY_RETURN
- }
*/
void Interrupts::post(int int_num, ThreadContext* tc)
{
@@ -195,14 +189,14 @@ void Interrupts::clear(int int_num, int index)
fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
}
-void Interrupts::clear_all(ThreadContext *tc)
+void Interrupts::clearAll(ThreadContext *tc)
{
DPRINTF(Interrupt, "Interrupts all cleared\n");
uint8_t intstatus = 0;
setCauseIP_(tc, intstatus);
}
-void Interrupts::clear_all()
+void Interrupts::clearAll()
{
fatal("Must use Thread COntext when clearing MIPS Interrupts in M5");
}
@@ -252,12 +246,6 @@ void Interrupts::updateIntrInfo(ThreadContext *tc) const
;
}
-uint64_t Interrupts::get_vec(int int_num)
-{
- panic("MipsISA::Interrupts::get_vec() is not implemented. \n");
- M5_DUMMY_RETURN
- }
-
bool Interrupts::interruptsPending(ThreadContext *tc) const
{
//if there is a on cpu timer interrupt (i.e. Compare == Count)
diff --git a/src/arch/mips/interrupts.hh b/src/arch/mips/interrupts.hh
index f0e928088..af71e4636 100755
--- a/src/arch/mips/interrupts.hh
+++ b/src/arch/mips/interrupts.hh
@@ -57,23 +57,23 @@ class Interrupts
// for posting an interrupt. It sets a bit
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
void post(int int_num, int index);
// clear(int int_num, int index) is responsible
// for clearing an interrupt. It clear a bit
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
void clear(int int_num, int index);
- // clear_all() is responsible
+ // clearAll() is responsible
// for clearing all interrupts. It clears all bits
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
- void clear_all();
+ void clearAll();
// getInterrupt(ThreadContext * tc) checks if an interrupt
// should be returned. It ands the interrupt mask and
@@ -91,9 +91,7 @@ class Interrupts
void updateIntrInfoCpuTimerIntr(ThreadContext *tc) const;
bool onCpuTimerInterrupt(ThreadContext *tc) const;
- uint64_t get_vec(int int_num);
-
- bool check_interrupts(ThreadContext * tc) const{
+ bool checkInterrupts(ThreadContext *tc) const {
//return (intstatus != 0) && !(tc->readPC() & 0x3);
if (oncputimerintr == false){
updateIntrInfo(tc);
@@ -121,7 +119,7 @@ class Interrupts
// for posting an interrupt. It sets a bit
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
void post(int int_num, ThreadContext* tc);
void post(int int_num, int index);
@@ -130,19 +128,19 @@ class Interrupts
// for clearing an interrupt. It clear a bit
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
void clear(int int_num, ThreadContext* tc);
void clear(int int_num, int index);
- // clear_all() is responsible
+ // clearAll() is responsible
// for clearing all interrupts. It clears all bits
// in intstatus corresponding to Cause IP*. The
// MIPS register Cause is updated by updateIntrInfo
- // which is called by check_interrupts
+ // which is called by checkInterrupts
//
- void clear_all(ThreadContext* tc);
- void clear_all();
+ void clearAll(ThreadContext* tc);
+ void clearAll();
// getInterrupt(ThreadContext * tc) checks if an interrupt
// should be returned. It ands the interrupt mask and
@@ -160,9 +158,9 @@ class Interrupts
bool interruptsPending(ThreadContext *tc) const;
bool onCpuTimerInterrupt(ThreadContext *tc) const;
- uint64_t get_vec(int int_num);
-
- bool check_interrupts(ThreadContext * tc) const{
+ bool
+ checkInterrupts(ThreadContext *tc) const
+ {
return interruptsPending(tc);
}
diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa
index b1cd03ca1..8af504e55 100644
--- a/src/arch/mips/isa/decoder.isa
+++ b/src/arch/mips/isa/decoder.isa
@@ -416,16 +416,16 @@ decode OPCODE_HI default Unknown::unknown() {
Ctrl_Base_DepTag);
break;
case 25:
- data = 0 | fcsr_val & 0xFE000000 >> 24
- | fcsr_val & 0x00800000 >> 23;
+ data = (fcsr_val & 0xFE000000 >> 24)
+ | (fcsr_val & 0x00800000 >> 23);
break;
case 26:
- data = 0 | fcsr_val & 0x0003F07C;
+ data = fcsr_val & 0x0003F07C;
break;
case 28:
- data = 0 | fcsr_val & 0x00000F80
- | fcsr_val & 0x01000000 >> 21
- | fcsr_val & 0x00000003;
+ data = (fcsr_val & 0x00000F80)
+ | (fcsr_val & 0x01000000 >> 21)
+ | (fcsr_val & 0x00000003);
break;
case 31:
data = fcsr_val;
@@ -603,7 +603,8 @@ decode OPCODE_HI default Unknown::unknown() {
0xA: rdpgpr({{
if(Config_AR >= 1)
{ // Rev 2 of the architecture
- Rd = xc->tcBase()->readIntReg(RT + NumIntRegs * SRSCtl_PSS);
+ panic("Shadow Sets Not Fully Implemented.\n");
+ //Rd = xc->tcBase()->readIntReg(RT + NumIntRegs * SRSCtl_PSS);
}
else
{
@@ -613,7 +614,8 @@ decode OPCODE_HI default Unknown::unknown() {
0xE: wrpgpr({{
if(Config_AR >= 1)
{ // Rev 2 of the architecture
- xc->tcBase()->setIntReg(RD + NumIntRegs * SRSCtl_PSS,Rt);
+ panic("Shadow Sets Not Fully Implemented.\n");
+ //xc->tcBase()->setIntReg(RD + NumIntRegs * SRSCtl_PSS,Rt);
// warn("Writing %d to %d, PSS: %d, SRS: %x\n",Rt,RD + NumIntRegs * SRSCtl_PSS, SRSCtl_PSS,SRSCtl);
}
else
@@ -1963,7 +1965,7 @@ decode OPCODE_HI default Unknown::unknown() {
0x0: decode OP_LO {
format IntOp {
0x0: append({{ Rt.uw = (Rt.uw << RD) | bits(Rs.uw,RD-1,0); }});
- 0x1: prepend({{ Rt.uw = (Rt.uw >> RD) | (bits(Rs.uw,RD-1,0) << 32-RD); }});
+ 0x1: prepend({{ Rt.uw = (Rt.uw >> RD) | (bits(Rs.uw, RD - 1, 0) << (32 - RD)); }});
}
}
0x2: decode OP_LO {
@@ -2050,11 +2052,11 @@ decode OPCODE_HI default Unknown::unknown() {
format LoadUnalignedMemory {
0x2: lwl({{ uint32_t mem_shift = 24 - (8 * byte_offset);
Rt.uw = mem_word << mem_shift |
- Rt.uw & mask(mem_shift);
+ (Rt.uw & mask(mem_shift));
}});
0x6: lwr({{ uint32_t mem_shift = 8 * byte_offset;
- Rt.uw = Rt.uw & (mask(mem_shift) << (32 - mem_shift)) |
- mem_word >> mem_shift;
+ Rt.uw = (Rt.uw & (mask(mem_shift) << (32 - mem_shift))) |
+ (mem_word >> mem_shift);
}});
}
}
@@ -2069,12 +2071,12 @@ decode OPCODE_HI default Unknown::unknown() {
format StoreUnalignedMemory {
0x2: swl({{ uint32_t reg_shift = 24 - (8 * byte_offset);
uint32_t mem_shift = 32 - reg_shift;
- mem_word = mem_word & (mask(reg_shift) << mem_shift) |
- Rt.uw >> reg_shift;
+ mem_word = (mem_word & (mask(reg_shift) << mem_shift)) |
+ (Rt.uw >> reg_shift);
}});
0x6: swr({{ uint32_t reg_shift = 8 * byte_offset;
mem_word = Rt.uw << reg_shift |
- mem_word & (mask(reg_shift));
+ (mem_word & (mask(reg_shift)));
}});
}
format CP0Control {
diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa
index f0210c29b..8596308e2 100644
--- a/src/arch/mips/isa/formats/mem.isa
+++ b/src/arch/mips/isa/formats/mem.isa
@@ -43,7 +43,7 @@ output header {{
protected:
/// Memory request flags. See mem_req_base.hh.
- unsigned memAccessFlags;
+ Request::Flags memAccessFlags;
/// Pointer to EAComp object.
const StaticInstPtr eaCompPtr;
/// Pointer to MemAcc object.
@@ -57,7 +57,7 @@ output header {{
StaticInstPtr _eaCompPtr = nullStaticInstPtr,
StaticInstPtr _memAccPtr = nullStaticInstPtr)
: MipsStaticInst(mnem, _machInst, __opClass),
- memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr),
+ eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr),
disp(sext<16>(OFFSET))
{
}
@@ -70,7 +70,7 @@ output header {{
const StaticInstPtr &eaCompInst() const { return eaCompPtr; }
const StaticInstPtr &memAccInst() const { return memAccPtr; }
- unsigned memAccFlags() { return memAccessFlags; }
+ Request::Flags memAccFlags() { return memAccessFlags; }
};
/**
diff --git a/src/arch/mips/isa/formats/mt.isa b/src/arch/mips/isa/formats/mt.isa
index 81fdc2898..1928ee903 100644
--- a/src/arch/mips/isa/formats/mt.isa
+++ b/src/arch/mips/isa/formats/mt.isa
@@ -196,7 +196,7 @@ def format MT_Control(code, *opt_flags) {{
def format MT_MFTR(code, *flags) {{
flags += ('IsNonSpeculative', )
-# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->getThreadNum() << \": Executing MT INST: ' + name + '\" << endl;\n' + code
+# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->threadId() << \": Executing MT INST: ' + name + '\" << endl;\n' + code
code += 'if (MT_H == 1) {\n'
code += 'data = bits(data, top_bit, bottom_bit);\n'
@@ -212,7 +212,7 @@ def format MT_MFTR(code, *flags) {{
def format MT_MTTR(code, *flags) {{
flags += ('IsNonSpeculative', )
-# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->getThreadNum() << \": Executing MT INST: ' + name + '\" << endl;\n' + code
+# code = 'std::cerr << curTick << \": T\" << xc->tcBase()->threadId() << \": Executing MT INST: ' + name + '\" << endl;\n' + code
iop = InstObjParams(name, Name, 'MTOp', code, flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa
index 0405aa5b3..f729cbf63 100644
--- a/src/arch/mips/isa/formats/util.isa
+++ b/src/arch/mips/isa/formats/util.isa
@@ -61,6 +61,7 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
inst_flags)
if mem_flags:
+ mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
s = '\n\tmemAccessFlags = ' + string.join(mem_flags, '|') + ';'
iop.constructor += s
memacc_iop.constructor += s
diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh
index fe28ad601..12c887132 100644
--- a/src/arch/mips/isa_traits.hh
+++ b/src/arch/mips/isa_traits.hh
@@ -147,11 +147,11 @@ namespace MipsISA
// MIPS modes
enum mode_type
{
- mode_kernel = 0, // kernel
- mode_supervisor = 1, // supervisor
- mode_user = 2, // user mode
+ mode_kernel = 0, // kernel
+ mode_supervisor = 1, // supervisor
+ mode_user = 2, // user mode
mode_debug = 3, // debug mode
- mode_number // number of modes
+ mode_number // number of modes
};
inline mode_type getOperatingMode(MiscReg Stat)
@@ -181,6 +181,8 @@ namespace MipsISA
const int NumIntRegs = NumIntArchRegs*NumShadowRegSets + NumIntSpecialRegs; //HI & LO Regs
const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;//
+ const int TotalArchRegs = NumIntArchRegs * NumShadowRegSets;
+
// Static instruction parameters
const int MaxInstSrcRegs = 10;
const int MaxInstDestRegs = 8;
@@ -188,13 +190,6 @@ namespace MipsISA
// semantically meaningful register indices
const int ZeroReg = 0;
const int AssemblerReg = 1;
- const int ReturnValueReg = 2;
- const int ReturnValueReg1 = 2;
- const int ReturnValueReg2 = 3;
- const int ArgumentReg0 = 4;
- const int ArgumentReg1 = 5;
- const int ArgumentReg2 = 6;
- const int ArgumentReg3 = 7;
const int KernelReg0 = 26;
const int KernelReg1 = 27;
const int GlobalPointerReg = 28;
@@ -202,14 +197,9 @@ namespace MipsISA
const int FramePointerReg = 30;
const int ReturnAddressReg = 31;
- const int ArgumentReg[] = {4, 5, 6, 7};
- const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
-
- const int SyscallNumReg = ReturnValueReg1;
- const int SyscallPseudoReturnReg = ReturnValueReg2;
- const int SyscallSuccessReg = ArgumentReg3;
+ const int SyscallPseudoReturnReg = 3;
- const int LogVMPageSize = 13; // 8K bytes
+ const int LogVMPageSize = 13; // 8K bytes
const int VMPageSize = (1 << LogVMPageSize);
const int BranchPredAddrShiftAmt = 2; // instructions are 4-byte aligned
@@ -391,6 +381,4 @@ namespace MipsISA
};
-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
index 4499107d7..8745731dc 100644
--- a/src/arch/mips/linux/linux.cc
+++ b/src/arch/mips/linux/linux.cc
@@ -35,34 +35,34 @@
// 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 },
+ { 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 },
+ { MipsLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
#endif
#ifdef _O_NOCTTY
- { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY },
+ { MipsLinux::TGT_O_NOCTTY, _O_NOCTTY },
#endif
#ifdef _O_SYNC
- { MipsLinux::TGT_O_SYNC, _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 },
+ { 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 },
+ { MipsLinux::TGT_O_SYNC, O_SYNC },
#endif
#endif /* _MSC_VER */
};
diff --git a/src/arch/mips/linux/linux.hh b/src/arch/mips/linux/linux.hh
index fcfaa18ea..aaeba0a42 100644
--- a/src/arch/mips/linux/linux.hh
+++ b/src/arch/mips/linux/linux.hh
@@ -32,9 +32,6 @@
#define __ARCH_MIPS_LINUX_LINUX_HH__
#include "kern/linux/linux.hh"
-#include <string>
-
-using std::string;
class MipsLinux : public Linux
{
@@ -49,21 +46,21 @@ class MipsLinux : public Linux
//@{
/// 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
+ 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().
@@ -72,12 +69,12 @@ class MipsLinux : public Linux
//@{
/// 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_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_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
//@}
//@{
@@ -94,15 +91,15 @@ class MipsLinux : public Linux
//@{
/// 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 = 0x540d;
- static const unsigned TIOCGETA = 0x7417;
+ 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_ = 0x540d;
+ static const unsigned TIOCGETA_ = 0x7417;
//@}
/// For table().
diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc
index 06e6e2cf4..24e71305a 100644
--- a/src/arch/mips/linux/process.cc
+++ b/src/arch/mips/linux/process.cc
@@ -51,7 +51,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename,"m5.eecs.umich.edu");
@@ -70,13 +70,13 @@ static SyscallReturn
sys_getsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
- // unsigned nbytes = tc->getSyscallArg(2);
+ unsigned op = process->getSyscallArg(tc, 0);
+ // unsigned nbytes = process->getSyscallArg(tc, 2);
switch (op) {
case 45: { // GSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1));
// I don't think this exactly matches the HW FPCR
*fpcr = 0;
fpcr.copyOut(tc->getMemPort());
@@ -97,13 +97,13 @@ static SyscallReturn
sys_setsysinfoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned op = tc->getSyscallArg(0);
- // unsigned nbytes = tc->getSyscallArg(2);
+ unsigned op = process->getSyscallArg(tc, 0);
+ // unsigned nbytes = process->getSyscallArg(tc, 2);
switch (op) {
case 14: { // SSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(process->getSyscallArg(tc, 1));
// I don't think this exactly matches the HW FPCR
fpcr.copyIn(tc->getMemPort());
DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): "
@@ -138,7 +138,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>),
/* 16 */ SyscallDesc("lchown", chownFunc),
- /* 17 */ SyscallDesc("break", obreakFunc),
+ /* 17 */ SyscallDesc("break", brkFunc),
/* 18 */ SyscallDesc("unused#18", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -160,13 +160,13 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 36 */ SyscallDesc("sync", unimplementedFunc),
/* 37 */ SyscallDesc("kill", unimplementedFunc),
/* 38 */ SyscallDesc("rename", unimplementedFunc),
- /* 39 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 39 */ SyscallDesc("mkdir", mkdirFunc),
/* 40 */ SyscallDesc("rmdir", unimplementedFunc),
/* 41 */ SyscallDesc("dup", unimplementedFunc),
/* 42 */ SyscallDesc("pipe", pipePseudoFunc),
/* 43 */ SyscallDesc("times", unimplementedFunc),
/* 44 */ SyscallDesc("prof", unimplementedFunc),
- /* 45 */ SyscallDesc("brk", obreakFunc),
+ /* 45 */ SyscallDesc("brk", brkFunc),
/* 46 */ SyscallDesc("setgid", unimplementedFunc),
/* 47 */ SyscallDesc("getgid", getgidFunc),
/* 48 */ SyscallDesc("signal", ignoreFunc),
@@ -175,13 +175,13 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 51 */ SyscallDesc("acct", unimplementedFunc),
/* 52 */ SyscallDesc("umount2", unimplementedFunc),
/* 53 */ SyscallDesc("lock", unimplementedFunc),
- /* 54 */ SyscallDesc("ioctl", unimplementedFunc/*ioctlFunc<MipsLinux>*/),
+ /* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>),
/* 55 */ SyscallDesc("fcntl", fcntlFunc),
/* 56 */ SyscallDesc("mpx", unimplementedFunc),
/* 57 */ SyscallDesc("setpgid", unimplementedFunc),
/* 58 */ SyscallDesc("ulimit", unimplementedFunc),
/* 59 */ SyscallDesc("unused#59", unimplementedFunc),
- /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", umaskFunc),
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
/* 62 */ SyscallDesc("ustat", unimplementedFunc),
/* 63 */ SyscallDesc("dup2", unimplementedFunc),
@@ -206,7 +206,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 82 */ SyscallDesc("reserved#82", unimplementedFunc),
/* 83 */ SyscallDesc("symlink", unimplementedFunc),
/* 84 */ SyscallDesc("unused#84", unimplementedFunc),
- /* 85 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 85 */ SyscallDesc("readlink", readlinkFunc),
/* 86 */ SyscallDesc("uselib", unimplementedFunc),
/* 87 */ SyscallDesc("swapon", gethostnameFunc),
/* 88 */ SyscallDesc("reboot", unimplementedFunc),
@@ -288,7 +288,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 164 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
/* 165 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
/* 166 */ SyscallDesc("nanosleep", unimplementedFunc),
- /* 167 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 167 */ SyscallDesc("mremap", mremapFunc<MipsLinux>),
/* 168 */ SyscallDesc("accept", unimplementedFunc),
/* 169 */ SyscallDesc("bind", unimplementedFunc),
/* 170 */ SyscallDesc("connect", unimplementedFunc),
@@ -324,7 +324,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 200 */ SyscallDesc("pread64", unimplementedFunc),
/* 201 */ SyscallDesc("pwrite64", unimplementedFunc),
/* 202 */ SyscallDesc("chown", unimplementedFunc),
- /* 203 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 203 */ SyscallDesc("getcwd", getcwdFunc),
/* 204 */ SyscallDesc("capget", unimplementedFunc),
/* 205 */ SyscallDesc("capset", unimplementedFunc),
/* 206 */ SyscallDesc("sigalstack", unimplementedFunc),
@@ -425,7 +425,7 @@ 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)
+ 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/system.cc b/src/arch/mips/linux/system.cc
index bed863e9d..23062c96b 100644
--- a/src/arch/mips/linux/system.cc
+++ b/src/arch/mips/linux/system.cc
@@ -168,7 +168,6 @@ LinuxMipsSystem::setDelayLoop(ThreadContext *tc)
vp = tc->getVirtPort();
vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988));
- tc->delVirtPort(vp);
}
}
diff --git a/src/arch/mips/linux/system.hh b/src/arch/mips/linux/system.hh
index 24fb604ed..984f74694 100644
--- a/src/arch/mips/linux/system.hh
+++ b/src/arch/mips/linux/system.hh
@@ -43,9 +43,6 @@ class IdleStartEvent;
#include "kern/linux/events.hh"
#include "params/LinuxMipsSystem.hh"
-using namespace MipsISA;
-using namespace Linux;
-
/**
* This class contains linux specific system code (Loading, Events).
* It points to objects that are the system binaries to load and patches them
@@ -112,7 +109,7 @@ class LinuxMipsSystem : public MipsSystem
* PC based event to skip the dprink() call and emulate its
* functionality
*/
- DebugPrintkEvent *debugPrintkEvent;
+ Linux::DebugPrintkEvent *debugPrintkEvent;
/**
* Skip calculate_delay_loop() rather than waiting for this to be
diff --git a/src/arch/mips/linux/threadinfo.hh b/src/arch/mips/linux/threadinfo.hh
index 25ee74dd3..b0d0cd811 100644
--- a/src/arch/mips/linux/threadinfo.hh
+++ b/src/arch/mips/linux/threadinfo.hh
@@ -55,7 +55,7 @@ class ThreadInfo
CopyOut(tc, &data, addr, sizeof(T));
- data = TheISA::gtoh(data);
+ data = MipsISA::gtoh(data);
return true;
}
@@ -77,7 +77,7 @@ class ThreadInfo
Addr sp;
if (!addr)
- addr = tc->readMiscRegNoEffect(0/*TheISA::IPR_PALtemp23*/);
+ addr = tc->readMiscRegNoEffect(0/*MipsISA::IPR_PALtemp23*/);
FunctionalPort *p = tc->getPhysPort();
p->readBlob(addr, (uint8_t *)&sp, sizeof(Addr));
diff --git a/src/arch/mips/locked_mem.hh b/src/arch/mips/locked_mem.hh
index 34da79ed9..021b8cf73 100644
--- a/src/arch/mips/locked_mem.hh
+++ b/src/arch/mips/locked_mem.hh
@@ -49,11 +49,10 @@ template <class XC>
inline void
handleLockedRead(XC *xc, Request *req)
{
- unsigned tid = req->getThreadNum();
- xc->setMiscRegNoEffect(LLAddr, req->getPaddr() & ~0xf, tid);
- xc->setMiscRegNoEffect(LLFlag, true, tid);
+ xc->setMiscRegNoEffect(LLAddr, req->getPaddr() & ~0xf);
+ xc->setMiscRegNoEffect(LLFlag, true);
DPRINTF(LLSC, "[tid:%i]: Load-Link Flag Set & Load-Link Address set to %x.\n",
- tid, req->getPaddr() & ~0xf);
+ req->threadId(), req->getPaddr() & ~0xf);
}
@@ -61,22 +60,20 @@ template <class XC>
inline bool
handleLockedWrite(XC *xc, Request *req)
{
- unsigned tid = req->getThreadNum();
-
if (req->isUncacheable()) {
// Funky Turbolaser mailbox access...don't update
// result register (see stq_c in decoder.isa)
req->setExtraData(2);
} else {
// standard store conditional
- bool lock_flag = xc->readMiscRegNoEffect(LLFlag, tid);
- Addr lock_addr = xc->readMiscRegNoEffect(LLAddr, tid);
+ bool lock_flag = xc->readMiscRegNoEffect(LLFlag);
+ Addr lock_addr = xc->readMiscRegNoEffect(LLAddr);
if (!lock_flag || (req->getPaddr() & ~0xf) != lock_addr) {
// Lock flag not set or addr mismatch in CPU;
// don't even bother sending to memory system
req->setExtraData(0);
- xc->setMiscRegNoEffect(LLFlag, false, tid);
+ xc->setMiscRegNoEffect(LLFlag, false);
// the rest of this code is not architectural;
// it's just a debugging aid to help detect
@@ -86,9 +83,9 @@ handleLockedWrite(XC *xc, Request *req)
stCondFailures++;
xc->setStCondFailures(stCondFailures);
if (stCondFailures % 10 == 0) {
- warn("%i: cpu %d: %d consecutive "
+ warn("%i: context %d: %d consecutive "
"store conditional failures\n",
- curTick, xc->readCpuId(), stCondFailures);
+ curTick, xc->contextId(), stCondFailures);
}
if (stCondFailures == 5000) {
@@ -97,10 +94,10 @@ handleLockedWrite(XC *xc, Request *req)
if (!lock_flag){
DPRINTF(LLSC, "[tid:%i]: Lock Flag Set, Store Conditional Failed.\n",
- tid);
+ req->threadId());
} else if ((req->getPaddr() & ~0xf) != lock_addr) {
DPRINTF(LLSC, "[tid:%i]: Load-Link Address Mismatch, Store Conditional Failed.\n",
- tid);
+ req->threadId());
}
// store conditional failed already, so don't issue it to mem
return false;
diff --git a/src/arch/mips/microcode_rom.hh b/src/arch/mips/microcode_rom.hh
new file mode 100644
index 000000000..a5be81e2a
--- /dev/null
+++ b/src/arch/mips/microcode_rom.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_MIPS_MICROCODE_ROM_HH__
+#define __ARCH_MIPS_MICROCODE_ROM_HH__
+
+#include "sim/microcode_rom.hh"
+
+namespace MipsISA
+{
+ using ::MicrocodeRom;
+}
+
+#endif // __ARCH_MIPS_MICROCODE_ROM_HH__
diff --git a/src/arch/mips/mips_core_specific.cc b/src/arch/mips/mips_core_specific.cc
index a17ebcdf3..80d856b0c 100755
--- a/src/arch/mips/mips_core_specific.cc
+++ b/src/arch/mips/mips_core_specific.cc
@@ -113,13 +113,13 @@ MipsISA::processInterrupts(CPU *cpu)
/*int
MipsISA::MiscRegFile::getInstAsid()
{
- return EV5::ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
+ return AlphaISA::ITB_ASN_ASN(ipr[IPR_ITB_ASN]);
}
int
MipsISA::MiscRegFile::getDataAsid()
{
- return EV5::DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
+ return AlphaISA::DTB_ASN_ASN(ipr[IPR_DTB_ASN]);
}*/
diff --git a/src/arch/mips/mt.hh b/src/arch/mips/mt.hh
index 6765c27a9..d0c333d86 100755
--- a/src/arch/mips/mt.hh
+++ b/src/arch/mips/mt.hh
@@ -45,7 +45,6 @@
#include "base/misc.hh"
#include <iostream>
-using namespace std;
namespace MipsISA
{
@@ -78,7 +77,7 @@ haltThread(TC *tc)
// @TODO: Needs to check if this is a branch and if so, take previous instruction
tc->setMiscReg(TCRestart, tc->readNextPC());
- warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->getThreadNum(), tc->getCpuPtr()->name(),
+ warn("%i: Halting thread %i in %s @ PC %x, setting restart PC to %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
tc->readPC(), tc->readNextPC());
}
}
@@ -98,7 +97,7 @@ restoreThread(TC *tc)
tc->setNextNPC(pc + 8);
tc->activate(0);
- warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->getThreadNum(), tc->getCpuPtr()->name(),
+ warn("%i: Restoring thread %i in %s @ PC %x", curTick, tc->threadId(), tc->getCpuPtr()->name(),
tc->readPC());
}
}
@@ -164,7 +163,7 @@ forkThread(TC *tc, Fault &fault, int Rd_bits, int Rs, int Rt)
success = 1;
}
} else {
- std::cerr << "Bad VPEs" << endl;
+ std::cerr << "Bad VPEs" << std::endl;
}
}
@@ -217,10 +216,10 @@ yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
if (ok == 1) {
unsigned tcstatus = tc->readMiscRegNoEffect(TCStatus);
tc->setMiscReg(TCStatus, insertBits(tcstatus, TCS_A, TCS_A, 0));
- warn("%i: Deactivating Hardware Thread Context #%i", curTick, tc->getThreadNum());
+ warn("%i: Deactivating Hardware Thread Context #%i", curTick, tc->threadId());
}
} else if (src_reg > 0) {
- if (src_reg & !yield_mask != 0) {
+ if (src_reg && !yield_mask != 0) {
unsigned vpe_control = tc->readMiscReg(VPEControl);
tc->setMiscReg(VPEControl, insertBits(vpe_control, VPEC_EXCPT_HI, VPEC_EXCPT_LO, 2));
fault = new ThreadFault();
@@ -238,7 +237,7 @@ yieldThread(TC *tc, Fault &fault, int src_reg, uint32_t yield_mask)
fault = new ThreadFault();
} else {
//tc->ScheduleOtherThreads();
- //std::cerr << "T" << tc->getThreadNum() << "YIELD: Schedule Other Threads.\n" << std::endl;
+ //std::cerr << "T" << tc->threadId() << "YIELD: Schedule Other Threads.\n" << std::endl;
//tc->suspend();
// Save last known PC in TCRestart
// @TODO: Needs to check if this is a branch and if so, take previous instruction
diff --git a/src/arch/mips/pagetable.hh b/src/arch/mips/pagetable.hh
index 8c43a7b0c..bbed94194 100755
--- a/src/arch/mips/pagetable.hh
+++ b/src/arch/mips/pagetable.hh
@@ -59,9 +59,9 @@ namespace MipsISA {
Addr level3() const
{ return MipsISA::PteAddr(addr >> PageShift); }
Addr level2() const
- { return MipsISA::PteAddr(addr >> NPtePageShift + PageShift); }
+ { return MipsISA::PteAddr(addr >> (NPtePageShift + PageShift)); }
Addr level1() const
- { return MipsISA::PteAddr(addr >> 2 * NPtePageShift + PageShift); }
+ { return MipsISA::PteAddr(addr >> (2 * NPtePageShift + PageShift)); }
};
// ITB/DTB page table entry
diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
index b7bd22d78..784ddfe33 100644
--- a/src/arch/mips/process.cc
+++ b/src/arch/mips/process.cc
@@ -40,6 +40,10 @@
using namespace std;
using namespace MipsISA;
+static const int SyscallSuccessReg = 7;
+static const int FirstArgumentReg = 4;
+static const int ReturnValueReg = 2;
+
MipsLiveProcess::MipsLiveProcess(LiveProcessParams * params,
ObjectFile *objFile)
: LiveProcess(params, objFile)
@@ -64,3 +68,33 @@ MipsLiveProcess::startup()
{
argsInit(MachineBytes, VMPageSize);
}
+
+MipsISA::IntReg
+MipsLiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < 6);
+ return tc->readIntReg(FirstArgumentReg + i);
+}
+
+void
+MipsLiveProcess::setSyscallArg(ThreadContext *tc,
+ int i, MipsISA::IntReg val)
+{
+ assert(i < 6);
+ tc->setIntReg(FirstArgumentReg + i, val);
+}
+
+void
+MipsLiveProcess::setSyscallReturn(ThreadContext *tc,
+ SyscallReturn return_value)
+{
+ if (return_value.successful()) {
+ // no error
+ tc->setIntReg(SyscallSuccessReg, 0);
+ tc->setIntReg(ReturnValueReg, return_value.value());
+ } else {
+ // got an error, return details
+ tc->setIntReg(SyscallSuccessReg, (IntReg) -1);
+ tc->setIntReg(ReturnValueReg, -return_value.value());
+ }
+}
diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh
index 18bf289b8..87c62330f 100644
--- a/src/arch/mips/process.hh
+++ b/src/arch/mips/process.hh
@@ -47,6 +47,10 @@ class MipsLiveProcess : public LiveProcess
virtual void startup();
+ public:
+ MipsISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, MipsISA::IntReg val);
+ void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
};
diff --git a/src/arch/mips/regfile.cc b/src/arch/mips/regfile.cc
index 0c670af6d..663115bb6 100644
--- a/src/arch/mips/regfile.cc
+++ b/src/arch/mips/regfile.cc
@@ -188,12 +188,6 @@ RegFile::unserialize(Checkpoint *cp, const std::string &section)
}
-
-void RegFile::changeContext(RegContextParam param, RegContextVal val)
-{
- panic("Change Context Not Implemented for MipsISA");
-}
-
static inline int flattenIntIndex(ThreadContext * tc, int reg)
{
return reg;
@@ -206,12 +200,6 @@ MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest)
}
void
-MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest);
-{
- panic("Copy Regs Not Implemented Yet\n");
-}
-
-void
MipsISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
{
panic("Copy Misc. Regs Not Implemented Yet\n");
diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh
index 1537855df..0c0ecc7eb 100644
--- a/src/arch/mips/regfile/float_regfile.hh
+++ b/src/arch/mips/regfile/float_regfile.hh
@@ -44,11 +44,6 @@ class Checkpoint;
namespace MipsISA
{
- static inline std::string getFloatRegName(RegIndex)
- {
- return "";
- }
-
const uint32_t MIPS32_QNAN = 0x7fbfffff;
const uint64_t MIPS64_QNAN = ULL(0x7fbfffffffffffff);
diff --git a/src/arch/mips/regfile/int_regfile.cc b/src/arch/mips/regfile/int_regfile.cc
index c46ecf0b3..88de4be94 100644
--- a/src/arch/mips/regfile/int_regfile.cc
+++ b/src/arch/mips/regfile/int_regfile.cc
@@ -37,7 +37,6 @@
using namespace MipsISA;
using namespace std;
-
void
IntRegFile::clear()
{
@@ -45,29 +44,33 @@ IntRegFile::clear()
currShadowSet=0;
}
+int
+IntRegFile::readShadowSet()
+{
+ return currShadowSet;
+}
+
void
IntRegFile::setShadowSet(int css)
{
- DPRINTF(MipsPRA,"Setting Shadow Set to :%d (%s)\n",css,currShadowSet);
+ DPRINTF(MipsPRA, "Setting Shadow Set to :%d (%s)\n", css, currShadowSet);
currShadowSet = css;
}
IntReg
IntRegFile::readReg(int intReg)
{
- if(intReg < NumIntRegs)
- { // Regular GPR Read
- DPRINTF(MipsPRA,"Reading Reg: %d, CurrShadowSet: %d\n",intReg,currShadowSet);
- if(intReg >= NumIntArchRegs*NumShadowRegSets){
- return regs[intReg+NumIntRegs*currShadowSet];
- }
- else {
- return regs[(intReg + NumIntArchRegs*currShadowSet) % NumIntArchRegs];
- }
- }
- else
- { // Read from shadow GPR .. probably called by RDPGPR
- return regs[intReg];
+ if (intReg < NumIntArchRegs) {
+ // Regular GPR Read
+ DPRINTF(MipsPRA, "Reading Reg: %d, CurrShadowSet: %d\n", intReg,
+ currShadowSet);
+
+ return regs[intReg + NumIntArchRegs * currShadowSet];
+ } else {
+ unsigned special_reg_num = intReg - NumIntArchRegs;
+
+ // Read A Special Reg
+ return regs[TotalArchRegs + special_reg_num];
}
}
@@ -75,20 +78,15 @@ Fault
IntRegFile::setReg(int intReg, const IntReg &val)
{
if (intReg != ZeroReg) {
+ if (intReg < NumIntArchRegs) {
+ regs[intReg + NumIntArchRegs * currShadowSet] = val;
+ } else {
+ unsigned special_reg_num = intReg - NumIntArchRegs;
- if(intReg < NumIntRegs)
- {
- if(intReg >= NumIntArchRegs*NumShadowRegSets){
- regs[intReg] = val;
- }
- else{
- regs[intReg+NumIntRegs*currShadowSet] = val;
- }
- }
- else{
- regs[intReg] = val;
+ regs[TotalArchRegs + special_reg_num] = val;
}
}
+
return NoFault;
}
@@ -103,4 +101,3 @@ IntRegFile::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(regs, NumIntRegs);
}
-
diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh
index 8ddd276e6..c5a6bb345 100644
--- a/src/arch/mips/regfile/int_regfile.hh
+++ b/src/arch/mips/regfile/int_regfile.hh
@@ -42,13 +42,8 @@ class Checkpoint;
namespace MipsISA
{
- static inline std::string getIntRegName(RegIndex)
- {
- return "";
- }
-
enum MiscIntRegNums {
- LO = NumIntArchRegs*NumShadowRegSets,
+ LO = NumIntArchRegs,
HI,
DSPACX0,
DSPLo1,
@@ -72,6 +67,7 @@ namespace MipsISA
int currShadowSet;
public:
void clear();
+ int readShadowSet();
void setShadowSet(int css);
IntReg readReg(int intReg);
Fault setReg(int intReg, const IntReg &val);
diff --git a/src/arch/mips/regfile/misc_regfile.cc b/src/arch/mips/regfile/misc_regfile.cc
index dc6ae0baf..a00bf166e 100755..100644
--- a/src/arch/mips/regfile/misc_regfile.cc
+++ b/src/arch/mips/regfile/misc_regfile.cc
@@ -40,42 +40,55 @@
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
+//#include "params/DerivO3CPU.hh"
+
using namespace std;
+using namespace MipsISA;
std::string MiscRegFile::miscRegNames[NumMiscRegs] =
-{"Index", "MVPControl", "MVPConf0", "MVPConf1", "", "", "", "",
- "Random", "VPEControl", "VPEConf0", "VPEConf1", "YQMask", "VPESchedule", "VPEScheFBack", "VPEOpt",
- "EntryLo0", "TCStatus", "TCBind", "TCRestart", "TCHalt", "TCContext", "TCSchedule", "TCScheFBack",
- "EntryLo1", "", "", "", "", "", "", "",
- "Context", "ContextConfig", "", "", "", "", "", "",
- "PageMask", "PageGrain", "", "", "", "", "", "",
- "Wired", "SRSConf0", "SRCConf1", "SRSConf2", "SRSConf3", "SRSConf4", "", "",
- "HWREna", "", "", "", "", "", "", "",
- "BadVAddr", "", "", "", "", "", "", "",
- "Count", "", "", "", "", "", "", "",
- "EntryHi", "", "", "", "", "", "", "",
- "Compare", "", "", "", "", "", "", "",
- "Status", "IntCtl", "SRSCtl", "SRSMap", "", "", "", "",
- "Cause", "", "", "", "", "", "", "",
- "EPC", "", "", "", "", "", "", "",
- "PRId", "EBase", "", "", "", "", "", "",
- "Config", "Config1", "Config2", "Config3", "", "", "", "",
- "LLAddr", "", "", "", "", "", "", "",
- "WatchLo0", "WatchLo1", "WatchLo2", "WatchLo3", "WatchLo4", "WatchLo5", "WatchLo6", "WatchLo7",
- "WatchHi0", "WatchHi1", "WatchHi2", "WatchHi3", "WatchHi4", "WatchHi5", "WatchHi6", "WatchHi7",
- "XCContext64", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
- "", "", "", "", "", "", "", "",
- "Debug", "TraceControl1", "TraceControl2", "UserTraceData", "TraceBPC", "", "", "",
- "DEPC", "", "", "", "", "", "", "",
- "PerfCnt0", "PerfCnt1", "PerfCnt2", "PerfCnt3", "PerfCnt4", "PerfCnt5", "PerfCnt6", "PerfCnt7",
- "ErrCtl", "", "", "", "", "", "", "",
- "CacheErr0", "CacheErr1", "CacheErr2", "CacheErr3", "", "", "", "",
- "TagLo0", "DataLo1", "TagLo2", "DataLo3", "TagLo4", "DataLo5", "TagLo6", "DataLo7",
- "TagHi0", "DataHi1", "TagHi2", "DataHi3", "TagHi4", "DataHi5", "TagHi6", "DataHi7",
- "ErrorEPC", "", "", "", "", "", "", "",
- "DESAVE", "", "", "", "", "", "", "",
- "LLFlag"
+{
+ "Index", "MVPControl", "MVPConf0", "MVPConf1", "", "", "", "",
+ "Random", "VPEControl", "VPEConf0", "VPEConf1",
+ "YQMask", "VPESchedule", "VPEScheFBack", "VPEOpt",
+ "EntryLo0", "TCStatus", "TCBind", "TCRestart",
+ "TCHalt", "TCContext", "TCSchedule", "TCScheFBack",
+ "EntryLo1", "", "", "", "", "", "", "",
+ "Context", "ContextConfig", "", "", "", "", "", "",
+ "PageMask", "PageGrain", "", "", "", "", "", "",
+ "Wired", "SRSConf0", "SRCConf1", "SRSConf2",
+ "SRSConf3", "SRSConf4", "", "",
+ "HWREna", "", "", "", "", "", "", "",
+ "BadVAddr", "", "", "", "", "", "", "",
+ "Count", "", "", "", "", "", "", "",
+ "EntryHi", "", "", "", "", "", "", "",
+ "Compare", "", "", "", "", "", "", "",
+ "Status", "IntCtl", "SRSCtl", "SRSMap", "", "", "", "",
+ "Cause", "", "", "", "", "", "", "",
+ "EPC", "", "", "", "", "", "", "",
+ "PRId", "EBase", "", "", "", "", "", "",
+ "Config", "Config1", "Config2", "Config3", "", "", "", "",
+ "LLAddr", "", "", "", "", "", "", "",
+ "WatchLo0", "WatchLo1", "WatchLo2", "WatchLo3",
+ "WatchLo4", "WatchLo5", "WatchLo6", "WatchLo7",
+ "WatchHi0", "WatchHi1", "WatchHi2", "WatchHi3",
+ "WatchHi4", "WatchHi5", "WatchHi6", "WatchHi7",
+ "XCContext64", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "",
+ "Debug", "TraceControl1", "TraceControl2", "UserTraceData",
+ "TraceBPC", "", "", "",
+ "DEPC", "", "", "", "", "", "", "",
+ "PerfCnt0", "PerfCnt1", "PerfCnt2", "PerfCnt3",
+ "PerfCnt4", "PerfCnt5", "PerfCnt6", "PerfCnt7",
+ "ErrCtl", "", "", "", "", "", "", "",
+ "CacheErr0", "CacheErr1", "CacheErr2", "CacheErr3", "", "", "", "",
+ "TagLo0", "DataLo1", "TagLo2", "DataLo3",
+ "TagLo4", "DataLo5", "TagLo6", "DataLo7",
+ "TagHi0", "DataHi1", "TagHi2", "DataHi3",
+ "TagHi4", "DataHi5", "TagHi6", "DataHi7",
+ "ErrorEPC", "", "", "", "", "", "", "",
+ "DESAVE", "", "", "", "", "", "", "",
+ "LLFlag"
};
MiscRegFile::MiscRegFile()
@@ -170,11 +183,12 @@ void
MiscRegFile::reset(std::string core_name, unsigned num_threads,
unsigned num_vpes, BaseCPU *_cpu)
{
-
DPRINTF(MipsPRA, "Resetting CP0 State with %i TCs and %i VPEs\n",
num_threads, num_vpes);
cpu = _cpu;
- const BaseCPU::Params *p = _cpu->params;
+
+ MipsISA::CoreSpecific &cp = cpu->coreParams;
+
// Do Default CP0 initialization HERE
// Do Initialization for MT cores here (eventually use
@@ -183,10 +197,10 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
DPRINTF(MipsPRA, "Initializing CP0 State.... ");
MiscReg ProcID = readRegNoEffect(PRId);
- replaceBits(ProcID,PRIdCoOp_HI,PRIdCoOp_LO,p->coreParams.CP0_PRId_CompanyOptions);
- replaceBits(ProcID,PRIdCoID_HI,PRIdCoID_LO,p->coreParams.CP0_PRId_CompanyID);
- replaceBits(ProcID,PRIdProc_ID_HI,PRIdProc_ID_LO,p->coreParams.CP0_PRId_ProcessorID);
- replaceBits(ProcID,PRIdRev_HI,PRIdRev_LO,p->coreParams.CP0_PRId_Revision);
+ replaceBits(ProcID,PRIdCoOp_HI,PRIdCoOp_LO,cp.CP0_PRId_CompanyOptions);
+ replaceBits(ProcID,PRIdCoID_HI,PRIdCoID_LO,cp.CP0_PRId_CompanyID);
+ replaceBits(ProcID,PRIdProc_ID_HI,PRIdProc_ID_LO,cp.CP0_PRId_ProcessorID);
+ replaceBits(ProcID,PRIdRev_HI,PRIdRev_LO,cp.CP0_PRId_Revision);
setRegNoEffect(PRId,ProcID);
// Now, create Write Mask for ProcID register
MiscReg ProcID_Mask = 0; // Read-Only register
@@ -195,11 +209,11 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Config
MiscReg cfg = readRegNoEffect(Config);
- replaceBits(cfg, Config_BE_HI, Config_BE_LO, p->coreParams.CP0_Config_BE);
- replaceBits(cfg, Config_AT_HI, Config_AT_LO, p->coreParams.CP0_Config_AT);
- replaceBits(cfg, Config_AR_HI, Config_AR_LO, p->coreParams.CP0_Config_AR);
- replaceBits(cfg, Config_MT_HI, Config_MT_LO, p->coreParams.CP0_Config_MT);
- replaceBits(cfg, Config_VI_HI, Config_VI_LO, p->coreParams.CP0_Config_VI);
+ replaceBits(cfg, Config_BE_HI, Config_BE_LO, cp.CP0_Config_BE);
+ replaceBits(cfg, Config_AT_HI, Config_AT_LO, cp.CP0_Config_AT);
+ replaceBits(cfg, Config_AR_HI, Config_AR_LO, cp.CP0_Config_AR);
+ replaceBits(cfg, Config_MT_HI, Config_MT_LO, cp.CP0_Config_MT);
+ replaceBits(cfg, Config_VI_HI, Config_VI_LO, cp.CP0_Config_VI);
replaceBits(cfg, Config_M, 1);
setRegNoEffect(Config, cfg);
// Now, create Write Mask for Config register
@@ -209,20 +223,21 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Config1
MiscReg cfg1 = readRegNoEffect(Config1);
- replaceBits(cfg1, Config1_MMUSize_HI, Config1_MMUSize_LO, p->coreParams.CP0_Config1_MMU);
- replaceBits(cfg1, Config1_IS_HI, Config1_IS_LO, p->coreParams.CP0_Config1_IS);
- replaceBits(cfg1, Config1_IL_HI, Config1_IL_LO, p->coreParams.CP0_Config1_IL);
- replaceBits(cfg1, Config1_IA_HI, Config1_IA_LO, p->coreParams.CP0_Config1_IA);
- replaceBits(cfg1, Config1_DS_HI, Config1_DS_LO, p->coreParams.CP0_Config1_DS);
- replaceBits(cfg1, Config1_DL_HI, Config1_DL_LO, p->coreParams.CP0_Config1_DL);
- replaceBits(cfg1, Config1_DA_HI, Config1_DA_LO, p->coreParams.CP0_Config1_DA);
- replaceBits(cfg1, Config1_FP_HI, Config1_FP_LO, p->coreParams.CP0_Config1_FP);
- replaceBits(cfg1, Config1_EP_HI, Config1_EP_LO, p->coreParams.CP0_Config1_EP);
- replaceBits(cfg1, Config1_WR_HI, Config1_WR_LO, p->coreParams.CP0_Config1_WR);
- replaceBits(cfg1, Config1_MD_HI, Config1_MD_LO, p->coreParams.CP0_Config1_MD);
- replaceBits(cfg1, Config1_C2_HI, Config1_C2_LO, p->coreParams.CP0_Config1_C2);
- replaceBits(cfg1, Config1_PC_HI, Config1_PC_LO, p->coreParams.CP0_Config1_PC);
- replaceBits(cfg1, Config1_M, p->coreParams.CP0_Config1_M);
+ replaceBits(cfg1, Config1_MMUSize_HI, Config1_MMUSize_LO,
+ cp.CP0_Config1_MMU);
+ replaceBits(cfg1, Config1_IS_HI, Config1_IS_LO, cp.CP0_Config1_IS);
+ replaceBits(cfg1, Config1_IL_HI, Config1_IL_LO, cp.CP0_Config1_IL);
+ replaceBits(cfg1, Config1_IA_HI, Config1_IA_LO, cp.CP0_Config1_IA);
+ replaceBits(cfg1, Config1_DS_HI, Config1_DS_LO, cp.CP0_Config1_DS);
+ replaceBits(cfg1, Config1_DL_HI, Config1_DL_LO, cp.CP0_Config1_DL);
+ replaceBits(cfg1, Config1_DA_HI, Config1_DA_LO, cp.CP0_Config1_DA);
+ replaceBits(cfg1, Config1_FP_HI, Config1_FP_LO, cp.CP0_Config1_FP);
+ replaceBits(cfg1, Config1_EP_HI, Config1_EP_LO, cp.CP0_Config1_EP);
+ replaceBits(cfg1, Config1_WR_HI, Config1_WR_LO, cp.CP0_Config1_WR);
+ replaceBits(cfg1, Config1_MD_HI, Config1_MD_LO, cp.CP0_Config1_MD);
+ replaceBits(cfg1, Config1_C2_HI, Config1_C2_LO, cp.CP0_Config1_C2);
+ replaceBits(cfg1, Config1_PC_HI, Config1_PC_LO, cp.CP0_Config1_PC);
+ replaceBits(cfg1, Config1_M, cp.CP0_Config1_M);
setRegNoEffect(Config1, cfg1);
// Now, create Write Mask for Config register
MiscReg cfg1_Mask = 0; // Read Only Register
@@ -231,15 +246,15 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Config2
MiscReg cfg2 = readRegNoEffect(Config2);
- replaceBits(cfg2, Config2_TU_HI, Config2_TU_LO, p->coreParams.CP0_Config2_TU);
- replaceBits(cfg2, Config2_TS_HI, Config2_TS_LO, p->coreParams.CP0_Config2_TS);
- replaceBits(cfg2, Config2_TL_HI, Config2_TL_LO, p->coreParams.CP0_Config2_TL);
- replaceBits(cfg2, Config2_TA_HI, Config2_TA_LO, p->coreParams.CP0_Config2_TA);
- replaceBits(cfg2, Config2_SU_HI, Config2_SU_LO, p->coreParams.CP0_Config2_SU);
- replaceBits(cfg2, Config2_SS_HI, Config2_SS_LO, p->coreParams.CP0_Config2_SS);
- replaceBits(cfg2, Config2_SL_HI, Config2_SL_LO, p->coreParams.CP0_Config2_SL);
- replaceBits(cfg2, Config2_SA_HI, Config2_SA_LO, p->coreParams.CP0_Config2_SA);
- replaceBits(cfg2, Config2_M, p->coreParams.CP0_Config2_M);
+ replaceBits(cfg2, Config2_TU_HI, Config2_TU_LO, cp.CP0_Config2_TU);
+ replaceBits(cfg2, Config2_TS_HI, Config2_TS_LO, cp.CP0_Config2_TS);
+ replaceBits(cfg2, Config2_TL_HI, Config2_TL_LO, cp.CP0_Config2_TL);
+ replaceBits(cfg2, Config2_TA_HI, Config2_TA_LO, cp.CP0_Config2_TA);
+ replaceBits(cfg2, Config2_SU_HI, Config2_SU_LO, cp.CP0_Config2_SU);
+ replaceBits(cfg2, Config2_SS_HI, Config2_SS_LO, cp.CP0_Config2_SS);
+ replaceBits(cfg2, Config2_SL_HI, Config2_SL_LO, cp.CP0_Config2_SL);
+ replaceBits(cfg2, Config2_SA_HI, Config2_SA_LO, cp.CP0_Config2_SA);
+ replaceBits(cfg2, Config2_M, cp.CP0_Config2_M);
setRegNoEffect(Config2, cfg2);
// Now, create Write Mask for Config register
MiscReg cfg2_Mask = 0x7000F000; // Read Only Register
@@ -248,14 +263,14 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Config3
MiscReg cfg3 = readRegNoEffect(Config3);
- replaceBits(cfg3, Config3_DSPP_HI, Config3_DSPP_LO, p->coreParams.CP0_Config3_DSPP);
- replaceBits(cfg3, Config3_LPA_HI, Config3_LPA_LO, p->coreParams.CP0_Config3_LPA);
- replaceBits(cfg3, Config3_VEIC_HI, Config3_VEIC_LO, p->coreParams.CP0_Config3_VEIC);
- replaceBits(cfg3, Config3_VINT_HI, Config3_VINT_LO, p->coreParams.CP0_Config3_VInt);
- replaceBits(cfg3, Config3_SP_HI, Config3_SP_LO, p->coreParams.CP0_Config3_SP);
- replaceBits(cfg3, Config3_MT_HI, Config3_MT_LO, p->coreParams.CP0_Config3_MT);
- replaceBits(cfg3, Config3_SM_HI, Config3_SM_LO, p->coreParams.CP0_Config3_SM);
- replaceBits(cfg3, Config3_TL_HI, Config3_TL_LO, p->coreParams.CP0_Config3_TL);
+ replaceBits(cfg3, Config3_DSPP_HI, Config3_DSPP_LO, cp.CP0_Config3_DSPP);
+ replaceBits(cfg3, Config3_LPA_HI, Config3_LPA_LO, cp.CP0_Config3_LPA);
+ replaceBits(cfg3, Config3_VEIC_HI, Config3_VEIC_LO, cp.CP0_Config3_VEIC);
+ replaceBits(cfg3, Config3_VINT_HI, Config3_VINT_LO, cp.CP0_Config3_VInt);
+ replaceBits(cfg3, Config3_SP_HI, Config3_SP_LO, cp.CP0_Config3_SP);
+ replaceBits(cfg3, Config3_MT_HI, Config3_MT_LO, cp.CP0_Config3_MT);
+ replaceBits(cfg3, Config3_SM_HI, Config3_SM_LO, cp.CP0_Config3_SM);
+ replaceBits(cfg3, Config3_TL_HI, Config3_TL_LO, cp.CP0_Config3_TL);
setRegNoEffect(Config3, cfg3);
// Now, create Write Mask for Config register
MiscReg cfg3_Mask = 0; // Read Only Register
@@ -264,7 +279,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// EBase - CPUNum
MiscReg EB = readRegNoEffect(EBase);
- replaceBits(EB, EBase_CPUNum_HI, EBase_CPUNum_LO, p->coreParams.CP0_EBase_CPUNum);
+ replaceBits(EB, EBase_CPUNum_HI, EBase_CPUNum_LO, cp.CP0_EBase_CPUNum);
replaceBits(EB, 31, 31, 1);
setRegNoEffect(EBase, EB);
// Now, create Write Mask for Config register
@@ -275,7 +290,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// SRS Control - HSS (Highest Shadow Set)
MiscReg SC = readRegNoEffect(SRSCtl);
- replaceBits(SC, SRSCtl_HSS_HI,SRSCtl_HSS_LO,p->coreParams.CP0_SrsCtl_HSS);
+ replaceBits(SC, SRSCtl_HSS_HI,SRSCtl_HSS_LO,cp.CP0_SrsCtl_HSS);
setRegNoEffect(SRSCtl, SC);
// Now, create Write Mask for the SRS Ctl register
MiscReg SC_Mask = 0x0000F3C0;
@@ -284,8 +299,8 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// IntCtl - IPTI, IPPCI
MiscReg IC = readRegNoEffect(IntCtl);
- replaceBits(IC, IntCtl_IPTI_HI,IntCtl_IPTI_LO,p->coreParams.CP0_IntCtl_IPTI);
- replaceBits(IC, IntCtl_IPPCI_HI,IntCtl_IPPCI_LO,p->coreParams.CP0_IntCtl_IPPCI);
+ replaceBits(IC, IntCtl_IPTI_HI,IntCtl_IPTI_LO,cp.CP0_IntCtl_IPTI);
+ replaceBits(IC, IntCtl_IPPCI_HI,IntCtl_IPPCI_LO,cp.CP0_IntCtl_IPPCI);
setRegNoEffect(IntCtl, IC);
// Now, create Write Mask for the IntCtl register
MiscReg IC_Mask = 0x000003E0;
@@ -294,7 +309,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Watch Hi - M - FIXME (More than 1 Watch register)
MiscReg WHi = readRegNoEffect(WatchHi0);
- replaceBits(WHi, WatchHi_M, p->coreParams.CP0_WatchHi_M);
+ replaceBits(WHi, WatchHi_M, cp.CP0_WatchHi_M);
setRegNoEffect(WatchHi0, WHi);
// Now, create Write Mask for the IntCtl register
MiscReg wh_Mask = 0x7FFF0FFF;
@@ -303,8 +318,8 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Perf Ctr - M - FIXME (More than 1 PerfCnt Pair)
MiscReg PCtr = readRegNoEffect(PerfCnt0);
- replaceBits(PCtr, PerfCntCtl_M, p->coreParams.CP0_PerfCtr_M);
- replaceBits(PCtr, PerfCntCtl_W, p->coreParams.CP0_PerfCtr_W);
+ replaceBits(PCtr, PerfCntCtl_M, cp.CP0_PerfCtr_M);
+ replaceBits(PCtr, PerfCntCtl_W, cp.CP0_PerfCtr_W);
setRegNoEffect(PerfCnt0, PCtr);
// Now, create Write Mask for the IntCtl register
MiscReg pc_Mask = 0x00007FF;
@@ -322,7 +337,7 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// PageGrain
MiscReg pagegrain = readRegNoEffect(PageGrain);
- replaceBits(pagegrain,PageGrain_ESP,p->coreParams.CP0_Config3_SP);
+ replaceBits(pagegrain,PageGrain_ESP,cp.CP0_Config3_SP);
setRegNoEffect(PageGrain, pagegrain);
// Now, create Write Mask for the IntCtl register
MiscReg pg_Mask = 0x10000000;
@@ -331,12 +346,18 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
// Status
MiscReg stat = readRegNoEffect(Status);
- // Only CU0 and IE are modified on a reset - everything else needs to be controlled
- // on a per CPU model basis
- // replaceBits(stat, Status_CU0_HI,Status_CU0_LO, 1); // Enable CP0 on reset
+ // Only CU0 and IE are modified on a reset - everything else needs
+ // to be controlled on a per CPU model basis
+
+ // Enable CP0 on reset
+ // replaceBits(stat, Status_CU0_HI,Status_CU0_LO, 1);
+
+ // Enable ERL bit on a reset
+ replaceBits(stat, Status_ERL_HI, Status_ERL_LO, 1);
+
+ // Enable BEV bit on a reset
+ replaceBits(stat, Status_BEV_HI, Status_BEV_LO, 1);
- replaceBits(stat, Status_ERL_HI, Status_ERL_LO, 1); // Enable ERL bit on a reset
- replaceBits(stat, Status_BEV_HI, Status_BEV_LO, 1); // Enable BEV bit on a reset
setRegNoEffect(Status, stat);
// Now, create Write Mask for the Status register
MiscReg stat_Mask = 0xFF78FF17;
@@ -417,12 +438,6 @@ MiscRegFile::reset(std::string core_name, unsigned num_threads,
}
-inline std::string
-MipsISA::getMiscRegName(unsigned reg_idx)
-{
- return MiscRegFile::miscRegNames[reg_idx];
-}
-
inline unsigned
MiscRegFile::getVPENum(unsigned tid)
{
@@ -437,7 +452,8 @@ MiscRegFile::readRegNoEffect(int reg_idx, unsigned tid)
unsigned reg_sel = (bankType[misc_reg] == perThreadContext)
? tid : getVPENum(tid);
DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) (%lx).\n",
- misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg),miscRegFile[misc_reg][reg_sel]);
+ misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg],
+ miscRegFile[misc_reg][reg_sel]);
return miscRegFile[misc_reg][reg_sel];
}
@@ -451,8 +467,10 @@ MiscRegFile::readReg(int reg_idx,
int misc_reg = reg_idx - Ctrl_Base_DepTag;
unsigned reg_sel = (bankType[misc_reg] == perThreadContext)
? tid : getVPENum(tid);
- DPRINTF(MipsPRA, "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n",
- misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg),miscRegFile[misc_reg][reg_sel]);
+ DPRINTF(MipsPRA,
+ "Reading CP0 Register:%u Select:%u (%s) with effect (%lx).\n",
+ misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg],
+ miscRegFile[misc_reg][reg_sel]);
switch (misc_reg)
@@ -468,8 +486,10 @@ MiscRegFile::setRegNoEffect(int reg_idx, const MiscReg &val, unsigned tid)
int misc_reg = reg_idx - Ctrl_Base_DepTag;
unsigned reg_sel = (bankType[misc_reg] == perThreadContext)
? tid : getVPENum(tid);
- DPRINTF(MipsPRA, "[tid:%i]: Setting (direct set) CP0 Register:%u Select:%u (%s) to %#x.\n",
- tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val);
+ DPRINTF(MipsPRA,
+ "[tid:%i]: Setting (direct set) CP0 Register:%u "
+ "Select:%u (%s) to %#x.\n",
+ tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val);
miscRegFile[misc_reg][reg_sel] = val;
}
@@ -480,7 +500,9 @@ MiscRegFile::setRegMask(int reg_idx, const MiscReg &val, unsigned tid)
int misc_reg = reg_idx - Ctrl_Base_DepTag;
unsigned reg_sel = (bankType[misc_reg] == perThreadContext)
? tid : getVPENum(tid);
- DPRINTF(MipsPRA,"[tid:%i]: Setting CP0 Register: %u Select: %u (%s) to %#x\n",tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val);
+ DPRINTF(MipsPRA,
+ "[tid:%i]: Setting CP0 Register: %u Select: %u (%s) to %#x\n",
+ tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val);
miscRegFile_WriteMask[misc_reg][reg_sel] = val;
}
@@ -497,8 +519,10 @@ MiscRegFile::setReg(int reg_idx, const MiscReg &val,
int reg_sel = (bankType[misc_reg] == perThreadContext)
? tid : getVPENum(tid);
- DPRINTF(MipsPRA, "[tid:%i]: Setting CP0 Register:%u Select:%u (%s) to %#x, with effect.\n",
- tid, misc_reg / 8, misc_reg % 8, getMiscRegName(misc_reg), val);
+ DPRINTF(MipsPRA,
+ "[tid:%i]: Setting CP0 Register:%u "
+ "Select:%u (%s) to %#x, with effect.\n",
+ tid, misc_reg / 8, misc_reg % 8, miscRegNames[misc_reg], val);
MiscReg cp0_val = filterCP0Write(misc_reg, reg_sel, val);
@@ -506,16 +530,28 @@ MiscRegFile::setReg(int reg_idx, const MiscReg &val,
scheduleCP0Update(1);
}
-/** This method doesn't need to adjust the Control Register Offset since
- it has already been done in the calling method (setRegWithEffect) */
-MiscReg MiscRegFile::filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val)
+/**
+ * This method doesn't need to adjust the Control Register Offset
+ * since it has already been done in the calling method
+ * (setRegWithEffect)
+*/
+MiscReg
+MiscRegFile::filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val)
{
MiscReg retVal = val;
- retVal &= miscRegFile_WriteMask[misc_reg][reg_sel]; // Mask off read-only regions
+
+ // Mask off read-only regions
+ retVal &= miscRegFile_WriteMask[misc_reg][reg_sel];
MiscReg curVal = miscRegFile[misc_reg][reg_sel];
- curVal &= (~miscRegFile_WriteMask[misc_reg][reg_sel]); // Mask off current alue with inverse mask (clear writeable bits)
+ // Mask off current alue with inverse mask (clear writeable bits)
+ curVal &= (~miscRegFile_WriteMask[misc_reg][reg_sel]);
retVal |= curVal; // Combine the two
- DPRINTF(MipsPRA,"filterCP0Write: Mask: %lx, Inverse Mask: %lx, write Val: %x, current val: %lx, written val: %x\n",miscRegFile_WriteMask[misc_reg][reg_sel],~miscRegFile_WriteMask[misc_reg][reg_sel],val,miscRegFile[misc_reg][reg_sel],retVal);
+ DPRINTF(MipsPRA,
+ "filterCP0Write: Mask: %lx, Inverse Mask: %lx, write Val: %x, "
+ "current val: %lx, written val: %x\n",
+ miscRegFile_WriteMask[misc_reg][reg_sel],
+ ~miscRegFile_WriteMask[misc_reg][reg_sel],
+ val, miscRegFile[misc_reg][reg_sel], retVal);
return retVal;
}
void
@@ -526,7 +562,7 @@ MiscRegFile::scheduleCP0Update(int delay)
//schedule UPDATE
CP0Event *cp0_event = new CP0Event(this, cpu, UpdateCP0);
- cp0_event->schedule(curTick + cpu->ticks(delay));
+ cpu->schedule(cp0_event, curTick + cpu->ticks(delay));
}
}
@@ -560,7 +596,7 @@ MiscRegFile::updateCPU()
}
MiscRegFile::CP0Event::CP0Event(CP0 *_cp0, BaseCPU *_cpu, CP0EventType e_type)
- : Event(&mainEventQueue, CPU_Tick_Pri), cp0(_cp0), cpu(_cpu), cp0EventType(e_type)
+ : Event(CPU_Tick_Pri), cp0(_cp0), cpu(_cpu), cp0EventType(e_type)
{ }
void
@@ -585,10 +621,7 @@ MiscRegFile::CP0Event::description() const
void
MiscRegFile::CP0Event::scheduleEvent(int delay)
{
- if (squashed())
- reschedule(curTick + cpu->ticks(delay));
- else if (!scheduled())
- schedule(curTick + cpu->ticks(delay));
+ cpu->reschedule(this, curTick + cpu->ticks(delay), true);
}
void
diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh
index 5f19579b3..c611d94cc 100644
--- a/src/arch/mips/regfile/misc_regfile.hh
+++ b/src/arch/mips/regfile/misc_regfile.hh
@@ -75,7 +75,8 @@ namespace MipsISA
void clear(unsigned tid_or_vpn = 0);
- void reset(std::string core_name, unsigned num_threads, unsigned num_vpes, BaseCPU *_cpu);
+ void reset(std::string core_name, unsigned num_threads,
+ unsigned num_vpes, BaseCPU *_cpu);
void expandForMultithreading(unsigned num_threads, unsigned num_vpes);
@@ -98,7 +99,8 @@ namespace MipsISA
MiscReg filterCP0Write(int misc_reg, int reg_sel, const MiscReg &val);
void setRegMask(int misc_reg, const MiscReg &val, unsigned tid = 0);
- void setRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0);
+ void setRegNoEffect(int misc_reg, const MiscReg &val,
+ unsigned tid = 0);
//template <class TC>
void setReg(int misc_reg, const MiscReg &val,
@@ -160,8 +162,6 @@ namespace MipsISA
static std::string miscRegNames[NumMiscRegs];
};
-
- inline std::string getMiscRegName(unsigned reg_idx);
} // namespace MipsISA
#endif
diff --git a/src/arch/mips/regfile/regfile.cc b/src/arch/mips/regfile/regfile.cc
index 996c14f14..a1c8eab6a 100644
--- a/src/arch/mips/regfile/regfile.cc
+++ b/src/arch/mips/regfile/regfile.cc
@@ -193,7 +193,7 @@ RegFile::setNextNPC(Addr val)
}
void
-RegFile::serialize(std::ostream &os)
+RegFile::serialize(EventManager *em, std::ostream &os)
{
intRegFile.serialize(os);
//SERIALIZE_ARRAY(floatRegFile, NumFloatRegs);
@@ -207,7 +207,8 @@ RegFile::serialize(std::ostream &os)
}
void
-RegFile::unserialize(Checkpoint *cp, const std::string &section)
+RegFile::unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section)
{
intRegFile.unserialize(cp, section);
//UNSERIALIZE_ARRAY(floatRegFile);
diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh
index 8304b7cda..ebf793396 100644
--- a/src/arch/mips/regfile/regfile.hh
+++ b/src/arch/mips/regfile/regfile.hh
@@ -41,22 +41,23 @@
//#include "cpu/base.hh"
#include "sim/faults.hh"
-class Checkpoint;
class BaseCPU;
+class Checkpoint;
+class EventManager;
namespace MipsISA
{
class RegFile {
protected:
- Addr pc; // program counter
- Addr npc; // next-cycle program counter
- Addr nnpc; // next-next-cycle program counter
+ 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
- IntRegFile intRegFile; // (signed) integer register file
- FloatRegFile floatRegFile; // floating point register file
- MiscRegFile miscRegFile; // control register file
+ IntRegFile intRegFile; // (signed) integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegFile; // control register file
public:
void clear();
@@ -99,12 +100,9 @@ namespace MipsISA
Addr readNextNPC();
void setNextNPC(Addr val);
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
-
- void changeContext(RegContextParam param, RegContextVal val)
- {
- }
+ void serialize(EventManager *em, std::ostream &os);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section);
};
diff --git a/src/arch/mips/stacktrace.cc b/src/arch/mips/stacktrace.cc
index 6c6f6bb3c..04a9a0f18 100644
--- a/src/arch/mips/stacktrace.cc
+++ b/src/arch/mips/stacktrace.cc
@@ -70,8 +70,6 @@ ProcessInfo::ProcessInfo(ThreadContext *_tc)
// if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
// panic("thread info not compiled into kernel\n");
// name_off = vp->readGtoH<int32_t>(addr);
-
- tc->delVirtPort(vp);
}
Addr
@@ -87,7 +85,6 @@ ProcessInfo::task(Addr ksp) const
vp = tc->getVirtPort();
tsk = vp->readGtoH<Addr>(base + task_off);
- tc->delVirtPort(vp);
return tsk;
}
@@ -105,7 +102,6 @@ ProcessInfo::pid(Addr ksp) const
vp = tc->getVirtPort();
pd = vp->readGtoH<uint16_t>(task + pid_off);
- tc->delVirtPort(vp);
return pd;
}
@@ -163,7 +159,7 @@ StackTrace::trace(ThreadContext *_tc, bool is_call)
// }
// SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
-// Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
+// Addr ksp = tc->readIntReg(MipsISA::StackPointerReg);
// Addr bottom = ksp & ~0x3fff;
// Addr addr;
diff --git a/src/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh
index e2424523f..4c02cc86c 100644
--- a/src/arch/mips/stacktrace.hh
+++ b/src/arch/mips/stacktrace.hh
@@ -61,7 +61,7 @@ class ProcessInfo
class StackTrace
{
protected:
- typedef TheISA::MachInst MachInst;
+ typedef MipsISA::MachInst MachInst;
private:
ThreadContext *tc;
std::vector<Addr> stack;
diff --git a/src/arch/mips/system.cc b/src/arch/mips/system.cc
index 605acfe32..73bc33161 100755
--- a/src/arch/mips/system.cc
+++ b/src/arch/mips/system.cc
@@ -134,9 +134,9 @@ MipsSystem::~MipsSystem()
* 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
+ * 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
@@ -185,7 +185,7 @@ MipsSystem::setMipsAccess(Addr access)
{
Addr addr = 0;
if (consoleSymtab->findAddress("m5MipsAccess", addr)) {
- // virtPort.write(addr, htog(EV5::Phys2K0Seg(access)));
+ // virtPort.write(addr, htog(AlphaISA::Phys2K0Seg(access)));
} else
panic("could not find m5MipsAccess\n");
}
diff --git a/src/arch/mips/tlb.cc b/src/arch/mips/tlb.cc
index d78aefab4..eac44eba8 100644
--- a/src/arch/mips/tlb.cc
+++ b/src/arch/mips/tlb.cc
@@ -59,7 +59,7 @@ using namespace MipsISA;
// MIPS TLB
//
-#define MODE2MASK(X) (1 << (X))
+#define MODE2MASK(X) (1 << (X))
TLB::TLB(const Params *p)
: BaseTLB(p), size(p->size), nlu(0)
@@ -91,7 +91,7 @@ TLB::lookup(Addr vpn, uint8_t asn) const
Addr Mask = pte->Mask;
Addr InvMask = ~Mask;
Addr VPN = pte->VPN;
- // warn("Valid: %d - %d\n",pte->V0,pte->V1);
+ // warn("Valid: %d - %d\n",pte->V0,pte->V1);
if(((vpn & InvMask) == (VPN & InvMask)) && (pte->G || (asn == pte->asid)))
{ // We have a VPN + ASID Match
retval = pte;
@@ -149,7 +149,7 @@ TLB::checkCacheability(RequestPtr &req)
// or by the TLB entry
if((req->getVaddr() & VAddrUncacheable) == VAddrUncacheable) {
// mark request as uncacheable
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
}
return NoFault;
}
@@ -310,7 +310,7 @@ TLB::regStats()
}
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
+ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
{
#if !FULL_SYSTEM
Process * p = tc->getProcessPtr();
@@ -389,7 +389,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
}
else
{// Ok, this is really a match, set paddr
- // hits++;
+ // hits++;
Addr PAddr;
if(EvenOdd == 0){
PAddr = pte->PFN0;
@@ -406,7 +406,7 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
}
else
{ // Didn't find any match, return a TLB Refill Exception
- // misses++;
+ // misses++;
ItbRefillFault *Flt=new ItbRefillFault();
/* EntryHi VPN, ASID fields must be set */
Flt->EntryHi_Asid = Asid;
@@ -426,8 +426,16 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
#endif
}
+void
+ITB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc), req, tc, false);
+}
+
Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
{
#if !FULL_SYSTEM
Process * p = tc->getProcessPtr();
@@ -494,7 +502,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
if(Valid == false)
{//Invalid entry
- // invalids++;
+ // invalids++;
DtbInvalidFault *Flt = new DtbInvalidFault();
/* EntryHi VPN, ASID fields must be set */
Flt->EntryHi_Asid = Asid;
@@ -512,7 +520,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
}
else
{// Ok, this is really a match, set paddr
- // hits++;
+ // hits++;
if(!Dirty)
{
TLBModifiedFault *Flt = new TLBModifiedFault();
@@ -544,7 +552,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
}
else
{ // Didn't find any match, return a TLB Refill Exception
- // misses++;
+ // misses++;
DtbRefillFault *Flt=new DtbRefillFault();
/* EntryHi VPN, ASID fields must be set */
Flt->EntryHi_Asid = Asid;
@@ -564,6 +572,14 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
#endif
}
+void
+DTB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc, write), req, tc, write);
+}
+
///////////////////////////////////////////////////////////////////////
//
// Mips ITB
@@ -577,19 +593,19 @@ ITB::ITB(const Params *p)
// ITB::regStats()
// {
// /* hits - causes failure for some reason
-// .name(name() + ".hits")
-// .desc("ITB hits");
+// .name(name() + ".hits")
+// .desc("ITB hits");
// misses
-// .name(name() + ".misses")
-// .desc("ITB misses");
+// .name(name() + ".misses")
+// .desc("ITB misses");
// acv
-// .name(name() + ".acv")
-// .desc("ITB acv");
+// .name(name() + ".acv")
+// .desc("ITB acv");
// accesses
-// .name(name() + ".accesses")
-// .desc("ITB accesses");
+// .name(name() + ".accesses")
+// .desc("ITB accesses");
-// accesses = hits + misses + invalids; */
+// accesses = hits + misses + invalids; */
// }
diff --git a/src/arch/mips/tlb.hh b/src/arch/mips/tlb.hh
index 4333777ff..dc0babf9a 100644
--- a/src/arch/mips/tlb.hh
+++ b/src/arch/mips/tlb.hh
@@ -68,6 +68,9 @@ struct TlbEntry
return _pageStart;
}
+ void
+ updateVaddr(Addr new_vaddr) {}
+
void serialize(std::ostream &os)
{
SERIALIZE_SCALAR(_pageStart);
@@ -84,23 +87,23 @@ class TLB : public BaseTLB
{
protected:
typedef std::multimap<Addr, int> PageTable;
- PageTable lookupTable; // Quick lookup into page table
+ PageTable lookupTable; // Quick lookup into page table
- MipsISA::PTE *table; // the Page Table
- int size; // TLB Size
- int nlu; // not last used entry (for replacement)
+ MipsISA::PTE *table; // the Page Table
+ int size; // TLB Size
+ int nlu; // not last used entry (for replacement)
void nextnlu() { if (++nlu >= size) nlu = 0; }
MipsISA::PTE *lookup(Addr vpn, uint8_t asn) const;
- 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;
+ 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 invalids;
@@ -142,7 +145,9 @@ class ITB : public TLB {
typedef MipsTLBParams Params;
ITB(const Params *p);
- Fault translate(RequestPtr &req, ThreadContext *tc);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation);
};
class DTB : public TLB {
@@ -150,7 +155,10 @@ class DTB : public TLB {
typedef MipsTLBParams Params;
DTB(const Params *p);
- Fault translate(RequestPtr &req, ThreadContext *tc, bool write = false);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc,
+ bool write = false);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write = false);
};
class UTB : public ITB, public DTB {
diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh
index 4208cb2d8..b459d9e14 100644
--- a/src/arch/mips/types.hh
+++ b/src/arch/mips/types.hh
@@ -60,9 +60,6 @@ namespace MipsISA
MiscReg ctrlreg;
} AnyReg;
- typedef int RegContextParam;
- typedef int RegContextVal;
-
//used in FP convert & round function
enum ConvertType{
SINGLE_TO_DOUBLE,
diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc
index c254811fa..5908caf68 100644
--- a/src/arch/mips/utility.cc
+++ b/src/arch/mips/utility.cc
@@ -59,10 +59,9 @@ getArgument(ThreadContext *tc, int number, bool fp)
return tc->readIntReg(ArgumentReg[number]);
} else {
Addr sp = tc->readIntReg(StackPointerReg);
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
uint64_t arg = vp->read<uint64_t>(sp +
(number-NumArgumentRegs) * sizeof(uint64_t));
- tc->delVirtPort(vp);
return arg;
}
#else
@@ -146,7 +145,7 @@ genCCVector(uint32_t fcsr, int cc_num, uint32_t cc_val)
{
int cc_idx = (cc_num == 0) ? 23 : cc_num + 24;
- fcsr = bits(fcsr, 31, cc_idx + 1) << cc_idx + 1 |
+ fcsr = bits(fcsr, 31, cc_idx + 1) << (cc_idx + 1) |
cc_val << cc_idx |
bits(fcsr, cc_idx - 1, 0);
@@ -260,7 +259,7 @@ zeroRegisters(CPU *cpu)
void
startupCPU(ThreadContext *tc, int cpuId)
{
- tc->activate(0/*tc->getThreadNum()*/);
+ tc->activate(0/*tc->threadId()*/);
}
} // namespace MipsISA
diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript
index a86c00250..940cf2076 100644
--- a/src/arch/sparc/SConscript
+++ b/src/arch/sparc/SConscript
@@ -44,11 +44,14 @@ if env['TARGET_ISA'] == 'sparc':
Source('utility.cc')
SimObject('SparcTLB.py')
- TraceFlag('Sparc')
+ TraceFlag('Sparc', "Generic SPARC ISA stuff")
+ TraceFlag('RegisterWindows', "Register window manipulation")
if env['FULL_SYSTEM']:
SimObject('SparcSystem.py')
+ SimObject('SparcInterrupts.py')
+ Source('interrupts.cc')
Source('stacktrace.cc')
Source('system.cc')
Source('ua2005.cc')
diff --git a/src/arch/sparc/SparcInterrupts.py b/src/arch/sparc/SparcInterrupts.py
new file mode 100644
index 000000000..2cc964c2d
--- /dev/null
+++ b/src/arch/sparc/SparcInterrupts.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+
+class SparcInterrupts(SimObject):
+ type = 'SparcInterrupts'
+ cxx_class = 'SparcISA::Interrupts'
diff --git a/src/arch/sparc/SparcTLB.py b/src/arch/sparc/SparcTLB.py
index 2d0257cd7..6758d612a 100644
--- a/src/arch/sparc/SparcTLB.py
+++ b/src/arch/sparc/SparcTLB.py
@@ -28,21 +28,20 @@
from m5.SimObject import SimObject
from m5.params import *
-class SparcTLB(SimObject):
+
+from BaseTLB import BaseTLB
+
+class SparcTLB(BaseTLB):
type = 'SparcTLB'
abstract = True
size = Param.Int("TLB size")
class SparcDTB(SparcTLB):
type = 'SparcDTB'
- cxx_namespace = 'SparcISA'
- cxx_class = 'DTB'
-
+ cxx_class = 'SparcISA::DTB'
size = 64
class SparcITB(SparcTLB):
type = 'SparcITB'
- cxx_namespace = 'SparcISA'
- cxx_class = 'ITB'
-
+ cxx_class = 'SparcISA::ITB'
size = 64
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index e201cef95..9c189d164 100644
--- a/src/arch/sparc/faults.cc
+++ b/src/arch/sparc/faults.cc
@@ -546,7 +546,7 @@ void SparcFaultBase::invoke(ThreadContext * tc)
doNormalFault(tc, trapType(), true);
getHyperVector(tc, PC, NPC, 2);
} else if (level == Hyperprivileged ||
- level == Privileged && trapType() >= 384) {
+ (level == Privileged && trapType() >= 384)) {
doNormalFault(tc, trapType(), true);
getHyperVector(tc, PC, NPC, trapType());
} else {
diff --git a/src/arch/sparc/floatregfile.cc b/src/arch/sparc/floatregfile.cc
index e1b5ea7c8..2d1af2218 100644
--- a/src/arch/sparc/floatregfile.cc
+++ b/src/arch/sparc/floatregfile.cc
@@ -41,20 +41,6 @@ using namespace std;
class Checkpoint;
-string SparcISA::getFloatRegName(RegIndex index)
-{
- static std::string floatRegName[NumFloatRegs] =
- {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
- "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
- "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
- "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63"};
- return floatRegName[index];
-}
-
void FloatRegFile::clear()
{
memset(regSpace, 0, sizeof(regSpace));
@@ -75,7 +61,8 @@ FloatReg FloatRegFile::readReg(int floatReg, int width)
result32 = htog(result32);
memcpy(&fresult32, &result32, sizeof(result32));
result = fresult32;
- DPRINTF(Sparc, "Read FP32 register %d = [%f]0x%x\n", floatReg, result, result32);
+ DPRINTF(FloatRegs, "Read FP32 register %d = [%f]0x%x\n",
+ floatReg, result, result32);
break;
case DoubleWidth:
uint64_t result64;
@@ -84,7 +71,8 @@ FloatReg FloatRegFile::readReg(int floatReg, int width)
result64 = htog(result64);
memcpy(&fresult64, &result64, sizeof(result64));
result = fresult64;
- DPRINTF(Sparc, "Read FP64 register %d = [%f]0x%x\n", floatReg, result, result64);
+ DPRINTF(FloatRegs, "Read FP64 register %d = [%f]0x%x\n",
+ floatReg, result, result64);
break;
case QuadWidth:
panic("Quad width FP not implemented.");
@@ -107,13 +95,15 @@ FloatRegBits FloatRegFile::readRegBits(int floatReg, int width)
uint32_t result32;
memcpy(&result32, regSpace + 4 * floatReg, sizeof(result32));
result = htog(result32);
- DPRINTF(Sparc, "Read FP32 bits register %d = 0x%x\n", floatReg, result);
+ DPRINTF(FloatRegs, "Read FP32 bits register %d = 0x%x\n",
+ floatReg, result);
break;
case DoubleWidth:
uint64_t result64;
memcpy(&result64, regSpace + 4 * floatReg, sizeof(result64));
result = htog(result64);
- DPRINTF(Sparc, "Read FP64 bits register %d = 0x%x\n", floatReg, result);
+ DPRINTF(FloatRegs, "Read FP64 bits register %d = 0x%x\n",
+ floatReg, result);
break;
case QuadWidth:
panic("Quad width FP not implemented.");
@@ -141,14 +131,16 @@ Fault FloatRegFile::setReg(int floatReg, const FloatReg &val, int width)
memcpy(&result32, &fresult32, sizeof(result32));
result32 = gtoh(result32);
memcpy(regSpace + 4 * floatReg, &result32, sizeof(result32));
- DPRINTF(Sparc, "Write FP64 register %d = 0x%x\n", floatReg, result32);
+ DPRINTF(FloatRegs, "Write FP64 register %d = 0x%x\n",
+ floatReg, result32);
break;
case DoubleWidth:
fresult64 = val;
memcpy(&result64, &fresult64, sizeof(result64));
result64 = gtoh(result64);
memcpy(regSpace + 4 * floatReg, &result64, sizeof(result64));
- DPRINTF(Sparc, "Write FP64 register %d = 0x%x\n", floatReg, result64);
+ DPRINTF(FloatRegs, "Write FP64 register %d = 0x%x\n",
+ floatReg, result64);
break;
case QuadWidth:
panic("Quad width FP not implemented.");
@@ -171,12 +163,14 @@ Fault FloatRegFile::setRegBits(int floatReg, const FloatRegBits &val, int width)
case SingleWidth:
result32 = gtoh((uint32_t)val);
memcpy(regSpace + 4 * floatReg, &result32, sizeof(result32));
- DPRINTF(Sparc, "Write FP64 bits register %d = 0x%x\n", floatReg, result32);
+ DPRINTF(FloatRegs, "Write FP64 bits register %d = 0x%x\n",
+ floatReg, result32);
break;
case DoubleWidth:
result64 = gtoh((uint64_t)val);
memcpy(regSpace + 4 * floatReg, &result64, sizeof(result64));
- DPRINTF(Sparc, "Write FP64 bits register %d = 0x%x\n", floatReg, result64);
+ DPRINTF(FloatRegs, "Write FP64 bits register %d = 0x%x\n",
+ floatReg, result64);
break;
case QuadWidth:
panic("Quad width FP not implemented.");
diff --git a/src/arch/sparc/floatregfile.hh b/src/arch/sparc/floatregfile.hh
index 72803a5e0..265e71b4a 100644
--- a/src/arch/sparc/floatregfile.hh
+++ b/src/arch/sparc/floatregfile.hh
@@ -42,8 +42,6 @@ class Checkpoint;
namespace SparcISA
{
- std::string getFloatRegName(RegIndex);
-
const int NumFloatArchRegs = 64;
const int NumFloatRegs = 64;
diff --git a/src/cpu/o3/mips/thread_context.cc b/src/arch/sparc/interrupts.cc
index 0061a2a63..96d61e559 100755..100644
--- a/src/cpu/o3/mips/thread_context.cc
+++ b/src/arch/sparc/interrupts.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,12 +25,13 @@
* (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: Kevin Lim
- * Korey Sewell
+ * Authors: Gabe Black
*/
-#include "cpu/o3/thread_context.hh"
-#include "cpu/o3/thread_context_impl.hh"
-
-template class O3ThreadContext<MipsSimpleImpl>;
-
+#include "arch/sparc/interrupts.hh"
+
+SparcISA::Interrupts *
+SparcInterruptsParams::create()
+{
+ return new SparcISA::Interrupts(this);
+}
diff --git a/src/arch/sparc/interrupts.hh b/src/arch/sparc/interrupts.hh
index 4ad3385fb..ec930e2b0 100644
--- a/src/arch/sparc/interrupts.hh
+++ b/src/arch/sparc/interrupts.hh
@@ -35,25 +35,43 @@
#include "arch/sparc/faults.hh"
#include "arch/sparc/isa_traits.hh"
#include "cpu/thread_context.hh"
+#include "params/SparcInterrupts.hh"
+#include "sim/sim_object.hh"
namespace SparcISA
{
-class Interrupts
+class Interrupts : public SimObject
{
-
private:
+ BaseCPU * cpu;
uint64_t interrupts[NumInterruptTypes];
uint64_t intStatus;
public:
- Interrupts()
+
+ void
+ setCPU(BaseCPU * _cpu)
+ {
+ cpu = _cpu;
+ }
+
+ typedef SparcInterruptsParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ Interrupts(Params * p) : SimObject(p), cpu(NULL)
{
- clear_all();
+ clearAll();
}
- int InterruptLevel(uint64_t softint)
+ int
+ InterruptLevel(uint64_t softint)
{
if (softint & 0x10000 || softint & 0x1)
return 14;
@@ -66,7 +84,8 @@ class Interrupts
return 0;
}
- void post(int int_num, int index)
+ void
+ post(int int_num, int index)
{
DPRINTF(Interrupt, "Interrupt %d:%d posted\n", int_num, index);
assert(int_num >= 0 && int_num < NumInterruptTypes);
@@ -76,7 +95,8 @@ class Interrupts
intStatus |= ULL(1) << int_num;
}
- void clear(int int_num, int index)
+ void
+ clear(int int_num, int index)
{
DPRINTF(Interrupt, "Interrupt %d:%d cleared\n", int_num, index);
assert(int_num >= 0 && int_num < NumInterruptTypes);
@@ -87,7 +107,8 @@ class Interrupts
intStatus &= ~(ULL(1) << int_num);
}
- void clear_all()
+ void
+ clearAll()
{
for (int i = 0; i < NumInterruptTypes; ++i) {
interrupts[i] = 0;
@@ -95,12 +116,14 @@ class Interrupts
intStatus = 0;
}
- bool check_interrupts(ThreadContext * tc) const
+ bool
+ checkInterrupts(ThreadContext *tc) const
{
return intStatus;
}
- Fault getInterrupt(ThreadContext * tc)
+ Fault
+ getInterrupt(ThreadContext *tc)
{
int hpstate = tc->readMiscRegNoEffect(MISCREG_HPSTATE);
int pstate = tc->readMiscRegNoEffect(MISCREG_PSTATE);
@@ -143,8 +166,8 @@ class Interrupts
return new DevMondo;
}
if (interrupts[IT_SOFT_INT]) {
- return new
- InterruptLevelN(InterruptLevel(interrupts[IT_SOFT_INT]));
+ int level = InterruptLevel(interrupts[IT_SOFT_INT]);
+ return new InterruptLevelN(level);
}
if (interrupts[IT_RES_ERROR]) {
@@ -155,24 +178,28 @@ class Interrupts
return NoFault;
}
- void updateIntrInfo(ThreadContext * tc)
+ void
+ updateIntrInfo(ThreadContext *tc)
{
}
- uint64_t get_vec(int int_num)
+ uint64_t
+ get_vec(int int_num)
{
assert(int_num >= 0 && int_num < NumInterruptTypes);
return interrupts[int_num];
}
- void serialize(std::ostream &os)
+ void
+ serialize(std::ostream &os)
{
SERIALIZE_ARRAY(interrupts,NumInterruptTypes);
SERIALIZE_SCALAR(intStatus);
}
- void unserialize(Checkpoint *cp, const std::string &section)
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(interrupts,NumInterruptTypes);
UNSERIALIZE_SCALAR(intStatus);
diff --git a/src/arch/sparc/intregfile.cc b/src/arch/sparc/intregfile.cc
index 39a613a0d..54c30d1cc 100644
--- a/src/arch/sparc/intregfile.cc
+++ b/src/arch/sparc/intregfile.cc
@@ -41,138 +41,40 @@ using namespace std;
class Checkpoint;
-string SparcISA::getIntRegName(RegIndex index)
-{
- static std::string intRegName[NumIntArchRegs] =
- {"g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
- "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7",
- "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
- "i0", "i1", "i2", "i3", "i4", "i5", "i6", "i7"};
- return intRegName[index];
-}
-
-int IntRegFile::flattenIndex(int reg)
-{
- int flatIndex = offset[reg >> FrameOffsetBits]
- | (reg & FrameOffsetMask);
- DPRINTF(Sparc, "Flattened index %d into %d.\n", reg, flatIndex);
- return flatIndex;
-}
-
void IntRegFile::clear()
{
- int x;
- for (x = 0; x < MaxGL; x++)
- memset(regGlobals[x], 0, sizeof(IntReg) * RegsPerFrame);
- for(int x = 0; x < 2 * NWindows; x++)
- memset(regSegments[x], 0, sizeof(IntReg) * RegsPerFrame);
memset(regs, 0, sizeof(IntReg) * NumIntRegs);
}
IntRegFile::IntRegFile()
{
- offset[Globals] = 0;
- regView[Globals] = regGlobals[0];
- setCWP(0);
clear();
}
IntReg IntRegFile::readReg(int intReg)
{
- DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, regs[intReg]);
+ DPRINTF(IntRegs, "Read register %d = 0x%x\n", intReg, regs[intReg]);
return regs[intReg];
- /* XXX Currently not used. When used again regView/offset need to be
- * serialized!
- IntReg val;
- if(intReg < NumIntArchRegs)
- val = regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask];
- else if((intReg -= NumIntArchRegs) < NumMicroIntRegs)
- val = microRegs[intReg];
- else
- panic("Tried to read non-existant integer register %d, %d\n",
- NumIntArchRegs + NumMicroIntRegs + intReg, intReg);
-
- DPRINTF(Sparc, "Read register %d = 0x%x\n", intReg, val);
- return val;
- */
}
void IntRegFile::setReg(int intReg, const IntReg &val)
{
if(intReg)
{
- DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val);
+ DPRINTF(IntRegs, "Wrote register %d = 0x%x\n", intReg, val);
regs[intReg] = val;
}
return;
- /* XXX Currently not used. When used again regView/offset need to be
- * serialized!
- if(intReg)
- {
- DPRINTF(Sparc, "Wrote register %d = 0x%x\n", intReg, val);
- if(intReg < NumIntArchRegs)
- regView[intReg >> FrameOffsetBits][intReg & FrameOffsetMask] = val;
- else if((intReg -= NumIntArchRegs) < NumMicroIntRegs)
- microRegs[intReg] = val;
- else
- panic("Tried to set non-existant integer register\n");
- } */
-}
-
-//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 IntRegFile::setCWP(int cwp)
-{
- int index = ((NWindows - cwp) % NWindows) * 2;
- if (index < 0)
- panic("Index less than 0. cwp=%d nwin=%d\n", cwp, NWindows);
- 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 IntRegFile::setGlobals(int gl)
-{
- DPRINTF(Sparc, "Now using %d globals\n", gl);
-
- regView[Globals] = regGlobals[gl];
- offset[Globals] = RegGlobalOffset + gl * RegsPerFrame;
-
- if (regView[Globals] == regView[Inputs] ||
- regView[Globals] == regView[Locals] ||
- regView[Globals] == regView[Outputs] )
- panic("Two register arrays set to the same thing!\n");
}
void IntRegFile::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(regs, NumIntRegs);
SERIALIZE_ARRAY(microRegs, NumMicroIntRegs);
-
- /* the below doesn't seem needed unless gabe makes regview work*/
- unsigned int x;
- for(x = 0; x < MaxGL; x++)
- SERIALIZE_ARRAY(regGlobals[x], RegsPerFrame);
- for(x = 0; x < 2 * NWindows; x++)
- SERIALIZE_ARRAY(regSegments[x], RegsPerFrame);
}
void IntRegFile::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(regs, NumIntRegs);
UNSERIALIZE_ARRAY(microRegs, NumMicroIntRegs);
-
- /* the below doesn't seem needed unless gabe makes regview work*/
- unsigned int x;
- for(x = 0; x < MaxGL; x++)
- UNSERIALIZE_ARRAY(regGlobals[x], RegsPerFrame);
- for(unsigned int x = 0; x < 2 * NWindows; x++)
- UNSERIALIZE_ARRAY(regSegments[x], RegsPerFrame);
}
diff --git a/src/arch/sparc/intregfile.hh b/src/arch/sparc/intregfile.hh
index 83ef1d17b..f669f6b0d 100644
--- a/src/arch/sparc/intregfile.hh
+++ b/src/arch/sparc/intregfile.hh
@@ -42,53 +42,17 @@ class Checkpoint;
namespace SparcISA
{
- class RegFile;
-
- //This function translates integer register file indices into names
- std::string getIntRegName(RegIndex);
-
const int NumIntArchRegs = 32;
const int NumIntRegs = (MaxGL + 1) * 8 + NWindows * 16 + NumMicroIntRegs;
class IntRegFile
{
- private:
- friend class RegFile;
protected:
- //The number of bits needed to index into each 8 register frame
- static const int FrameOffsetBits = 3;
- //The number of bits to choose between the 4 sets of 8 registers
- static const int FrameNumBits = 2;
-
- //The number of registers per "frame" (8)
- static const int RegsPerFrame = 1 << FrameOffsetBits;
- //A mask to get the frame number
- static const uint64_t FrameNumMask =
- (FrameNumBits == sizeof(int)) ?
- (unsigned int)(-1) :
- (1 << FrameNumBits) - 1;
- static const uint64_t FrameOffsetMask =
- (FrameOffsetBits == sizeof(int)) ?
- (unsigned int)(-1) :
- (1 << FrameOffsetBits) - 1;
-
- IntReg regGlobals[MaxGL+1][RegsPerFrame];
- IntReg regSegments[2 * NWindows][RegsPerFrame];
IntReg microRegs[NumMicroIntRegs];
IntReg regs[NumIntRegs];
- enum regFrame {Globals, Outputs, Locals, Inputs, NumFrames};
-
- IntReg * regView[NumFrames];
-
- static const int RegGlobalOffset = 0;
- static const int FrameOffset = (MaxGL + 1) * RegsPerFrame;
- int offset[NumFrames];
-
public:
- int flattenIndex(int reg);
-
void clear();
IntRegFile();
@@ -100,14 +64,6 @@ namespace SparcISA
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
-
- protected:
- //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);
-
- void setGlobals(int gl);
};
}
diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa
index c35b231ff..e34ca033f 100644
--- a/src/arch/sparc/isa/decoder.isa
+++ b/src/arch/sparc/isa/decoder.isa
@@ -1231,16 +1231,14 @@ decode OP default Unknown::unknown()
0x23: Load::lddf({{Frd.udw = Mem.udw;}});
0x24: Store::stf({{Mem.uw = Frds.uw;}});
0x25: decode RD {
- 0x0: Store::stfsr({{fault = checkFpEnableFault(xc);
- if (fault)
- return fault;
- Mem.uw = Fsr<31:0>;
- Fsr = insertBits(Fsr,16,14,0);}});
- 0x1: Store::stxfsr({{fault = checkFpEnableFault(xc);
- if (fault)
- return fault;
- Mem.udw = Fsr;
- Fsr = insertBits(Fsr,16,14,0);}});
+ 0x0: StoreFsr::stfsr({{fault = checkFpEnableFault(xc);
+ if (fault)
+ return fault;
+ Mem.uw = Fsr<31:0>;}});
+ 0x1: StoreFsr::stxfsr({{fault = checkFpEnableFault(xc);
+ if (fault)
+ return fault;
+ Mem.udw = Fsr;}});
default: FailUnimpl::stfsrOther();
}
0x26: stqf({{fault = new FpDisabled;}});
diff --git a/src/arch/sparc/isa/formats/mem/basicmem.isa b/src/arch/sparc/isa/formats/mem/basicmem.isa
index e3c043cf3..c7bb3e435 100644
--- a/src/arch/sparc/isa/formats/mem/basicmem.isa
+++ b/src/arch/sparc/isa/formats/mem/basicmem.isa
@@ -108,6 +108,16 @@ def format Store(code, *opt_flags) {{
StoreFuncs, '', name, Name, 0, opt_flags)
}};
+def format StoreFsr(code, *opt_flags) {{
+ code = filterDoubles(code)
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code,
+ StoreFuncs, '', name, Name, 0, opt_flags,
+ 'Fsr = insertBits(Fsr,16,14,0);')
+}};
+
def format TwinLoad(code, *opt_flags) {{
(header_output,
decoder_output,
diff --git a/src/arch/sparc/isa/formats/mem/swap.isa b/src/arch/sparc/isa/formats/mem/swap.isa
index 2ebe9aa15..046f89822 100644
--- a/src/arch/sparc/isa/formats/mem/swap.isa
+++ b/src/arch/sparc/isa/formats/mem/swap.isa
@@ -133,6 +133,7 @@ let {{
def format Swap(code, postacc_code, mem_flags, *opt_flags) {{
mem_flags = makeList(mem_flags)
+ mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
flags = string.join(mem_flags, '|')
(header_output,
@@ -144,6 +145,7 @@ def format Swap(code, postacc_code, mem_flags, *opt_flags) {{
def format SwapAlt(code, postacc_code, mem_flags, *opt_flags) {{
mem_flags = makeList(mem_flags)
+ mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
mem_flags.append("EXT_ASI")
flags = string.join(mem_flags, '|')
(header_output,
@@ -175,6 +177,7 @@ let {{
def format CasAlt(code, postacc_code, mem_flags, *opt_flags) {{
mem_flags = makeList(mem_flags)
+ mem_flags = [ 'Request::%s' % flag for flag in mem_flags ]
mem_flags.append("EXT_ASI")
flags = string.join(mem_flags, '|')
(header_output,
diff --git a/src/arch/sparc/isa/formats/mem/util.isa b/src/arch/sparc/isa/formats/mem/util.isa
index 38cde9a50..31efb9cf6 100644
--- a/src/arch/sparc/isa/formats/mem/util.isa
+++ b/src/arch/sparc/isa/formats/mem/util.isa
@@ -264,11 +264,6 @@ def template StoreInitiateAcc {{
fault = xc->write((%(mem_acc_type)s%(mem_acc_size)s_t)Mem,
EA, %(asi_val)s, 0);
}
- if(fault == NoFault)
- {
- //Write the resulting state to the execution context
- %(op_wb)s;
- }
return fault;
}
}};
@@ -277,6 +272,15 @@ def template StoreCompleteAcc {{
Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc,
Trace::InstRecord * traceData) const
{
+ Fault fault = NoFault;
+ %(op_decl)s;
+
+ %(op_rd)s;
+ %(postacc_code)s;
+ if (fault == NoFault)
+ {
+ %(op_wb)s;
+ }
return NoFault;
}
}};
@@ -314,10 +318,11 @@ let {{
# are split into ones that are available in priv and hpriv, and
# those that are only available in hpriv
AlternateASIPrivFaultCheck = '''
- if(!bits(Pstate,2,2) && !bits(Hpstate,2,2) && !AsiIsUnPriv((ASI)EXT_ASI) ||
- !bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI))
- fault = new PrivilegedAction;
- else if(AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2))
+ if ((!bits(Pstate,2,2) && !bits(Hpstate,2,2) &&
+ !AsiIsUnPriv((ASI)EXT_ASI)) ||
+ (!bits(Hpstate,2,2) && AsiIsHPriv((ASI)EXT_ASI)))
+ fault = new PrivilegedAction;
+ else if (AsiIsAsIfUser((ASI)EXT_ASI) && !bits(Pstate,2,2))
fault = new PrivilegedAction;
'''
diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh
index 133817eb5..501f2f990 100644
--- a/src/arch/sparc/isa_traits.hh
+++ b/src/arch/sparc/isa_traits.hh
@@ -66,18 +66,14 @@ namespace SparcISA
};
// semantically meaningful register indices
- const int ZeroReg = 0; // architecturally meaningful
+ 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 StackPointerReg = 14;
const int FramePointerReg = 30;
- const int ArgumentReg[] = {8, 9, 10, 11, 12, 13};
- const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
-
// Some OS syscall use a second register (o1) to return a second value
- const int SyscallPseudoReturnReg = ArgumentReg[1];
+ const int SyscallPseudoReturnReg = 9;
//8K. This value is implmentation specific; and should probably
//be somewhere else.
diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc
index 1211d5f65..102e5af3b 100644
--- a/src/arch/sparc/linux/linux.cc
+++ b/src/arch/sparc/linux/linux.cc
@@ -34,34 +34,34 @@
// 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 },
+ { 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 },
+ { SparcLinux::TGT_O_NONBLOCK, _O_NONBLOCK },
#endif
#ifdef _O_NOCTTY
- { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY },
+ { SparcLinux::TGT_O_NOCTTY, _O_NOCTTY },
#endif
#ifdef _O_SYNC
- { SparcLinux::TGT_O_SYNC, _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 },
+ { 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 },
+ { SparcLinux::TGT_O_SYNC, O_SYNC },
#endif
#endif /* _MSC_VER */
};
diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh
index f396eb5cd..b1dc691ce 100644
--- a/src/arch/sparc/linux/linux.hh
+++ b/src/arch/sparc/linux/linux.hh
@@ -58,21 +58,21 @@ class SparcLinux : public Linux
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 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;
diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc
index f4ec28c00..2078c1dce 100644
--- a/src/arch/sparc/linux/process.cc
+++ b/src/arch/sparc/linux/process.cc
@@ -47,7 +47,7 @@ using namespace SparcISA;
SyscallDesc*
SparcLinuxProcess::getDesc(int callnum)
{
- if (callnum < 0 || callnum > Num_Syscall_Descs)
+ if (callnum < 0 || callnum >= Num_Syscall_Descs)
return NULL;
return &syscallDescs[callnum];
}
@@ -55,7 +55,7 @@ SparcLinuxProcess::getDesc(int callnum)
SyscallDesc*
SparcLinuxProcess::getDesc32(int callnum)
{
- if (callnum < 0 || callnum > Num_Syscall32_Descs)
+ if (callnum < 0 || callnum >= Num_Syscall32_Descs)
return NULL;
return &syscall32Descs[callnum];
}
diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh
index 06eee9235..a76b4b3b2 100644
--- a/src/arch/sparc/linux/process.hh
+++ b/src/arch/sparc/linux/process.hh
@@ -32,7 +32,6 @@
#define __SPARC_LINUX_PROCESS_HH__
#include "arch/sparc/linux/linux.hh"
-#include "arch/sparc/syscallreturn.hh"
#include "arch/sparc/process.hh"
#include "sim/process.hh"
diff --git a/src/arch/sparc/linux/syscalls.cc b/src/arch/sparc/linux/syscalls.cc
index 03c8bafe2..8496fca13 100644
--- a/src/arch/sparc/linux/syscalls.cc
+++ b/src/arch/sparc/linux/syscalls.cc
@@ -29,7 +29,6 @@
*/
#include "arch/sparc/linux/process.hh"
-#include "arch/sparc/syscallreturn.hh"
#include "sim/syscall_emul.hh"
class LiveProcess;
@@ -42,7 +41,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -60,9 +59,9 @@ SyscallReturn getresuidFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc)
{
const IntReg id = htog(100);
- Addr ruid = tc->getSyscallArg(0);
- Addr euid = tc->getSyscallArg(1);
- Addr suid = tc->getSyscallArg(2);
+ Addr ruid = p->getSyscallArg(tc, 0);
+ Addr euid = p->getSyscallArg(tc, 1);
+ Addr suid = p->getSyscallArg(tc, 2);
//Handle the EFAULT case
//Set the ruid
if(ruid)
@@ -106,7 +105,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", unimplementedFunc),
/* 16 */ SyscallDesc("lchown", unimplementedFunc), //32 bit
- /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 17 */ SyscallDesc("brk", brkFunc),
/* 18 */ SyscallDesc("perfctr", unimplementedFunc), //32 bit
/* 19 */ SyscallDesc("lseek", lseekFunc), //32 bit
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -147,7 +146,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 55 */ SyscallDesc("reboot", unimplementedFunc), //32 bit
/* 56 */ SyscallDesc("mmap2", unimplementedFunc), //32 bit
/* 57 */ SyscallDesc("symlink", unimplementedFunc),
- /* 58 */ SyscallDesc("readlink", unimplementedFunc), //32 bit
+ /* 58 */ SyscallDesc("readlink", readlinkFunc), //32 bit
/* 59 */ SyscallDesc("execve", unimplementedFunc), //32 bit
/* 60 */ SyscallDesc("umask", unimplementedFunc), //32 bit
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
@@ -208,7 +207,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 116 */ SyscallDesc("gettimeofday", unimplementedFunc), //32 bit
/* 117 */ SyscallDesc("getrusage", unimplementedFunc), //32 bit
/* 118 */ SyscallDesc("getsockopt", unimplementedFunc),
- /* 119 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 119 */ SyscallDesc("getcwd", getcwdFunc),
/* 120 */ SyscallDesc("readv", unimplementedFunc),
/* 121 */ SyscallDesc("writev", unimplementedFunc),
/* 122 */ SyscallDesc("settimeofday", unimplementedFunc), //32 bit
@@ -225,7 +224,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 133 */ SyscallDesc("sendto", unimplementedFunc),
/* 134 */ SyscallDesc("shutdown", unimplementedFunc),
/* 135 */ SyscallDesc("socketpair", unimplementedFunc),
- /* 136 */ SyscallDesc("mkdir", unimplementedFunc), //32 bit
+ /* 136 */ SyscallDesc("mkdir", mkdirFunc), //32 bit
/* 137 */ SyscallDesc("rmdir", unimplementedFunc),
/* 138 */ SyscallDesc("utimes", unimplementedFunc), //32 bit
/* 139 */ SyscallDesc("stat64", unimplementedFunc),
@@ -339,7 +338,7 @@ SyscallDesc SparcLinuxProcess::syscall32Descs[] = {
/* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc), //32 bit
/* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc), //32 bit
/* 249 */ SyscallDesc("nanosleep", unimplementedFunc),
- /* 250 */ SyscallDesc("mremap", unimplementedFunc), //32 bit
+ /* 250 */ SyscallDesc("mremap", mremapFunc<Sparc32Linux>), //32 bit
/* 251 */ SyscallDesc("_sysctl", unimplementedFunc), //32 bit
/* 252 */ SyscallDesc("getsid", unimplementedFunc), //32 bit
/* 253 */ SyscallDesc("fdatasync", unimplementedFunc),
@@ -409,7 +408,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<Linux>),
/* 16 */ SyscallDesc("lchown", unimplementedFunc),
- /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 17 */ SyscallDesc("brk", brkFunc),
/* 18 */ SyscallDesc("perfctr", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -450,7 +449,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 55 */ SyscallDesc("reboot", unimplementedFunc),
/* 56 */ SyscallDesc("mmap2", unimplementedFunc),
/* 57 */ SyscallDesc("symlink", unimplementedFunc),
- /* 58 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 58 */ SyscallDesc("readlink", readlinkFunc),
/* 59 */ SyscallDesc("execve", unimplementedFunc),
/* 60 */ SyscallDesc("umask", unimplementedFunc),
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
@@ -528,7 +527,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 133 */ SyscallDesc("sendto", unimplementedFunc),
/* 134 */ SyscallDesc("shutdown", unimplementedFunc),
/* 135 */ SyscallDesc("socketpair", unimplementedFunc),
- /* 136 */ SyscallDesc("mkdir", unimplementedFunc),
+ /* 136 */ SyscallDesc("mkdir", mkdirFunc),
/* 137 */ SyscallDesc("rmdir", unimplementedFunc),
/* 138 */ SyscallDesc("utimes", unimplementedFunc),
/* 139 */ SyscallDesc("stat64", unimplementedFunc),
@@ -642,7 +641,7 @@ SyscallDesc SparcLinuxProcess::syscallDescs[] = {
/* 247 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
/* 248 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
/* 249 */ SyscallDesc("nanosleep", unimplementedFunc),
- /* 250 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 250 */ SyscallDesc("mremap", mremapFunc<SparcLinux>),
/* 251 */ SyscallDesc("_sysctl", unimplementedFunc),
/* 252 */ SyscallDesc("getsid", unimplementedFunc),
/* 253 */ SyscallDesc("fdatasync", unimplementedFunc),
diff --git a/src/arch/sparc/microcode_rom.hh b/src/arch/sparc/microcode_rom.hh
new file mode 100644
index 000000000..e46000dcc
--- /dev/null
+++ b/src/arch/sparc/microcode_rom.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_SPARC_MICROCODE_ROM_HH__
+#define __ARCH_SPARC_MICROCODE_ROM_HH__
+
+#include "sim/microcode_rom.hh"
+
+namespace SparcISA
+{
+ using ::MicrocodeRom;
+}
+
+#endif // __ARCH_SPARC_MICROCODE_ROM_HH__
diff --git a/src/arch/sparc/miscregfile.cc b/src/arch/sparc/miscregfile.cc
index 7b9c73433..38eba3862 100644
--- a/src/arch/sparc/miscregfile.cc
+++ b/src/arch/sparc/miscregfile.cc
@@ -42,27 +42,6 @@ using namespace std;
class Checkpoint;
-//These functions map register indices to names
-string SparcISA::getMiscRegName(RegIndex index)
-{
- static::string miscRegName[NumMiscRegs] =
- {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic",
- "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr",
- "stick", "stick_cmpr",
- "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl",
- "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin",
- "wstate",*/ "gl",
- "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg",
- "hstick_cmpr",
- "fsr", "prictx", "secctx", "partId", "lsuCtrlReg",
- "scratch0", "scratch1", "scratch2", "scratch3", "scratch4",
- "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail",
- "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail",
- "nresErrorHead", "nresErrorTail", "TlbData" };
-
- return miscRegName[index];
-}
-
enum RegMask
{
PSTATE_MASK = (((1 << 4) - 1) << 1) | (((1 << 4) - 1) << 6) | (1 << 12)
@@ -227,7 +206,7 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg)
/** Floating Point Status Register */
case MISCREG_FSR:
- DPRINTF(Sparc, "FSR read as: %#x\n", fsr);
+ DPRINTF(MiscRegs, "FSR read as: %#x\n", fsr);
return fsr;
case MISCREG_MMU_P_CONTEXT:
@@ -322,12 +301,13 @@ MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc)
return readFSReg(miscReg, tc);
#else
case MISCREG_HPSTATE:
- //HPSTATE is special because because sometimes in privilege checks for instructions
- //it will read HPSTATE to make sure the priv. level is ok
- //So, we'll just have to tell it it isn't, instead of panicing.
+ //HPSTATE is special because because sometimes in privilege
+ //checks for instructions it will read HPSTATE to make sure
+ //the priv. level is ok So, we'll just have to tell it it
+ //isn't, instead of panicing.
return 0;
- panic("Accessing Fullsystem register %s in SE mode\n",getMiscRegName(miscReg));
+ panic("Accessing Fullsystem register %d in SE mode\n", miscReg);
#endif
}
@@ -444,7 +424,7 @@ void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val)
/** Floating Point Status Register */
case MISCREG_FSR:
fsr = val;
- DPRINTF(Sparc, "FSR written with: %#x\n", fsr);
+ DPRINTF(MiscRegs, "FSR written with: %#x\n", fsr);
break;
case MISCREG_MMU_P_CONTEXT:
@@ -540,20 +520,17 @@ void MiscRegFile::setReg(int miscReg,
tl = val;
#if FULL_SYSTEM
if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
- tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ tc->getCpuPtr()->postInterrupt(IT_TRAP_LEVEL_ZERO, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ tc->getCpuPtr()->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0);
#endif
return;
case MISCREG_CWP:
new_val = val >= NWindows ? NWindows - 1 : val;
if (val >= NWindows)
new_val = NWindows - 1;
-
- tc->changeRegFileContext(CONTEXT_CWP, new_val);
break;
case MISCREG_GL:
- tc->changeRegFileContext(CONTEXT_GLOBALS, val);
break;
case MISCREG_PIL:
case MISCREG_SOFTINT:
@@ -584,13 +561,15 @@ void MiscRegFile::setReg(int miscReg,
//HPSTATE is special because normal trap processing saves HPSTATE when
//it goes into a trap, and restores it when it returns.
return;
- panic("Accessing Fullsystem register %s to %#x in SE mode\n", getMiscRegName(miscReg), val);
+ panic("Accessing Fullsystem register %d to %#x in SE mode\n",
+ miscReg, val);
#endif
}
setRegNoEffect(miscReg, new_val);
}
-void MiscRegFile::serialize(std::ostream & os)
+void
+MiscRegFile::serialize(EventManager *em, std::ostream &os)
{
SERIALIZE_SCALAR(asi);
SERIALIZE_SCALAR(tick);
@@ -667,7 +646,9 @@ void MiscRegFile::serialize(std::ostream & os)
#endif
}
-void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section)
+void
+MiscRegFile::unserialize(EventManager *em, Checkpoint *cp,
+ const string &section)
{
UNSERIALIZE_SCALAR(asi);
UNSERIALIZE_SCALAR(tick);
@@ -726,15 +707,15 @@ void MiscRegFile::unserialize(Checkpoint * cp, const std::string & section)
if (tick_cmp) {
tickCompare = new TickCompareEvent(this, tc);
- tickCompare->schedule(tick_cmp);
+ em->schedule(tickCompare, tick_cmp);
}
if (stick_cmp) {
sTickCompare = new STickCompareEvent(this, tc);
- sTickCompare->schedule(stick_cmp);
+ em->schedule(sTickCompare, stick_cmp);
}
if (hstick_cmp) {
hSTickCompare = new HSTickCompareEvent(this, tc);
- hSTickCompare->schedule(hstick_cmp);
+ em->schedule(hSTickCompare, hstick_cmp);
}
}
}
diff --git a/src/arch/sparc/miscregfile.hh b/src/arch/sparc/miscregfile.hh
index 3e17779a9..9eff7fcac 100644
--- a/src/arch/sparc/miscregfile.hh
+++ b/src/arch/sparc/miscregfile.hh
@@ -43,9 +43,6 @@ class Checkpoint;
namespace SparcISA
{
- //These functions map register indices to names
- std::string getMiscRegName(RegIndex);
-
enum MiscRegIndex
{
/** Ancillary State Registers */
@@ -171,50 +168,50 @@ namespace SparcISA
private:
/* ASR Registers */
- //uint64_t y; // Y (used in obsolete multiplication)
- //uint8_t ccr; // Condition Code Register
- uint8_t asi; // Address Space Identifier
- uint64_t tick; // Hardware clock-tick counter
- uint8_t fprs; // Floating-Point Register State
- uint64_t gsr; // General Status Register
+ //uint64_t y; // Y (used in obsolete multiplication)
+ //uint8_t ccr; // Condition Code Register
+ uint8_t asi; // Address Space Identifier
+ uint64_t tick; // Hardware clock-tick counter
+ uint8_t fprs; // Floating-Point Register State
+ uint64_t gsr; // General Status Register
uint64_t softint;
- uint64_t tick_cmpr; // Hardware tick compare registers
- uint64_t stick; // Hardware clock-tick counter
- uint64_t stick_cmpr; // Hardware tick compare registers
+ uint64_t tick_cmpr; // Hardware tick compare registers
+ uint64_t stick; // Hardware clock-tick counter
+ uint64_t stick_cmpr; // Hardware tick compare registers
/* Privileged Registers */
- uint64_t tpc[MaxTL]; // Trap Program Counter (value from
+ uint64_t tpc[MaxTL]; // Trap Program Counter (value from
// previous trap level)
- uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from
+ uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from
// previous trap level)
- uint64_t tstate[MaxTL]; // Trap State
- uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured
+ uint64_t tstate[MaxTL]; // Trap State
+ uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured
// on the previous level)
- uint64_t tba; // Trap Base Address
-
- uint16_t pstate; // Process State Register
- 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
- //uint8_t wstate; // Window State
+ uint64_t tba; // Trap Base Address
+
+ uint16_t pstate; // Process State Register
+ 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
+ //uint8_t wstate; // Window State
uint8_t gl; // Global level register
/** Hyperprivileged Registers */
- uint64_t hpstate; // Hyperprivileged State Register
+ uint64_t hpstate; // Hyperprivileged State Register
uint64_t htstate[MaxTL];// Hyperprivileged Trap State Register
uint64_t hintp;
- uint64_t htba; // Hyperprivileged Trap Base Address register
- uint64_t hstick_cmpr; // Hardware tick compare registers
+ uint64_t htba; // Hyperprivileged Trap Base Address register
+ uint64_t hstick_cmpr; // Hardware tick compare registers
uint64_t strandStatusReg;// Per strand status register
/** Floating point misc registers. */
- uint64_t fsr; // Floating-Point State Register
+ uint64_t fsr; // Floating-Point State Register
/** MMU Internal Registers */
uint16_t priContext;
@@ -288,9 +285,10 @@ namespace SparcISA
return priContext | (uint32_t)partId << 13;
}
- void serialize(std::ostream & os);
+ void serialize(EventManager *em, std::ostream & os);
- void unserialize(Checkpoint * cp, const std::string & section);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string & section);
void copyMiscRegs(ThreadContext * tc);
diff --git a/src/arch/sparc/pagetable.hh b/src/arch/sparc/pagetable.hh
index bf7f34b60..cbdabe4c3 100644
--- a/src/arch/sparc/pagetable.hh
+++ b/src/arch/sparc/pagetable.hh
@@ -31,6 +31,8 @@
#ifndef __ARCH_SPARC_PAGETABLE_HH__
#define __ARCH_SPARC_PAGETABLE_HH__
+#include <cassert>
+
#include "arch/sparc/isa_traits.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
@@ -38,8 +40,8 @@
class Checkpoint;
-namespace SparcISA
-{
+namespace SparcISA {
+
struct VAddr
{
VAddr(Addr a) { panic("not implemented yet."); }
@@ -54,8 +56,15 @@ class TteTag
public:
TteTag() : entry(0), populated(false) {}
TteTag(uint64_t e) : entry(e), populated(true) {}
- const TteTag &operator=(uint64_t e) { populated = true;
- entry = e; return *this; }
+
+ const TteTag &
+ operator=(uint64_t e)
+ {
+ populated = true;
+ entry = e;
+ return *this;
+ }
+
bool valid() const {assert(populated); return !bits(entry,62,62); }
Addr va() const {assert(populated); return bits(entry,41,0); }
};
@@ -76,13 +85,13 @@ class PageTableEntry
uint64_t entry4u;
bool populated;
-
public:
- PageTableEntry() : entry(0), type(invalid), populated(false) {}
+ PageTableEntry()
+ : entry(0), type(invalid), populated(false)
+ {}
PageTableEntry(uint64_t e, EntryType t = sun4u)
: entry(e), type(t), populated(true)
-
{
populate(entry, type);
}
@@ -113,49 +122,74 @@ class PageTableEntry
}
}
- void clear()
+ void
+ clear()
{
populated = false;
}
static int pageSizes[6];
-
uint64_t operator()() const { assert(populated); return entry4u; }
- const PageTableEntry &operator=(uint64_t e) { populated = true;
- entry4u = e; return *this; }
-
- const PageTableEntry &operator=(const PageTableEntry &e)
- { populated = true; entry4u = e.entry4u; type = e.type; return *this; }
-
- bool valid() const { return bits(entry4u,63,63) && populated; }
- uint8_t _size() const { assert(populated);
- return bits(entry4u, 62,61) |
- bits(entry4u, 48,48) << 2; }
- Addr size() const { assert(_size() < 6); return pageSizes[_size()]; }
- Addr sizeMask() const { assert(_size() < 6); return pageSizes[_size()]-1;}
- bool ie() const { return bits(entry4u, 59,59); }
- Addr pfn() const { assert(populated); return bits(entry4u,39,13); }
- Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);}
- bool locked() const { assert(populated); return bits(entry4u,6,6); }
- bool cv() const { assert(populated); return bits(entry4u,4,4); }
- bool cp() const { assert(populated); return bits(entry4u,5,5); }
- bool priv() const { assert(populated); return bits(entry4u,2,2); }
- bool writable() const { assert(populated); return bits(entry4u,1,1); }
- bool nofault() const { assert(populated); return bits(entry4u,60,60); }
- bool sideffect() const { assert(populated); return bits(entry4u,3,3); }
- Addr paddrMask() const { assert(populated);
- return mbits(entry4u, 39,13) & ~sizeMask(); }
+ const PageTableEntry &
+ operator=(uint64_t e)
+ {
+ populated = true;
+ entry4u = e;
+ return *this;
+ }
+
+ const PageTableEntry &
+ operator=(const PageTableEntry &e)
+ {
+ populated = true;
+ entry4u = e.entry4u;
+ type = e.type;
+ return *this;
+ }
+
+ bool valid() const { return bits(entry4u,63,63) && populated; }
+
+ uint8_t
+ _size() const
+ {
+ assert(populated);
+ return bits(entry4u, 62,61) | bits(entry4u, 48,48) << 2;
+ }
+
+ Addr size() const { assert(_size() < 6); return pageSizes[_size()]; }
+ Addr sizeMask() const { return size() - 1; }
+ bool ie() const { return bits(entry4u, 59,59); }
+ Addr pfn() const { assert(populated); return bits(entry4u,39,13); }
+ Addr paddr() const { assert(populated); return mbits(entry4u, 39,13);}
+ bool locked() const { assert(populated); return bits(entry4u,6,6); }
+ bool cv() const { assert(populated); return bits(entry4u,4,4); }
+ bool cp() const { assert(populated); return bits(entry4u,5,5); }
+ bool priv() const { assert(populated); return bits(entry4u,2,2); }
+ bool writable() const { assert(populated); return bits(entry4u,1,1); }
+ bool nofault() const { assert(populated); return bits(entry4u,60,60); }
+ bool sideffect() const { assert(populated); return bits(entry4u,3,3); }
+ Addr paddrMask() const { assert(populated); return paddr() & ~sizeMask(); }
+
+ Addr
+ translate(Addr vaddr) const
+ {
+ assert(populated);
+ Addr mask = sizeMask();
+ return (paddr() & ~mask) | (vaddr & mask);
+ }
};
-struct TlbRange {
+struct TlbRange
+{
Addr va;
Addr size;
int contextId;
int partitionId;
bool real;
- inline bool operator<(const TlbRange &r2) const
+ inline bool
+ operator<(const TlbRange &r2) const
{
if (real && !r2.real)
return true;
@@ -178,7 +212,9 @@ struct TlbRange {
return true;
return false;
}
- inline bool operator==(const TlbRange &r2) const
+
+ inline bool
+ operator==(const TlbRange &r2) const
{
return va == r2.va &&
size == r2.size &&
@@ -189,7 +225,11 @@ struct TlbRange {
};
-struct TlbEntry {
+struct TlbEntry
+{
+ TlbEntry()
+ {}
+
TlbEntry(Addr asn, Addr vaddr, Addr paddr)
{
uint64_t entry = 0;
@@ -215,8 +255,7 @@ struct TlbEntry {
valid = true;
}
- TlbEntry()
- {}
+
TlbRange range;
PageTableEntry pte;
bool used;
@@ -227,13 +266,17 @@ struct TlbEntry {
return pte.paddr();
}
+ void
+ updateVaddr(Addr new_vaddr)
+ {
+ range.va = new_vaddr;
+ }
+
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
-
};
-
-}; // namespace SparcISA
+} // namespace SparcISA
#endif // __ARCH_SPARC_PAGE_TABLE_HH__
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index 6e490e05e..b2b539816 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -46,6 +46,9 @@
using namespace std;
using namespace SparcISA;
+static const int FirstArgumentReg = 8;
+static const int ReturnValueReg = 8;
+
SparcLiveProcess::SparcLiveProcess(LiveProcessParams * params,
ObjectFile *objFile, Addr _StackBias)
@@ -112,44 +115,45 @@ SparcLiveProcess::startup()
{
Process::startup();
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
//From the SPARC ABI
//Setup default FP state
- threadContexts[0]->setMiscRegNoEffect(MISCREG_FSR, 0);
+ tc->setMiscRegNoEffect(MISCREG_FSR, 0);
- threadContexts[0]->setMiscRegNoEffect(MISCREG_TICK, 0);
+ tc->setMiscRegNoEffect(MISCREG_TICK, 0);
/*
* Register window management registers
*/
//No windows contain info from other programs
- //threadContexts[0]->setMiscRegNoEffect(MISCREG_OTHERWIN, 0);
- threadContexts[0]->setIntReg(NumIntArchRegs + 6, 0);
+ //tc->setMiscRegNoEffect(MISCREG_OTHERWIN, 0);
+ tc->setIntReg(NumIntArchRegs + 6, 0);
//There are no windows to pop
- //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANRESTORE, 0);
- threadContexts[0]->setIntReg(NumIntArchRegs + 4, 0);
+ //tc->setMiscRegNoEffect(MISCREG_CANRESTORE, 0);
+ tc->setIntReg(NumIntArchRegs + 4, 0);
//All windows are available to save into
- //threadContexts[0]->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2);
- threadContexts[0]->setIntReg(NumIntArchRegs + 3, NWindows - 2);
+ //tc->setMiscRegNoEffect(MISCREG_CANSAVE, NWindows - 2);
+ tc->setIntReg(NumIntArchRegs + 3, NWindows - 2);
//All windows are "clean"
- //threadContexts[0]->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows);
- threadContexts[0]->setIntReg(NumIntArchRegs + 5, NWindows);
+ //tc->setMiscRegNoEffect(MISCREG_CLEANWIN, NWindows);
+ tc->setIntReg(NumIntArchRegs + 5, NWindows);
//Start with register window 0
- threadContexts[0]->setMiscRegNoEffect(MISCREG_CWP, 0);
+ tc->setMiscRegNoEffect(MISCREG_CWP, 0);
//Always use spill and fill traps 0
- //threadContexts[0]->setMiscRegNoEffect(MISCREG_WSTATE, 0);
- threadContexts[0]->setIntReg(NumIntArchRegs + 7, 0);
+ //tc->setMiscRegNoEffect(MISCREG_WSTATE, 0);
+ tc->setIntReg(NumIntArchRegs + 7, 0);
//Set the trap level to 0
- threadContexts[0]->setMiscRegNoEffect(MISCREG_TL, 0);
+ tc->setMiscRegNoEffect(MISCREG_TL, 0);
//Set the ASI register to something fixed
- threadContexts[0]->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
+ tc->setMiscRegNoEffect(MISCREG_ASI, ASI_PRIMARY);
/*
* T1 specific registers
*/
//Turn on the icache, dcache, dtb translation, and itb translation.
- threadContexts[0]->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15);
+ tc->setMiscRegNoEffect(MISCREG_MMU_LSU_CTRL, 15);
}
void
@@ -160,8 +164,9 @@ Sparc32LiveProcess::startup()
SparcLiveProcess::startup();
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
//The process runs in user mode with 32 bit addresses
- threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x0a);
+ tc->setMiscReg(MISCREG_PSTATE, 0x0a);
argsInit(32 / 8, VMPageSize);
}
@@ -174,8 +179,9 @@ Sparc64LiveProcess::startup()
SparcLiveProcess::startup();
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
//The process runs in user mode
- threadContexts[0]->setMiscReg(MISCREG_PSTATE, 0x02);
+ tc->setMiscReg(MISCREG_PSTATE, 0x02);
argsInit(sizeof(IntReg), VMPageSize);
}
@@ -186,7 +192,7 @@ SparcLiveProcess::argsInit(int pageSize)
{
int intSize = sizeof(IntType);
- typedef M5_auxv_t<IntType> auxv_t;
+ typedef AuxVector<IntType> auxv_t;
std::vector<auxv_t> auxv;
@@ -335,18 +341,18 @@ SparcLiveProcess::argsInit(int pageSize)
IntType window_save_base = argc_base - window_save_size;
#endif
- DPRINTF(Sparc, "The addresses of items on the initial stack:\n");
- DPRINTF(Sparc, "%#x - sentry NULL\n", sentry_base);
- DPRINTF(Sparc, "filename = %s\n", filename);
- DPRINTF(Sparc, "%#x - file name\n", file_name_base);
- DPRINTF(Sparc, "%#x - env data\n", env_data_base);
- DPRINTF(Sparc, "%#x - arg data\n", arg_data_base);
- DPRINTF(Sparc, "%#x - auxv array\n", auxv_array_base);
- DPRINTF(Sparc, "%#x - envp array\n", envp_array_base);
- DPRINTF(Sparc, "%#x - argv array\n", argv_array_base);
- DPRINTF(Sparc, "%#x - argc \n", argc_base);
- DPRINTF(Sparc, "%#x - window save\n", window_save_base);
- DPRINTF(Sparc, "%#x - stack min\n", stack_min);
+ DPRINTF(Stack, "The addresses of items on the initial stack:\n");
+ DPRINTF(Stack, "%#x - sentry NULL\n", sentry_base);
+ DPRINTF(Stack, "filename = %s\n", filename);
+ DPRINTF(Stack, "%#x - file name\n", file_name_base);
+ DPRINTF(Stack, "%#x - env data\n", env_data_base);
+ DPRINTF(Stack, "%#x - arg data\n", arg_data_base);
+ DPRINTF(Stack, "%#x - auxv array\n", auxv_array_base);
+ DPRINTF(Stack, "%#x - envp array\n", envp_array_base);
+ DPRINTF(Stack, "%#x - argv array\n", argv_array_base);
+ DPRINTF(Stack, "%#x - argc \n", argc_base);
+ DPRINTF(Stack, "%#x - window save\n", window_save_base);
+ DPRINTF(Stack, "%#x - stack min\n", stack_min);
assert(window_save_base == stack_min);
@@ -354,7 +360,7 @@ SparcLiveProcess::argsInit(int pageSize)
// figure out argc
IntType argc = argv.size();
- IntType guestArgc = TheISA::htog(argc);
+ IntType guestArgc = SparcISA::htog(argc);
//Write out the sentry void *
uint64_t sentry_NULL = 0;
@@ -391,20 +397,21 @@ SparcLiveProcess::argsInit(int pageSize)
fillStart = stack_base;
spillStart = fillStart + sizeof(MachInst) * numFillInsts;
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
//Set up the thread context to start running the process
//assert(NumArgumentRegs >= 2);
- //threadContexts[0]->setIntReg(ArgumentReg[0], argc);
- //threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base);
- threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
+ //tc->setIntReg(ArgumentReg[0], argc);
+ //tc->setIntReg(ArgumentReg[1], argv_array_base);
+ tc->setIntReg(StackPointerReg, stack_min - StackBias);
// %g1 is a pointer to a function that should be run at exit. Since we
// don't have anything like that, it should be set to 0.
- threadContexts[0]->setIntReg(1, 0);
+ tc->setIntReg(1, 0);
Addr prog_entry = objFile->entryPoint();
- threadContexts[0]->setPC(prog_entry);
- threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
- threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ tc->setPC(prog_entry);
+ tc->setNextPC(prog_entry + sizeof(MachInst));
+ tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
@@ -505,3 +512,63 @@ void Sparc64LiveProcess::flushWindows(ThreadContext *tc)
tc->setIntReg(NumIntArchRegs + 4, Canrestore);
tc->setMiscReg(MISCREG_CWP, origCWP);
}
+
+IntReg
+Sparc32LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < 6);
+ return bits(tc->readIntReg(FirstArgumentReg + i), 31, 0);
+}
+
+void
+Sparc32LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val)
+{
+ assert(i < 6);
+ tc->setIntReg(FirstArgumentReg + i, bits(val, 31, 0));
+}
+
+IntReg
+Sparc64LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < 6);
+ return tc->readIntReg(FirstArgumentReg + i);
+}
+
+void
+Sparc64LiveProcess::setSyscallArg(ThreadContext *tc, int i, IntReg val)
+{
+ assert(i < 6);
+ tc->setIntReg(FirstArgumentReg + i, val);
+}
+
+void
+SparcLiveProcess::setSyscallReturn(ThreadContext *tc,
+ SyscallReturn return_value)
+{
+ // 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
+ tc->setIntReg(NumIntArchRegs + 2,
+ tc->readIntReg(NumIntArchRegs + 2) & 0xEE);
+ //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) & 0xEE);
+ IntReg val = return_value.value();
+ if (bits(tc->readMiscRegNoEffect(
+ SparcISA::MISCREG_PSTATE), 3, 3)) {
+ val = bits(val, 31, 0);
+ }
+ tc->setIntReg(ReturnValueReg, val);
+ } else {
+ // got an error, set XCC.C
+ tc->setIntReg(NumIntArchRegs + 2,
+ tc->readIntReg(NumIntArchRegs + 2) | 0x11);
+ //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) | 0x11);
+ IntReg val = -return_value.value();
+ if (bits(tc->readMiscRegNoEffect(
+ SparcISA::MISCREG_PSTATE), 3, 3)) {
+ val = bits(val, 31, 0);
+ }
+ tc->setIntReg(ReturnValueReg, val);
+ }
+}
diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh
index a37760139..fdb9734ba 100644
--- a/src/arch/sparc/process.hh
+++ b/src/arch/sparc/process.hh
@@ -69,26 +69,7 @@ class SparcLiveProcess : public LiveProcess
{ return spillStart; }
virtual void flushWindows(ThreadContext *tc) = 0;
-};
-
-template<class IntType>
-struct M5_auxv_t
-{
- IntType a_type;
- union {
- IntType a_val;
- IntType a_ptr;
- IntType a_fcn;
- };
-
- M5_auxv_t()
- {}
-
- M5_auxv_t(IntType type, IntType val)
- {
- a_type = SparcISA::htog(type);
- a_val = SparcISA::htog(val);
- }
+ void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
};
class Sparc32LiveProcess : public SparcLiveProcess
@@ -113,6 +94,9 @@ class Sparc32LiveProcess : public SparcLiveProcess
void argsInit(int intSize, int pageSize);
void flushWindows(ThreadContext *tc);
+
+ SparcISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val);
};
class Sparc64LiveProcess : public SparcLiveProcess
@@ -138,6 +122,9 @@ class Sparc64LiveProcess : public SparcLiveProcess
void argsInit(int intSize, int pageSize);
void flushWindows(ThreadContext *tc);
+
+ SparcISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, SparcISA::IntReg val);
};
#endif // __SPARC_PROCESS_HH__
diff --git a/src/arch/sparc/regfile.cc b/src/arch/sparc/regfile.cc
index d6be52424..1c172a4d5 100644
--- a/src/arch/sparc/regfile.cc
+++ b/src/arch/sparc/regfile.cc
@@ -155,7 +155,7 @@ int SparcISA::flattenIntIndex(ThreadContext * tc, int reg)
{
int gl = tc->readMiscRegNoEffect(MISCREG_GL);
int cwp = tc->readMiscRegNoEffect(MISCREG_CWP);
- //DPRINTF(Sparc, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp);
+ //DPRINTF(RegisterWindows, "Global Level = %d, Current Window Pointer = %d\n", gl, cwp);
int newReg;
//The total number of global registers
int numGlobals = (MaxGL + 1) * 8;
@@ -214,46 +214,33 @@ int SparcISA::flattenIntIndex(ThreadContext * tc, int reg)
}
else
panic("Tried to flatten invalid register index %d!\n", reg);
- DPRINTF(Sparc, "Flattened register %d to %d.\n", reg, newReg);
+ DPRINTF(RegisterWindows, "Flattened register %d to %d.\n", reg, newReg);
return newReg;
//return intRegFile.flattenIndex(reg);
}
-void RegFile::serialize(std::ostream &os)
+void
+RegFile::serialize(EventManager *em, ostream &os)
{
intRegFile.serialize(os);
floatRegFile.serialize(os);
- miscRegFile.serialize(os);
+ miscRegFile.serialize(em, os);
SERIALIZE_SCALAR(pc);
SERIALIZE_SCALAR(npc);
SERIALIZE_SCALAR(nnpc);
}
-void RegFile::unserialize(Checkpoint *cp, const std::string &section)
+void
+RegFile::unserialize(EventManager *em, Checkpoint *cp, const string &section)
{
intRegFile.unserialize(cp, section);
floatRegFile.unserialize(cp, section);
- miscRegFile.unserialize(cp, section);
+ miscRegFile.unserialize(em, cp, section);
UNSERIALIZE_SCALAR(pc);
UNSERIALIZE_SCALAR(npc);
UNSERIALIZE_SCALAR(nnpc);
}
-void RegFile::changeContext(RegContextParam param, RegContextVal 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 SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
{
@@ -366,12 +353,12 @@ void SparcISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
void SparcISA::copyRegs(ThreadContext *src, ThreadContext *dest)
{
// First loop through the integer registers.
- for (int i = 0; i < TheISA::NumIntRegs; ++i) {
+ for (int i = 0; i < SparcISA::NumIntRegs; ++i) {
dest->setIntReg(i, src->readIntReg(i));
}
// Then loop through the floating point registers.
- for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
+ for (int i = 0; i < SparcISA::NumFloatRegs; ++i) {
dest->setFloatRegBits(i, src->readFloatRegBits(i));
}
diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh
index c03f69fc5..505d7c8d7 100644
--- a/src/arch/sparc/regfile.hh
+++ b/src/arch/sparc/regfile.hh
@@ -48,8 +48,8 @@ namespace SparcISA
class RegFile
{
protected:
- Addr pc; // Program Counter
- Addr npc; // Next Program Counter
+ Addr pc; // Program Counter
+ Addr npc; // Next Program Counter
Addr nnpc;
public:
@@ -63,16 +63,14 @@ namespace SparcISA
void setNextNPC(Addr val);
protected:
- IntRegFile intRegFile; // integer register file
- FloatRegFile floatRegFile; // floating point register file
- MiscRegFile miscRegFile; // control register file
+ IntRegFile intRegFile; // integer register file
+ FloatRegFile floatRegFile; // floating point register file
+ MiscRegFile miscRegFile; // control register file
public:
void clear();
- int FlattenIntIndex(int reg);
-
MiscReg readMiscRegNoEffect(int miscReg);
MiscReg readMiscReg(int miscReg, ThreadContext *tc);
@@ -112,12 +110,11 @@ namespace SparcISA
void setIntReg(int intReg, const IntReg &val);
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
+ void serialize(EventManager *em, std::ostream &os);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section);
public:
-
- void changeContext(RegContextParam param, RegContextVal val);
};
int flattenIntIndex(ThreadContext * tc, int reg);
diff --git a/src/arch/sparc/remote_gdb.cc b/src/arch/sparc/remote_gdb.cc
index 67cc5b0d1..615c5b551 100644
--- a/src/arch/sparc/remote_gdb.cc
+++ b/src/arch/sparc/remote_gdb.cc
@@ -30,7 +30,7 @@
/*
* Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -38,8 +38,8 @@
*
* 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.
+ * 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
@@ -51,8 +51,8 @@
* 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.
+ * 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.
@@ -69,7 +69,7 @@
* 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
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
*/
/*-
@@ -89,8 +89,8 @@
* 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.
+ * 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.
@@ -137,7 +137,7 @@
#include "sim/system.hh"
using namespace std;
-using namespace TheISA;
+using namespace SparcISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
: BaseRemoteGDB(_system, c, NumGDBRegs), nextBkpt(0)
@@ -146,7 +146,7 @@ RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
///////////////////////////////////////////////////////////
// RemoteGDB::acc
//
-// Determine if the mapping at va..(va+len) is valid.
+// Determine if the mapping at va..(va+len) is valid.
//
bool
RemoteGDB::acc(Addr va, size_t len)
@@ -171,8 +171,8 @@ RemoteGDB::acc(Addr va, size_t len)
///////////////////////////////////////////////////////////
// RemoteGDB::getregs
//
-// Translate the kernel debugger register format into
-// the GDB register format.
+// Translate the kernel debugger register format into
+// the GDB register format.
void
RemoteGDB::getregs()
{
@@ -217,8 +217,8 @@ RemoteGDB::getregs()
///////////////////////////////////////////////////////////
// RemoteGDB::setregs
//
-// Translate the GDB register format into the kernel
-// debugger register format.
+// Translate the GDB register format into the kernel
+// debugger register format.
//
void
RemoteGDB::setregs()
diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc
index 40d172690..22924736b 100644
--- a/src/arch/sparc/solaris/process.cc
+++ b/src/arch/sparc/solaris/process.cc
@@ -48,7 +48,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Solaris::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Solaris::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "SunOS");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -80,7 +80,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<Solaris>),
/* 16 */ SyscallDesc("chown", chownFunc),
- /* 17 */ SyscallDesc("brk", obreakFunc),
+ /* 17 */ SyscallDesc("brk", brkFunc),
/* 18 */ SyscallDesc("stat", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -123,7 +123,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
/* 57 */ SyscallDesc("utssys", unimplementedFunc),
/* 58 */ SyscallDesc("fdsync", unimplementedFunc),
/* 59 */ SyscallDesc("execve", unimplementedFunc),
- /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", umaskFunc),
/* 61 */ SyscallDesc("chroot", unimplementedFunc),
/* 62 */ SyscallDesc("fcntl", unimplementedFunc),
/* 63 */ SyscallDesc("ulimit", unimplementedFunc),
@@ -153,7 +153,7 @@ SyscallDesc SparcSolarisProcess::syscallDescs[] = {
/* 87 */ SyscallDesc("poll", unimplementedFunc),
/* 88 */ SyscallDesc("lstat", unimplementedFunc),
/* 89 */ SyscallDesc("symlink", unimplementedFunc),
- /* 90 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 90 */ SyscallDesc("readlink", readlinkFunc),
/* 91 */ SyscallDesc("setgroups", unimplementedFunc),
/* 92 */ SyscallDesc("getgroups", unimplementedFunc),
/* 93 */ SyscallDesc("fchmod", unimplementedFunc),
@@ -336,7 +336,7 @@ SparcSolarisProcess::SparcSolarisProcess(LiveProcessParams * params,
SyscallDesc*
SparcSolarisProcess::getDesc(int callnum)
{
- if (callnum < 0 || callnum > Num_Syscall_Descs)
+ if (callnum < 0 || callnum >= Num_Syscall_Descs)
return NULL;
return &syscallDescs[callnum];
}
diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc
index c53caa72a..3cc910005 100644
--- a/src/arch/sparc/solaris/solaris.cc
+++ b/src/arch/sparc/solaris/solaris.cc
@@ -35,40 +35,40 @@
// 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 },
+ { 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 },
+ { SparcSolaris::TGT_O_NONBLOCK, _O_NONBLOCK },
+ { SparcSolaris::TGT_O_NDELAY , _O_NONBLOCK },
#endif
#ifdef _O_NOCTTY
- { SparcSolaris::TGT_O_NOCTTY, _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 },
+ { 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 },
+ { 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 },
+ { SparcSolaris::TGT_O_SYNC, O_SYNC },
+ { SparcSolaris::TGT_O_DSYNC, O_SYNC },
+ { SparcSolaris::TGT_O_RSYNC, O_SYNC },
#endif
#endif /* _MSC_VER */
};
diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh
index 0564faba4..df2565027 100644
--- a/src/arch/sparc/solaris/solaris.hh
+++ b/src/arch/sparc/solaris/solaris.hh
@@ -39,22 +39,22 @@ class SparcSolaris : public Solaris
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_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 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;
diff --git a/src/arch/sparc/sparc_traits.hh b/src/arch/sparc/sparc_traits.hh
index 715c08c03..e154ba274 100644
--- a/src/arch/sparc/sparc_traits.hh
+++ b/src/arch/sparc/sparc_traits.hh
@@ -47,8 +47,8 @@ namespace SparcISA
// const int NumRegularIntRegs = MaxGL * 8 + NWindows * 16;
// const int NumMicroIntRegs = 1;
// const int NumIntRegs =
-// NumRegularIntRegs +
-// NumMicroIntRegs;
+// NumRegularIntRegs +
+// NumMicroIntRegs;
// const int NumFloatRegs = 64;
// const int NumMiscRegs = 40;
}
diff --git a/src/arch/sparc/stacktrace.cc b/src/arch/sparc/stacktrace.cc
index 2d7991267..3ab0edb57 100644
--- a/src/arch/sparc/stacktrace.cc
+++ b/src/arch/sparc/stacktrace.cc
@@ -70,8 +70,6 @@ namespace SparcISA
if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
panic("thread info not compiled into kernel\n");
name_off = vp->readGtoH<int32_t>(addr);
-
- tc->delVirtPort(vp);
}
Addr
@@ -87,7 +85,6 @@ namespace SparcISA
vp = tc->getVirtPort();
tsk = vp->readGtoH<Addr>(base + task_off);
- tc->delVirtPort(vp);
return tsk;
}
@@ -105,7 +102,6 @@ namespace SparcISA
vp = tc->getVirtPort();
pd = vp->readGtoH<uint16_t>(task + pid_off);
- tc->delVirtPort(vp);
return pd;
}
@@ -163,7 +159,7 @@ namespace SparcISA
}
SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
- Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
+ Addr ksp = tc->readIntReg(SparcISA::StackPointerReg);
Addr bottom = ksp & ~0x3fff;
Addr addr;
diff --git a/src/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh
index 4bc5d779b..929990fcb 100644
--- a/src/arch/sparc/stacktrace.hh
+++ b/src/arch/sparc/stacktrace.hh
@@ -61,7 +61,7 @@ namespace SparcISA
class StackTrace
{
protected:
- typedef TheISA::MachInst MachInst;
+ typedef SparcISA::MachInst MachInst;
private:
ThreadContext *tc;
std::vector<Addr> stack;
diff --git a/src/arch/sparc/syscallreturn.hh b/src/arch/sparc/syscallreturn.hh
deleted file mode 100644
index cf13fc3e8..000000000
--- a/src/arch/sparc/syscallreturn.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.
- *
- * Authors: Gabe Black
- */
-
-#ifndef __ARCH_SPARC_SYSCALLRETURN_HH__
-#define __ARCH_SPARC_SYSCALLRETURN_HH__
-
-#include <inttypes.h>
-
-#include "sim/syscallreturn.hh"
-#include "arch/sparc/regfile.hh"
-#include "cpu/thread_context.hh"
-
-namespace SparcISA
-{
- static inline void setSyscallReturn(SyscallReturn return_value,
- ThreadContext * tc)
- {
- // 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
- tc->setIntReg(NumIntArchRegs + 2,
- tc->readIntReg(NumIntArchRegs + 2) & 0xEE);
- //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) & 0xEE);
- tc->setIntReg(ReturnValueReg, return_value.value());
- } else {
- // got an error, set XCC.C
- tc->setIntReg(NumIntArchRegs + 2,
- tc->readIntReg(NumIntArchRegs + 2) | 0x11);
- //tc->setMiscRegNoEffect(MISCREG_CCR, tc->readMiscRegNoEffect(MISCREG_CCR) | 0x11);
- tc->setIntReg(ReturnValueReg, -return_value.value());
- }
- }
-};
-
-#endif
diff --git a/src/arch/sparc/tlb.cc b/src/arch/sparc/tlb.cc
index 22df44908..95ad0229e 100644
--- a/src/arch/sparc/tlb.cc
+++ b/src/arch/sparc/tlb.cc
@@ -51,7 +51,7 @@ TLB::TLB(const Params *p)
{
// To make this work you'll have to change the hypervisor and OS
if (size > 64)
- fatal("SPARC T1 TLB registers don't support more than 64 TLB entries.");
+ fatal("SPARC T1 TLB registers don't support more than 64 TLB entries");
tlb = new TlbEntry[size];
std::memset(tlb, 0, sizeof(TlbEntry) * size);
@@ -87,8 +87,6 @@ void
TLB::insert(Addr va, int partition_id, int context_id, bool real,
const PageTableEntry& PTE, int entry)
{
-
-
MapIter i;
TlbEntry *new_entry = NULL;
// TlbRange tr;
@@ -103,8 +101,9 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real,
tr.real = real;
*/
- DPRINTF(TLB, "TLB: Inserting TLB Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
- va, PTE.paddr(), partition_id, context_id, (int)real, entry);
+ DPRINTF(TLB,
+ "TLB: Inserting Entry; va=%#x pa=%#x pid=%d cid=%d r=%d entryid=%d\n",
+ va, PTE.paddr(), partition_id, context_id, (int)real, entry);
// Demap any entry that conflicts
for (x = 0; x < size; x++) {
@@ -128,7 +127,6 @@ TLB::insert(Addr va, int partition_id, int context_id, bool real,
}
}
-
/*
i = lookupTable.find(tr);
if (i != lookupTable.end()) {
@@ -195,25 +193,22 @@ insertAllLocked:
new_entry->valid = true;
usedEntries++;
-
-
i = lookupTable.insert(new_entry->range, new_entry);
assert(i != lookupTable.end());
- // If all entries have there used bit set, clear it on them all, but the
- // one we just inserted
+ // If all entries have their used bit set, clear it on them all,
+ // but the one we just inserted
if (usedEntries == size) {
clearUsedBits();
new_entry->used = true;
usedEntries++;
}
-
}
TlbEntry*
-TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool
- update_used)
+TLB::lookup(Addr va, int partition_id, bool real, int context_id,
+ bool update_used)
{
MapIter i;
TlbRange tr;
@@ -240,8 +235,8 @@ TLB::lookup(Addr va, int partition_id, bool real, int context_id, bool
DPRINTF(TLB, "TLB: Valid entry found pa: %#x size: %#x\n", t->pte.paddr(),
t->pte.size());
- // Update the used bits only if this is a real access (not a fake one from
- // virttophys()
+ // Update the used bits only if this is a real access (not a fake
+ // one from virttophys()
if (!t->used && update_used) {
t->used = true;
usedEntries++;
@@ -304,11 +299,10 @@ TLB::demapPage(Addr va, int partition_id, bool real, int context_id)
void
TLB::demapContext(int partition_id, int context_id)
{
- int x;
DPRINTF(IPR, "TLB: Demapping Context pid=%#d cid=%d\n",
partition_id, context_id);
cacheValid = false;
- for (x = 0; x < size; x++) {
+ for (int x = 0; x < size; x++) {
if (tlb[x].range.contextId == context_id &&
tlb[x].range.partitionId == partition_id) {
if (tlb[x].valid == true) {
@@ -327,10 +321,9 @@ TLB::demapContext(int partition_id, int context_id)
void
TLB::demapAll(int partition_id)
{
- int x;
DPRINTF(TLB, "TLB: Demapping All pid=%#d\n", partition_id);
cacheValid = false;
- for (x = 0; x < size; x++) {
+ for (int x = 0; x < size; x++) {
if (tlb[x].valid && !tlb[x].pte.locked() &&
tlb[x].range.partitionId == partition_id) {
freeList.push_front(&tlb[x]);
@@ -347,11 +340,10 @@ TLB::demapAll(int partition_id)
void
TLB::invalidateAll()
{
- int x;
cacheValid = false;
-
lookupTable.clear();
- for (x = 0; x < size; x++) {
+
+ for (int x = 0; x < size; x++) {
if (tlb[x].valid == true)
freeList.push_back(&tlb[x]);
tlb[x].valid = false;
@@ -361,7 +353,8 @@ TLB::invalidateAll()
}
uint64_t
-TLB::TteRead(int entry) {
+TLB::TteRead(int entry)
+{
if (entry >= size)
panic("entry: %d\n", entry);
@@ -373,7 +366,8 @@ TLB::TteRead(int entry) {
}
uint64_t
-TLB::TagRead(int entry) {
+TLB::TagRead(int entry)
+{
assert(entry < size);
uint64_t tag;
if (!tlb[entry].valid)
@@ -442,7 +436,7 @@ DTB::writeSfsr(Addr a, bool write, ContextType ct,
}
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
+ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
{
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
@@ -459,9 +453,8 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
if (cacheEntry) {
if (cacheEntry->range.va < vaddr + sizeof(MachInst) &&
cacheEntry->range.va + cacheEntry->range.size >= vaddr) {
- req->setPaddr(cacheEntry->pte.paddr() & ~(cacheEntry->pte.size()-1) |
- vaddr & cacheEntry->pte.size()-1 );
- return NoFault;
+ req->setPaddr(cacheEntry->pte.translate(vaddr));
+ return NoFault;
}
} else {
req->setPaddr(vaddr & PAddrImplMask);
@@ -550,18 +543,26 @@ ITB::translate(RequestPtr &req, ThreadContext *tc)
cacheState = tlbdata;
cacheEntry = e;
- req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
- vaddr & e->pte.size()-1 );
+ req->setPaddr(e->pte.translate(vaddr));
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
}
-
+void
+ITB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc), req, tc, false);
+}
Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
{
- /* @todo this could really use some profiling and fixing to make it faster! */
+ /*
+ * @todo this could really use some profiling and fixing to make
+ * it faster!
+ */
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
Addr vaddr = req->getVaddr();
Addr size = req->getSize();
@@ -569,7 +570,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
asi = (ASI)req->getAsi();
bool implicit = false;
bool hpriv = bits(tlbdata,0,0);
- bool unaligned = (vaddr & size-1);
+ bool unaligned = vaddr & (size - 1);
DPRINTF(TLB, "TLB: DTB Request to translate va=%#x size=%d asi=%#x\n",
vaddr, size, asi);
@@ -599,11 +600,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
if (cacheAsi[0] == asi &&
ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
(!write || ce->pte.writable())) {
- req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
- if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
- DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
- return NoFault;
+ req->setPaddr(ce->pte.translate(vaddr));
+ if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
+ req->setFlags(Request::UNCACHEABLE);
+ DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
+ return NoFault;
} // if matched
} // if cache entry valid
if (cacheEntry[1]) {
@@ -612,11 +613,11 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
if (cacheAsi[1] == asi &&
ce_va < vaddr + size && ce_va + ce->range.size > vaddr &&
(!write || ce->pte.writable())) {
- req->setPaddr(ce->pte.paddrMask() | vaddr & ce->pte.sizeMask());
- if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
- DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
- return NoFault;
+ req->setPaddr(ce->pte.translate(vaddr));
+ if (ce->pte.sideffect() || (ce->pte.paddr() >> 39) & 1)
+ req->setFlags(Request::UNCACHEABLE);
+ DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
+ return NoFault;
} // if matched
} // if cache entry valid
}
@@ -639,7 +640,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
TlbEntry *e;
DPRINTF(TLB, "TLB: priv:%d hpriv:%d red:%d lsudm:%d part_id: %#X\n",
- priv, hpriv, red, lsu_dm, part_id);
+ priv, hpriv, red, lsu_dm, part_id);
if (implicit) {
if (tl > 0) {
@@ -725,11 +726,10 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
return new DataAccessException;
}
-
if ((!lsu_dm && !hpriv && !red) || AsiIsReal(asi)) {
real = true;
context = 0;
- };
+ }
if (hpriv && (implicit || (!AsiIsAsIfUser(asi) && !AsiIsReal(asi)))) {
req->setPaddr(vaddr & PAddrImplMask);
@@ -776,9 +776,8 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
return new DataAccessException;
}
-
if (e->pte.sideffect() || (e->pte.paddr() >> 39) & 1)
- req->setFlags(req->getFlags() | UNCACHEABLE);
+ req->setFlags(Request::UNCACHEABLE);
// cache translation date for next translation
cacheState = tlbdata;
@@ -796,8 +795,7 @@ DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
cacheAsi[0] = (ASI)0;
}
cacheValid = true;
- req->setPaddr(e->pte.paddr() & ~(e->pte.size()-1) |
- vaddr & e->pte.size()-1);
+ req->setPaddr(e->pte.translate(vaddr));
DPRINTF(TLB, "TLB: %#X -> %#X\n", vaddr, req->getPaddr());
return NoFault;
@@ -811,8 +809,8 @@ handleIntRegAccess:
return new PrivilegedAction;
}
- if (asi == ASI_SWVR_UDB_INTR_W && !write ||
- asi == ASI_SWVR_UDB_INTR_R && write) {
+ if ((asi == ASI_SWVR_UDB_INTR_W && !write) ||
+ (asi == ASI_SWVR_UDB_INTR_R && write)) {
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new DataAccessException;
}
@@ -832,7 +830,7 @@ handleQueueRegAccess:
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new PrivilegedAction;
}
- if (!hpriv && vaddr & 0xF || vaddr > 0x3f8 || vaddr < 0x3c0) {
+ if ((!hpriv && vaddr & 0xF) || vaddr > 0x3f8 || vaddr < 0x3c0) {
writeSfsr(vaddr, write, Primary, true, IllegalAsi, asi);
return new DataAccessException;
}
@@ -857,6 +855,14 @@ handleMmuRegAccess:
return NoFault;
};
+void
+DTB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc, write), req, tc, write);
+}
+
#if FULL_SYSTEM
Tick
@@ -869,7 +875,7 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
DPRINTF(IPR, "Memory Mapped IPR Read: asi=%#X a=%#x\n",
(uint32_t)pkt->req->getAsi(), pkt->getAddr());
- ITB * itb = tc->getITBPtr();
+ ITB *itb = tc->getITBPtr();
switch (asi) {
case ASI_LSU_CONTROL_REG:
@@ -1018,12 +1024,22 @@ DTB::doMmuRegRead(ThreadContext *tc, Packet *pkt)
itb->cx_config));
break;
case ASI_SWVR_INTR_RECEIVE:
- pkt->set(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
+ {
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ pkt->set(interrupts->get_vec(IT_INT_VEC));
+ }
break;
case ASI_SWVR_UDB_INTR_R:
- temp = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC));
- tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, temp);
- pkt->set(temp);
+ {
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ temp = findMsbSet(interrupts->get_vec(IT_INT_VEC));
+ tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, temp);
+ pkt->set(temp);
+ }
break;
default:
doMmuReadError:
@@ -1055,7 +1071,7 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
DPRINTF(IPR, "Memory Mapped IPR Write: asi=%#X a=%#x d=%#X\n",
(uint32_t)asi, va, data);
- ITB * itb = tc->getITBPtr();
+ ITB *itb = tc->getITBPtr();
switch (asi) {
case ASI_LSU_CONTROL_REG:
@@ -1129,7 +1145,7 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
break;
case ASI_SPARC_ERROR_EN_REG:
case ASI_SPARC_ERROR_STATUS_REG:
- warn("Ignoring write to SPARC ERROR regsiter\n");
+ inform("Ignoring write to SPARC ERROR regsiter\n");
break;
case ASI_HYP_SCRATCHPAD:
case ASI_SCRATCHPAD:
@@ -1173,7 +1189,8 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
real_insert = bits(va, 9,9);
pte.populate(data, bits(va,10,10) ? PageTableEntry::sun4v :
PageTableEntry::sun4u);
- insert(va_insert, part_insert, ct_insert, real_insert, pte, entry_insert);
+ insert(va_insert, part_insert, ct_insert, real_insert, pte,
+ entry_insert);
break;
case ASI_IMMU_DEMAP:
ignore = false;
@@ -1261,18 +1278,23 @@ DTB::doMmuRegWrite(ThreadContext *tc, Packet *pkt)
}
break;
case ASI_SWVR_INTR_RECEIVE:
- int msb;
- // clear all the interrupts that aren't set in the write
- while(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data) {
- msb = findMsbSet(tc->getCpuPtr()->get_interrupts(IT_INT_VEC) & data);
- tc->getCpuPtr()->clear_interrupt(IT_INT_VEC, msb);
+ {
+ int msb;
+ // clear all the interrupts that aren't set in the write
+ SparcISA::Interrupts * interrupts =
+ dynamic_cast<SparcISA::Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ while (interrupts->get_vec(IT_INT_VEC) & data) {
+ msb = findMsbSet(interrupts->get_vec(IT_INT_VEC) & data);
+ tc->getCpuPtr()->clearInterrupt(IT_INT_VEC, msb);
+ }
}
break;
case ASI_SWVR_UDB_INTR_W:
tc->getSystemPtr()->threadContexts[bits(data,12,8)]->getCpuPtr()->
- post_interrupt(bits(data,5,0),0);
+ postInterrupt(bits(data, 5, 0), 0);
break;
- default:
+ default:
doMmuWriteError:
panic("need to impl DTB::doMmuRegWrite() got asi=%#x, va=%#x d=%#x\n",
(uint32_t)pkt->req->getAsi(), pkt->getAddr(), data);
@@ -1310,10 +1332,6 @@ DTB::GetTsbPtr(ThreadContext *tc, Addr addr, int ctx, Addr *ptrs)
itb->cx_config);
}
-
-
-
-
uint64_t
DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
uint64_t c0_config, uint64_t cX_tsb, uint64_t cX_config)
@@ -1341,7 +1359,6 @@ DTB::MakeTsbPtr(TsbPageSize ps, uint64_t tag_access, uint64_t c0_tsb,
return ptr;
}
-
void
TLB::serialize(std::ostream &os)
{
diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh
index 2f7d08320..4fe532d4a 100644
--- a/src/arch/sparc/tlb.hh
+++ b/src/arch/sparc/tlb.hh
@@ -109,9 +109,9 @@ class TLB : public BaseTLB
* @param paritition_id partition this entry is for
* @param real is this a real->phys or virt->phys translation
* @param context_id if this is virt->phys what context
- * @param update_used should ew update the used bits in the entries on not
- * useful if we are trying to do a va->pa without mucking with any state for
- * a debug read for example.
+ * @param update_used should ew update the used bits in the
+ * entries on not useful if we are trying to do a va->pa without
+ * mucking with any state for a debug read for example.
* @return A pointer to a tlb entry
*/
TlbEntry *lookup(Addr va, int partition_id, bool real, int context_id = 0,
@@ -177,7 +177,9 @@ class ITB : public TLB
cacheEntry = NULL;
}
- Fault translate(RequestPtr &req, ThreadContext *tc);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation);
private:
void writeSfsr(bool write, ContextType ct,
bool se, FaultTypes ft, int asi);
@@ -199,7 +201,10 @@ class DTB : public TLB
cacheEntry[1] = NULL;
}
- Fault translate(RequestPtr &req, ThreadContext *tc, bool write);
+ Fault translateAtomic(RequestPtr req,
+ ThreadContext *tc, bool write=false);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write=false);
#if FULL_SYSTEM
Tick doMmuRegRead(ThreadContext *tc, Packet *pkt);
Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt);
diff --git a/src/arch/sparc/tlb_map.hh b/src/arch/sparc/tlb_map.hh
index 8285db939..fa49584ba 100644
--- a/src/arch/sparc/tlb_map.hh
+++ b/src/arch/sparc/tlb_map.hh
@@ -52,7 +52,7 @@ class TlbMap
i = tree.upper_bound(r);
- if (i == tree.begin())
+ if (i == tree.begin()) {
if (r.real == i->first.real &&
r.partitionId == i->first.partitionId &&
i->first.va < r.va + r.size &&
@@ -62,6 +62,7 @@ class TlbMap
else
// Nothing could match, so return end()
return tree.end();
+ }
i--;
diff --git a/src/arch/sparc/types.hh b/src/arch/sparc/types.hh
index d19e2a99f..dd369cc26 100644
--- a/src/arch/sparc/types.hh
+++ b/src/arch/sparc/types.hh
@@ -51,14 +51,6 @@ namespace SparcISA
MiscReg ctrlreg;
} AnyReg;
- enum RegContextParam
- {
- CONTEXT_CWP,
- CONTEXT_GLOBALS
- };
-
- typedef int RegContextVal;
-
typedef uint16_t RegIndex;
struct CoreSpecific {
diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc
index fe733813c..880d2c3eb 100644
--- a/src/arch/sparc/ua2005.cc
+++ b/src/arch/sparc/ua2005.cc
@@ -35,34 +35,59 @@
#include "sim/system.hh"
using namespace SparcISA;
+using namespace std;
void
MiscRegFile::checkSoftInt(ThreadContext *tc)
{
+ BaseCPU *cpu = tc->getCpuPtr();
+
// If PIL < 14, copy over the tm and sm bits
if (pil < 14 && softint & 0x10000)
- tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,16);
+ cpu->postInterrupt(IT_SOFT_INT, 16);
else
- tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,16);
+ cpu->clearInterrupt(IT_SOFT_INT, 16);
if (pil < 14 && softint & 0x1)
- tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,0);
+ cpu->postInterrupt(IT_SOFT_INT, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,0);
+ cpu->clearInterrupt(IT_SOFT_INT, 0);
// Copy over any of the other bits that are set
for (int bit = 15; bit > 0; --bit) {
if (1 << bit & softint && bit > pil)
- tc->getCpuPtr()->post_interrupt(IT_SOFT_INT,bit);
+ cpu->postInterrupt(IT_SOFT_INT, bit);
else
- tc->getCpuPtr()->clear_interrupt(IT_SOFT_INT,bit);
+ cpu->clearInterrupt(IT_SOFT_INT, bit);
}
}
+//These functions map register indices to names
+static inline string
+getMiscRegName(RegIndex index)
+{
+ static string miscRegName[NumMiscRegs] =
+ {/*"y", "ccr",*/ "asi", "tick", "fprs", "pcr", "pic",
+ "gsr", "softint_set", "softint_clr", "softint", "tick_cmpr",
+ "stick", "stick_cmpr",
+ "tpc", "tnpc", "tstate", "tt", "privtick", "tba", "pstate", "tl",
+ "pil", "cwp", /*"cansave", "canrestore", "cleanwin", "otherwin",
+ "wstate",*/ "gl",
+ "hpstate", "htstate", "hintp", "htba", "hver", "strand_sts_reg",
+ "hstick_cmpr",
+ "fsr", "prictx", "secctx", "partId", "lsuCtrlReg",
+ "scratch0", "scratch1", "scratch2", "scratch3", "scratch4",
+ "scratch5", "scratch6", "scratch7", "cpuMondoHead", "cpuMondoTail",
+ "devMondoHead", "devMondoTail", "resErrorHead", "resErrorTail",
+ "nresErrorHead", "nresErrorTail", "TlbData" };
+ return miscRegName[index];
+}
void
MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
{
+ BaseCPU *cpu = tc->getCpuPtr();
+
int64_t time;
switch (miscReg) {
/* Full system only ASRs */
@@ -80,12 +105,12 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
tickCompare = new TickCompareEvent(this, tc);
setRegNoEffect(miscReg, val);
if ((tick_cmpr & ~mask(63)) && tickCompare->scheduled())
- tickCompare->deschedule();
+ cpu->deschedule(tickCompare);
time = (tick_cmpr & mask(63)) - (tick & mask(63));
if (!(tick_cmpr & ~mask(63)) && time > 0) {
if (tickCompare->scheduled())
- tickCompare->deschedule();
- tickCompare->schedule(time * tc->getCpuPtr()->ticks(1));
+ cpu->deschedule(tickCompare);
+ cpu->schedule(tickCompare, curTick + time * cpu->ticks(1));
}
panic("writing to TICK compare register %#X\n", val);
break;
@@ -95,13 +120,13 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
sTickCompare = new STickCompareEvent(this, tc);
setRegNoEffect(miscReg, val);
if ((stick_cmpr & ~mask(63)) && sTickCompare->scheduled())
- sTickCompare->deschedule();
+ cpu->deschedule(sTickCompare);
time = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) -
- tc->getCpuPtr()->instCount();
+ cpu->instCount();
if (!(stick_cmpr & ~mask(63)) && time > 0) {
if (sTickCompare->scheduled())
- sTickCompare->deschedule();
- sTickCompare->schedule(time * tc->getCpuPtr()->ticks(1) + curTick);
+ cpu->deschedule(sTickCompare);
+ cpu->schedule(sTickCompare, curTick + time * cpu->ticks(1));
}
DPRINTF(Timer, "writing to sTICK compare register value %#X\n", val);
break;
@@ -120,9 +145,9 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
case MISCREG_HINTP:
setRegNoEffect(miscReg, val);
if (hintp)
- tc->getCpuPtr()->post_interrupt(IT_HINTP,0);
+ cpu->postInterrupt(IT_HINTP, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_HINTP,0);
+ cpu->clearInterrupt(IT_HINTP, 0);
break;
case MISCREG_HTBA:
@@ -134,25 +159,25 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
case MISCREG_QUEUE_CPU_MONDO_TAIL:
setRegNoEffect(miscReg, val);
if (cpu_mondo_head != cpu_mondo_tail)
- tc->getCpuPtr()->post_interrupt(IT_CPU_MONDO,0);
+ cpu->postInterrupt(IT_CPU_MONDO, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_CPU_MONDO,0);
+ cpu->clearInterrupt(IT_CPU_MONDO, 0);
break;
case MISCREG_QUEUE_DEV_MONDO_HEAD:
case MISCREG_QUEUE_DEV_MONDO_TAIL:
setRegNoEffect(miscReg, val);
if (dev_mondo_head != dev_mondo_tail)
- tc->getCpuPtr()->post_interrupt(IT_DEV_MONDO,0);
+ cpu->postInterrupt(IT_DEV_MONDO, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_DEV_MONDO,0);
+ cpu->clearInterrupt(IT_DEV_MONDO, 0);
break;
case MISCREG_QUEUE_RES_ERROR_HEAD:
case MISCREG_QUEUE_RES_ERROR_TAIL:
setRegNoEffect(miscReg, val);
if (res_error_head != res_error_tail)
- tc->getCpuPtr()->post_interrupt(IT_RES_ERROR,0);
+ cpu->postInterrupt(IT_RES_ERROR, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_RES_ERROR,0);
+ cpu->clearInterrupt(IT_RES_ERROR, 0);
break;
case MISCREG_QUEUE_NRES_ERROR_HEAD:
case MISCREG_QUEUE_NRES_ERROR_TAIL:
@@ -165,13 +190,13 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
hSTickCompare = new HSTickCompareEvent(this, tc);
setRegNoEffect(miscReg, val);
if ((hstick_cmpr & ~mask(63)) && hSTickCompare->scheduled())
- hSTickCompare->deschedule();
+ cpu->deschedule(hSTickCompare);
time = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) -
- tc->getCpuPtr()->instCount();
+ cpu->instCount();
if (!(hstick_cmpr & ~mask(63)) && time > 0) {
if (hSTickCompare->scheduled())
- hSTickCompare->deschedule();
- hSTickCompare->schedule(curTick + time * tc->getCpuPtr()->ticks(1));
+ cpu->deschedule(hSTickCompare);
+ cpu->schedule(hSTickCompare, curTick + time * cpu->ticks(1));
}
DPRINTF(Timer, "writing to hsTICK compare register value %#X\n", val);
break;
@@ -181,9 +206,9 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
setRegNoEffect(miscReg, val | HPSTATE::id);
#if FULL_SYSTEM
if (hpstate & HPSTATE::tlz && tl == 0 && !(hpstate & HPSTATE::hpriv))
- tc->getCpuPtr()->post_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ cpu->postInterrupt(IT_TRAP_LEVEL_ZERO, 0);
else
- tc->getCpuPtr()->clear_interrupt(IT_TRAP_LEVEL_ZERO,0);
+ cpu->clearInterrupt(IT_TRAP_LEVEL_ZERO, 0);
#endif
break;
case MISCREG_HTSTATE:
@@ -200,11 +225,12 @@ MiscRegFile::setFSReg(int miscReg, const MiscReg &val, ThreadContext *tc)
tc->suspend();
if (tc->getKernelStats())
tc->getKernelStats()->quiesce();
- }
+ }
break;
default:
- panic("Invalid write to FS misc register %s\n", getMiscRegName(miscReg));
+ panic("Invalid write to FS misc register %s\n",
+ getMiscRegName(miscReg));
}
}
@@ -250,12 +276,13 @@ MiscRegFile::readFSReg(int miscReg, ThreadContext * tc)
sys = tc->getSystemPtr();
temp = readRegNoEffect(miscReg) & (STS::active | STS::speculative);
- // Check that the CPU array is fully populated (by calling getNumCPus())
- assert(sys->getNumCPUs() > tc->readCpuId());
+ // Check that the CPU array is fully populated
+ // (by calling getNumCPus())
+ assert(sys->numContexts() > tc->contextId());
- temp |= tc->readCpuId() << STS::shft_id;
+ temp |= tc->contextId() << STS::shft_id;
- for (x = tc->readCpuId() & ~3; x < sys->threadContexts.size(); x++) {
+ for (x = tc->contextId() & ~3; x < sys->threadContexts.size(); x++) {
switch (sys->threadContexts[x]->status()) {
case ThreadContext::Active:
temp |= STS::st_run << (STS::shft_fsm0 -
@@ -280,16 +307,6 @@ MiscRegFile::readFSReg(int miscReg, ThreadContext * tc)
panic("Invalid read to FS misc register\n");
}
}
-/*
- In Niagra STICK==TICK so this isn't needed
- case MISCREG_STICK:
- SparcSystem *sys;
- sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
- assert(sys != NULL);
- return curTick/Clock::Int::ns - sys->sysTick | (stick & ~(mask(63)));
-*/
-
-
void
MiscRegFile::processTickCompare(ThreadContext *tc)
@@ -300,12 +317,14 @@ MiscRegFile::processTickCompare(ThreadContext *tc)
void
MiscRegFile::processSTickCompare(ThreadContext *tc)
{
+ BaseCPU *cpu = tc->getCpuPtr();
+
// since our microcode instructions take two cycles we need to check if
// we're actually at the correct cycle or we need to wait a little while
// more
int ticks;
ticks = ((int64_t)(stick_cmpr & mask(63)) - (int64_t)stick) -
- tc->getCpuPtr()->instCount();
+ cpu->instCount();
assert(ticks >= 0 && "stick compare missed interrupt cycle");
if (ticks == 0 || tc->status() == ThreadContext::Suspended) {
@@ -315,12 +334,14 @@ MiscRegFile::processSTickCompare(ThreadContext *tc)
setReg(MISCREG_SOFTINT, softint | (ULL(1) << 16), tc);
}
} else
- sTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick);
+ cpu->schedule(sTickCompare, curTick + ticks * cpu->ticks(1));
}
void
MiscRegFile::processHSTickCompare(ThreadContext *tc)
{
+ BaseCPU *cpu = tc->getCpuPtr();
+
// since our microcode instructions take two cycles we need to check if
// we're actually at the correct cycle or we need to wait a little while
// more
@@ -330,7 +351,7 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc)
return;
ticks = ((int64_t)(hstick_cmpr & mask(63)) - (int64_t)stick) -
- tc->getCpuPtr()->instCount();
+ cpu->instCount();
assert(ticks >= 0 && "hstick compare missed interrupt cycle");
if (ticks == 0 || tc->status() == ThreadContext::Suspended) {
@@ -341,6 +362,6 @@ MiscRegFile::processHSTickCompare(ThreadContext *tc)
}
// Need to do something to cause interrupt to happen here !!! @todo
} else
- hSTickCompare->schedule(ticks * tc->getCpuPtr()->ticks(1) + curTick);
+ cpu->schedule(hSTickCompare, curTick + ticks * cpu->ticks(1));
}
diff --git a/src/arch/sparc/utility.cc b/src/arch/sparc/utility.cc
index 6d4358603..d4cc286e6 100644
--- a/src/arch/sparc/utility.cc
+++ b/src/arch/sparc/utility.cc
@@ -46,14 +46,14 @@ namespace SparcISA {
//first 6 arguments which the caller may use but doesn't have to.
uint64_t getArgument(ThreadContext *tc, int number, bool fp) {
#if FULL_SYSTEM
+ const int NumArgumentRegs = 6;
if (number < NumArgumentRegs) {
- return tc->readIntReg(ArgumentReg[number]);
+ return tc->readIntReg(8 + number);
} else {
Addr sp = tc->readIntReg(StackPointerReg);
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
uint64_t arg = vp->read<uint64_t>(sp + 92 +
(number-NumArgumentRegs) * sizeof(uint64_t));
- tc->delVirtPort(vp);
return arg;
}
#else
diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc
index 9a93950d2..f23fb8304 100644
--- a/src/arch/sparc/vtophys.cc
+++ b/src/arch/sparc/vtophys.cc
@@ -40,85 +40,93 @@
using namespace std;
-namespace SparcISA
+namespace SparcISA {
+
+Addr
+vtophys(Addr vaddr)
{
- Addr vtophys(Addr vaddr)
- {
- // In SPARC it's almost always impossible to turn a VA->PA w/o a context
- // The only times we can kinda do it are if we have a SegKPM mapping
- // and can find the real address in the tlb or we have a physical
- // adddress already (beacuse we are looking at the hypervisor)
- // Either case is rare, so we'll just panic.
-
- panic("vtophys() without context on SPARC largly worthless\n");
- M5_DUMMY_RETURN
- }
+ // In SPARC it's almost always impossible to turn a VA->PA w/o a
+ // context The only times we can kinda do it are if we have a
+ // SegKPM mapping and can find the real address in the tlb or we
+ // have a physical adddress already (beacuse we are looking at the
+ // hypervisor) Either case is rare, so we'll just panic.
+
+ panic("vtophys() without context on SPARC largly worthless\n");
+ M5_DUMMY_RETURN;
+}
+
+Addr
+vtophys(ThreadContext *tc, Addr addr)
+{
+ // Here we have many options and are really implementing something like
+ // a fill handler to find the address since there isn't a multilevel
+ // table for us to walk around.
+ //
+ // 1. We are currently hyperpriv, return the address unmodified
+ // 2. The mmu is off return(ra->pa)
+ // 3. We are currently priv, use ctx0* tsbs to find the page
+ // 4. We are not priv, use ctxN0* tsbs to find the page
+ // For all accesses we check the tlbs first since it's possible that
+ // long standing pages (e.g. locked kernel mappings) won't be in the tsb
+ uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
+
+ bool hpriv = bits(tlbdata,0,0);
+ //bool priv = bits(tlbdata,2,2);
+ bool addr_mask = bits(tlbdata,3,3);
+ bool data_real = !bits(tlbdata,5,5);
+ bool inst_real = !bits(tlbdata,4,4);
+ bool ctx_zero = bits(tlbdata,18,16) > 0;
+ int part_id = bits(tlbdata,15,8);
+ int pri_context = bits(tlbdata,47,32);
+ //int sec_context = bits(tlbdata,63,48);
- Addr vtophys(ThreadContext *tc, Addr addr)
- {
- // Here we have many options and are really implementing something like
- // a fill handler to find the address since there isn't a multilevel
- // table for us to walk around.
- //
- // 1. We are currently hyperpriv, return the address unmodified
- // 2. The mmu is off return(ra->pa)
- // 3. We are currently priv, use ctx0* tsbs to find the page
- // 4. We are not priv, use ctxN0* tsbs to find the page
- // For all accesses we check the tlbs first since it's possible that
- // long standing pages (e.g. locked kernel mappings) won't be in the tsb
- uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
-
- bool hpriv = bits(tlbdata,0,0);
- //bool priv = bits(tlbdata,2,2);
- bool addr_mask = bits(tlbdata,3,3);
- bool data_real = !bits(tlbdata,5,5);
- bool inst_real = !bits(tlbdata,4,4);
- bool ctx_zero = bits(tlbdata,18,16) > 0;
- int part_id = bits(tlbdata,15,8);
- int pri_context = bits(tlbdata,47,32);
- //int sec_context = bits(tlbdata,63,48);
-
- FunctionalPort *mem = tc->getPhysPort();
- ITB* itb = tc->getITBPtr();
- DTB* dtb = tc->getDTBPtr();
- TlbEntry* tbe;
- PageTableEntry pte;
- Addr tsbs[4];
- Addr va_tag;
- TteTag ttetag;
-
- if (hpriv)
- return addr;
-
- if (addr_mask)
- addr = addr & VAddrAMask;
-
- tbe = dtb->lookup(addr, part_id, data_real, ctx_zero ? 0 : pri_context , false);
- if (tbe) goto foundtbe;
-
- tbe = itb->lookup(addr, part_id, inst_real, ctx_zero ? 0 : pri_context, false);
- if (tbe) goto foundtbe;
-
- // We didn't find it in the tlbs, so lets look at the TSBs
- dtb->GetTsbPtr(tc, addr, ctx_zero ? 0 : pri_context, tsbs);
- va_tag = bits(addr, 63, 22);
- for (int x = 0; x < 4; x++) {
- ttetag = betoh(mem->read<uint64_t>(tsbs[x]));
- if (ttetag.valid() && ttetag.va() == va_tag) {
- pte.populate(betoh(mem->read<uint64_t>(tsbs[x]) + sizeof(uint64_t)),
- PageTableEntry::sun4v); // I think it's sun4v at least!
- DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TTE\n", addr,
- pte.paddrMask() | addr & pte.sizeMask());
- goto foundpte;
- }
+ FunctionalPort *mem = tc->getPhysPort();
+ ITB* itb = tc->getITBPtr();
+ DTB* dtb = tc->getDTBPtr();
+ TlbEntry* tbe;
+ PageTableEntry pte;
+ Addr tsbs[4];
+ Addr va_tag;
+ TteTag ttetag;
+
+ if (hpriv)
+ return addr;
+
+ if (addr_mask)
+ addr = addr & VAddrAMask;
+
+ tbe = dtb->lookup(addr, part_id, data_real, ctx_zero ? 0 : pri_context ,
+ false);
+ if (tbe)
+ goto foundtbe;
+
+ tbe = itb->lookup(addr, part_id, inst_real, ctx_zero ? 0 : pri_context,
+ false);
+ if (tbe)
+ goto foundtbe;
+
+ // We didn't find it in the tlbs, so lets look at the TSBs
+ dtb->GetTsbPtr(tc, addr, ctx_zero ? 0 : pri_context, tsbs);
+ va_tag = bits(addr, 63, 22);
+ for (int x = 0; x < 4; x++) {
+ ttetag = betoh(mem->read<uint64_t>(tsbs[x]));
+ if (ttetag.valid() && ttetag.va() == va_tag) {
+ uint64_t entry = mem->read<uint64_t>(tsbs[x]) + sizeof(uint64_t);
+ // I think it's sun4v at least!
+ pte.populate(betoh(entry), PageTableEntry::sun4v);
+ DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TTE\n",
+ addr, pte.translate(addr));
+ goto foundpte;
}
- panic("couldn't translate %#x\n", addr);
-
-foundtbe:
- pte = tbe->pte;
- DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TLB\n", addr,
- pte.paddrMask() | addr & pte.sizeMask());
-foundpte:
- return pte.paddrMask() | addr & pte.sizeMask();
}
+ panic("couldn't translate %#x\n", addr);
+
+ foundtbe:
+ pte = tbe->pte;
+ DPRINTF(VtoPhys, "Virtual(%#x)->Physical(%#x) found in TLB\n", addr,
+ pte.translate(addr));
+ foundpte:
+ return pte.translate(addr);
}
+
+} /* namespace SparcISA */
diff --git a/src/arch/x86/SConscript b/src/arch/x86/SConscript
index 674cd54c2..4c0460e28 100644
--- a/src/arch/x86/SConscript
+++ b/src/arch/x86/SConscript
@@ -86,6 +86,7 @@
Import('*')
if env['TARGET_ISA'] == 'x86':
+ Source('cpuid.cc')
Source('emulenv.cc')
Source('floatregfile.cc')
Source('faults.cc')
@@ -105,16 +106,22 @@ if env['TARGET_ISA'] == 'x86':
Source('utility.cc')
SimObject('X86TLB.py')
- TraceFlag('Predecoder')
- TraceFlag('X86')
+ TraceFlag('Predecoder', "Predecoder debug output")
+ TraceFlag('X86', "Generic X86 ISA debugging")
if env['FULL_SYSTEM']:
+ TraceFlag('LocalApic', "Local APIC debugging")
+ TraceFlag('PageTableWalker', \
+ "Page table walker state machine debugging")
+ TraceFlag('Faults', "Trace all faults/exceptions/traps")
+
+ SimObject('X86LocalApic.py')
SimObject('X86System.py')
# Full-system sources
+ Source('interrupts.cc')
Source('linux/system.cc')
Source('pagetable_walker.cc')
- Source('smbios.cc')
Source('system.cc')
Source('stacktrace.cc')
Source('vtophys.cc')
@@ -170,7 +177,6 @@ if env['TARGET_ISA'] == 'x86':
'general_purpose/load_segment_registers.py',
'general_purpose/logical.py',
'general_purpose/no_operation.py',
- 'general_purpose/processor_information.py',
'general_purpose/rotate_and_shift/__init__.py',
'general_purpose/rotate_and_shift/rotate.py',
'general_purpose/rotate_and_shift/shift.py',
@@ -182,7 +188,9 @@ if env['TARGET_ISA'] == 'x86':
'general_purpose/string/scan_string.py',
'general_purpose/string/store_string.py',
'general_purpose/system_calls.py',
+ 'romutil.py',
'system/__init__.py',
+ 'system/control_registers.py',
'system/halt.py',
'system/invlpg.py',
'system/undefined_operation.py',
diff --git a/src/arch/x86/SConsopts b/src/arch/x86/SConsopts
index d8b7cbed1..f8b700271 100644
--- a/src/arch/x86/SConsopts
+++ b/src/arch/x86/SConsopts
@@ -3,43 +3,16 @@
# Copyright (c) 2007 The Hewlett-Packard Development Company
# All rights reserved.
#
-# Redistribution and use of this software in source and binary forms,
-# with or without modification, are permitted provided that the
-# following conditions are met:
-#
-# The software must be used only for Non-Commercial Use which means any
-# use which is NOT directed to receiving any direct monetary
-# compensation for, or commercial advantage from such use. Illustrative
-# examples of non-commercial use are academic research, personal study,
-# teaching, education and corporate research & development.
-# Illustrative examples of commercial use are distributing products for
-# commercial advantage and providing services using the software for
-# commercial advantage.
-#
-# If you wish to use this software or functionality therein that may be
-# covered by patents for commercial use, please contact:
-# Director of Intellectual Property Licensing
-# Office of Strategy and Technology
-# Hewlett-Packard Company
-# 1501 Page Mill Road
-# Palo Alto, California 94304
-#
-# Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer. Redistributions
-# in binary form must reproduce the above copyright notice, this list of
-# conditions and the following disclaimer in the documentation and/or
-# other materials provided with the distribution. Neither the name of
-# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission. No right of
-# sublicense is granted herewith. Derivatives of the software and
-# output created using the software may be prepared, but only for
-# Non-Commercial Uses. Derivatives of the software may be shared with
-# others provided: (i) the others agree to abide by the list of
-# conditions herein which includes the Non-Commercial Use restrictions;
-# and (ii) such Derivatives of the software include the above copyright
-# notice to acknowledge the contribution from this software where
-# applicable, this list of conditions and the disclaimer below.
+# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
diff --git a/src/arch/x86/X86LocalApic.py b/src/arch/x86/X86LocalApic.py
new file mode 100644
index 000000000..483c65ef8
--- /dev/null
+++ b/src/arch/x86/X86LocalApic.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from Device import BasicPioDevice
+
+class X86LocalApic(BasicPioDevice):
+ type = 'X86LocalApic'
+ cxx_class = 'X86ISA::Interrupts'
+ pio_latency = Param.Latency('1ns', 'Programmed IO latency in simticks')
+ int_port = Port("Port for sending and receiving interrupt messages")
diff --git a/src/arch/x86/X86System.py b/src/arch/x86/X86System.py
index f73764540..527831205 100644
--- a/src/arch/x86/X86System.py
+++ b/src/arch/x86/X86System.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -54,10 +54,27 @@
# Authors: Gabe Black
from m5.params import *
+from E820 import X86E820Table, X86E820Entry
+from SMBios import X86SMBiosSMBiosTable
+from IntelMP import X86IntelMPFloatingPointer, X86IntelMPConfigTable
+from ACPI import X86ACPIRSDP
from System import System
class X86System(System):
type = 'X86System'
+ smbios_table = Param.X86SMBiosSMBiosTable(
+ X86SMBiosSMBiosTable(), 'table of smbios/dmi information')
+ intel_mp_pointer = Param.X86IntelMPFloatingPointer(
+ X86IntelMPFloatingPointer(),
+ 'intel mp spec floating pointer structure')
+ intel_mp_table = Param.X86IntelMPConfigTable(
+ X86IntelMPConfigTable(),
+ 'intel mp spec configuration table')
+ acpi_description_table_pointer = Param.X86ACPIRSDP(
+ X86ACPIRSDP(), 'ACPI root description pointer structure')
class LinuxX86System(X86System):
type = 'LinuxX86System'
+
+ e820_table = Param.X86E820Table(
+ X86E820Table(), 'E820 map of physical memory')
diff --git a/src/arch/x86/X86TLB.py b/src/arch/x86/X86TLB.py
index dc080f37e..d5ae95372 100644
--- a/src/arch/x86/X86TLB.py
+++ b/src/arch/x86/X86TLB.py
@@ -54,23 +54,20 @@
# Authors: Gabe Black
from MemObject import MemObject
-from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
from m5 import build_env
+from BaseTLB import BaseTLB
if build_env['FULL_SYSTEM']:
class X86PagetableWalker(MemObject):
type = 'X86PagetableWalker'
- cxx_namespace = 'X86ISA'
- cxx_class = 'Walker'
+ cxx_class = 'X86ISA::Walker'
port = Port("Port for the hardware table walker")
system = Param.System(Parent.any, "system object")
-class X86TLB(SimObject):
+class X86TLB(BaseTLB):
type = 'X86TLB'
- cxx_namespace = 'X86ISA'
- cxx_class = 'TLB'
abstract = True
size = Param.Int("TLB size")
if build_env['FULL_SYSTEM']:
@@ -79,14 +76,10 @@ class X86TLB(SimObject):
class X86DTB(X86TLB):
type = 'X86DTB'
- cxx_namespace = 'X86ISA'
- cxx_class = 'DTB'
-
+ cxx_class = 'X86ISA::DTB'
size = 64
class X86ITB(X86TLB):
type = 'X86ITB'
- cxx_namespace = 'X86ISA'
- cxx_class = 'ITB'
-
+ cxx_class = 'X86ISA::ITB'
size = 64
diff --git a/src/cpu/o3/sparc/thread_context.hh b/src/arch/x86/apicregs.hh
index 7497959e4..464c3af2d 100644
--- a/src/cpu/o3/sparc/thread_context.hh
+++ b/src/arch/x86/apicregs.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,51 +28,64 @@
* Authors: Gabe Black
*/
-#include "arch/sparc/types.hh"
-#include "cpu/o3/thread_context.hh"
+#ifndef __ARCH_X86_APICREGS_HH__
+#define __ARCH_X86_APICREGS_HH__
-template <class Impl>
-class SparcTC : public O3ThreadContext<Impl>
+namespace X86ISA
{
- public:
-#if FULL_SYSTEM
- /** Returns pointer to the quiesce event. */
- virtual EndQuiesceEvent *getQuiesceEvent()
+ enum ApicRegIndex
{
- return this->thread->quiesceEvent;
- }
-#endif
+ APIC_ID,
+ APIC_VERSION,
+ APIC_TASK_PRIORITY,
+ APIC_ARBITRATION_PRIORITY,
+ APIC_PROCESSOR_PRIORITY,
+ APIC_EOI,
+ APIC_LOGICAL_DESTINATION,
+ APIC_DESTINATION_FORMAT,
+ APIC_SPURIOUS_INTERRUPT_VECTOR,
- virtual uint64_t readNextNPC()
- {
- return this->cpu->readNextNPC(this->thread->readTid());
- }
+ APIC_IN_SERVICE_BASE,
+
+ APIC_TRIGGER_MODE_BASE = APIC_IN_SERVICE_BASE + 16,
+
+ APIC_INTERRUPT_REQUEST_BASE = APIC_TRIGGER_MODE_BASE + 16,
+
+ APIC_ERROR_STATUS = APIC_INTERRUPT_REQUEST_BASE + 16,
+ APIC_INTERRUPT_COMMAND_LOW,
+ APIC_INTERRUPT_COMMAND_HIGH,
+ APIC_LVT_TIMER,
+ APIC_LVT_THERMAL_SENSOR,
+ APIC_LVT_PERFORMANCE_MONITORING_COUNTERS,
+ APIC_LVT_LINT0,
+ APIC_LVT_LINT1,
+ APIC_LVT_ERROR,
+ APIC_INITIAL_COUNT,
+ APIC_CURRENT_COUNT,
+ APIC_DIVIDE_CONFIGURATION,
- virtual void setNextNPC(uint64_t val)
+ APIC_INTERNAL_STATE,
+
+ NUM_APIC_REGS
+ };
+
+ static inline ApicRegIndex
+ APIC_IN_SERVICE(int index)
{
- this->cpu->setNextNPC(val, this->thread->readTid());
+ return (ApicRegIndex)(APIC_IN_SERVICE_BASE + index);
}
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
+ static inline ApicRegIndex
+ APIC_TRIGGER_MODE(int index)
{
- //XXX Ignore this for now. This -really- needs to get fixed.
+ return (ApicRegIndex)(APIC_TRIGGER_MODE_BASE + index);
}
-
- /** This function exits the thread context in the CPU and returns
- * 1 if the CPU has no more active threads (meaning it's OK to exit);
- * Used in syscall-emulation mode when a thread executes the 'exit'
- * syscall.
- */
- virtual int exit()
+ static inline ApicRegIndex
+ APIC_INTERRUPT_REQUEST(int index)
{
- this->deallocate();
-
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
+ return (ApicRegIndex)(APIC_INTERRUPT_REQUEST_BASE + index);
}
-};
+}
+
+#endif
diff --git a/src/arch/x86/bios/ACPI.py b/src/arch/x86/bios/ACPI.py
new file mode 100644
index 000000000..6f7cae946
--- /dev/null
+++ b/src/arch/x86/bios/ACPI.py
@@ -0,0 +1,99 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the
+# following conditions are met:
+#
+# The software must be used only for Non-Commercial Use which means any
+# use which is NOT directed to receiving any direct monetary
+# compensation for, or commercial advantage from such use. Illustrative
+# examples of non-commercial use are academic research, personal study,
+# teaching, education and corporate research & development.
+# Illustrative examples of commercial use are distributing products for
+# commercial advantage and providing services using the software for
+# commercial advantage.
+#
+# If you wish to use this software or functionality therein that may be
+# covered by patents for commercial use, please contact:
+# Director of Intellectual Property Licensing
+# Office of Strategy and Technology
+# Hewlett-Packard Company
+# 1501 Page Mill Road
+# Palo Alto, California 94304
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer. Redistributions
+# in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution. Neither the name of
+# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission. No right of
+# sublicense is granted herewith. Derivatives of the software and
+# output created using the software may be prepared, but only for
+# Non-Commercial Uses. Derivatives of the software may be shared with
+# others provided: (i) the others agree to abide by the list of
+# conditions herein which includes the Non-Commercial Use restrictions;
+# and (ii) such Derivatives of the software include the above copyright
+# notice to acknowledge the contribution from this software where
+# applicable, this list of conditions and the disclaimer below.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+# ACPI description table header. Subclasses contain and handle the actual
+# contents as appropriate for that type of table.
+class X86ACPISysDescTable(SimObject):
+ type = 'X86ACPISysDescTable'
+ cxx_class = 'X86ISA::ACPI::SysDescTable'
+ abstract = True
+
+ oem_id = Param.String('', 'string identifying the oem')
+ oem_table_id = Param.String('', 'oem table ID')
+ oem_revision = Param.UInt32(0, 'oem revision number for the table')
+
+ creator_id = Param.String('',
+ 'string identifying the generator of the table')
+ creator_revision = Param.UInt32(0,
+ 'revision number for the creator of the table')
+
+class X86ACPIRSDT(X86ACPISysDescTable):
+ type = 'X86ACPIRSDT'
+ cxx_class = 'X86ISA::ACPI::RSDT'
+
+ entries = VectorParam.X86ACPISysDescTable([], 'system description tables')
+
+class X86ACPIXSDT(X86ACPISysDescTable):
+ type = 'X86ACPIXSDT'
+ cxx_class = 'X86ISA::ACPI::XSDT'
+
+ entries = VectorParam.X86ACPISysDescTable([], 'system description tables')
+
+# Root System Description Pointer Structure
+class X86ACPIRSDP(SimObject):
+ type = 'X86ACPIRSDP'
+ cxx_class = 'X86ISA::ACPI::RSDP'
+
+ oem_id = Param.String('', 'string identifying the oem')
+ # Because 0 encodes ACPI 1.0, 2 encodes ACPI 3.0, the version implemented
+ # here.
+ revision = Param.UInt8(2, 'revision of ACPI being used, zero indexed')
+
+ rsdt = Param.X86ACPIRSDT(NULL, 'root system description table')
+ xsdt = Param.X86ACPIXSDT(X86ACPIXSDT(),
+ 'extended system description table')
diff --git a/src/arch/x86/bios/E820.py b/src/arch/x86/bios/E820.py
new file mode 100644
index 000000000..288c253fb
--- /dev/null
+++ b/src/arch/x86/bios/E820.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the
+# following conditions are met:
+#
+# The software must be used only for Non-Commercial Use which means any
+# use which is NOT directed to receiving any direct monetary
+# compensation for, or commercial advantage from such use. Illustrative
+# examples of non-commercial use are academic research, personal study,
+# teaching, education and corporate research & development.
+# Illustrative examples of commercial use are distributing products for
+# commercial advantage and providing services using the software for
+# commercial advantage.
+#
+# If you wish to use this software or functionality therein that may be
+# covered by patents for commercial use, please contact:
+# Director of Intellectual Property Licensing
+# Office of Strategy and Technology
+# Hewlett-Packard Company
+# 1501 Page Mill Road
+# Palo Alto, California 94304
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer. Redistributions
+# in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution. Neither the name of
+# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission. No right of
+# sublicense is granted herewith. Derivatives of the software and
+# output created using the software may be prepared, but only for
+# Non-Commercial Uses. Derivatives of the software may be shared with
+# others provided: (i) the others agree to abide by the list of
+# conditions herein which includes the Non-Commercial Use restrictions;
+# and (ii) such Derivatives of the software include the above copyright
+# notice to acknowledge the contribution from this software where
+# applicable, this list of conditions and the disclaimer below.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+class X86E820Entry(SimObject):
+ type = 'X86E820Entry'
+ cxx_class = 'X86ISA::E820Entry'
+
+ addr = Param.Addr(0, 'address of the beginning of the region')
+ size = Param.MemorySize('0B', 'size of the region')
+ range_type = Param.UInt64('type of the region')
+
+class X86E820Table(SimObject):
+ type = 'X86E820Table'
+ cxx_class = 'X86ISA::E820Table'
+
+ entries = VectorParam.X86E820Entry([], 'entries for the e820 table')
diff --git a/src/arch/x86/bios/IntelMP.py b/src/arch/x86/bios/IntelMP.py
new file mode 100644
index 000000000..04e79b6ac
--- /dev/null
+++ b/src/arch/x86/bios/IntelMP.py
@@ -0,0 +1,242 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the
+# following conditions are met:
+#
+# The software must be used only for Non-Commercial Use which means any
+# use which is NOT directed to receiving any direct monetary
+# compensation for, or commercial advantage from such use. Illustrative
+# examples of non-commercial use are academic research, personal study,
+# teaching, education and corporate research & development.
+# Illustrative examples of commercial use are distributing products for
+# commercial advantage and providing services using the software for
+# commercial advantage.
+#
+# If you wish to use this software or functionality therein that may be
+# covered by patents for commercial use, please contact:
+# Director of Intellectual Property Licensing
+# Office of Strategy and Technology
+# Hewlett-Packard Company
+# 1501 Page Mill Road
+# Palo Alto, California 94304
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer. Redistributions
+# in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution. Neither the name of
+# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission. No right of
+# sublicense is granted herewith. Derivatives of the software and
+# output created using the software may be prepared, but only for
+# Non-Commercial Uses. Derivatives of the software may be shared with
+# others provided: (i) the others agree to abide by the list of
+# conditions herein which includes the Non-Commercial Use restrictions;
+# and (ii) such Derivatives of the software include the above copyright
+# notice to acknowledge the contribution from this software where
+# applicable, this list of conditions and the disclaimer below.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+class X86IntelMPFloatingPointer(SimObject):
+ type = 'X86IntelMPFloatingPointer'
+ cxx_class = 'X86ISA::IntelMP::FloatingPointer'
+
+ # The minor revision of the spec to support. The major version is assumed
+ # to be 1 in accordance with the spec.
+ spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported')
+ # If no default configuration is used, set this to 0.
+ default_config = Param.UInt8(0, 'which default configuration to use')
+ imcr_present = Param.Bool(True,
+ 'whether the IMCR register is present in the APIC')
+
+class X86IntelMPConfigTable(SimObject):
+ type = 'X86IntelMPConfigTable'
+ cxx_class = 'X86ISA::IntelMP::ConfigTable'
+
+ spec_rev = Param.UInt8(4, 'minor revision of the MP spec supported')
+ oem_id = Param.String("", 'system manufacturer')
+ product_id = Param.String("", 'product family')
+ oem_table_addr = Param.UInt32(0,
+ 'pointer to the optional oem configuration table')
+ oem_table_size = Param.UInt16(0, 'size of the oem configuration table')
+ local_apic = Param.UInt32(0xFEE00000, 'address of the local APIC')
+
+ base_entries = VectorParam.X86IntelMPBaseConfigEntry([],
+ 'base configuration table entries')
+
+ ext_entries = VectorParam.X86IntelMPExtConfigEntry([],
+ 'extended configuration table entries')
+
+ def add_entry(self, entry):
+ if isinstance(entry, X86IntelMPBaseConfigEntry):
+ self.base_entries.append(entry)
+ elif isinstance(entry, X86IntelMPExtConfigEntry):
+ self.ext_entries.append(entry)
+ else:
+ panic("Don't know what type of Intel MP entry %s is." \
+ % entry.__class__.__name__)
+
+class X86IntelMPBaseConfigEntry(SimObject):
+ type = 'X86IntelMPBaseConfigEntry'
+ cxx_class = 'X86ISA::IntelMP::BaseConfigEntry'
+ abstract = True
+
+class X86IntelMPExtConfigEntry(SimObject):
+ type = 'X86IntelMPExtConfigEntry'
+ cxx_class = 'X86ISA::IntelMP::ExtConfigEntry'
+ abstract = True
+
+class X86IntelMPProcessor(X86IntelMPBaseConfigEntry):
+ type = 'X86IntelMPProcessor'
+ cxx_class = 'X86ISA::IntelMP::Processor'
+
+ local_apic_id = Param.UInt8(0, 'local APIC id')
+ local_apic_version = Param.UInt8(0,
+ 'bits 0-7 of the local APIC version register')
+ enable = Param.Bool(True, 'if this processor is usable')
+ bootstrap = Param.Bool(False, 'if this is the bootstrap processor')
+
+ stepping = Param.UInt8(0, 'Processor stepping')
+ model = Param.UInt8(0, 'Processor model')
+ family = Param.UInt8(0, 'Processor family')
+
+ feature_flags = Param.UInt32(0, 'flags returned by the CPUID instruction')
+
+class X86IntelMPBus(X86IntelMPBaseConfigEntry):
+ type = 'X86IntelMPBus'
+ cxx_class = 'X86ISA::IntelMP::Bus'
+
+ bus_id = Param.UInt8(0, 'bus id assigned by the bios')
+ bus_type = Param.String("", 'string that identify the bus type')
+ # Legal values for bus_type are:
+ #
+ # "CBUS", "CBUSII", "EISA", "FUTURE", "INTERN", "ISA", "MBI", "MBII",
+ # "MCA", "MPI", "MPSA", "NUBUS", "PCI", "PCMCIA", "TC", "VL", "VME",
+ # "XPRESS"
+
+class X86IntelMPIOAPIC(X86IntelMPBaseConfigEntry):
+ type = 'X86IntelMPIOAPIC'
+ cxx_class = 'X86ISA::IntelMP::IOAPIC'
+
+ id = Param.UInt8(0, 'id of this APIC')
+ version = Param.UInt8(0, 'bits 0-7 of the version register')
+
+ enable = Param.Bool(True, 'if this APIC is usable')
+
+ address = Param.UInt32(0xfec00000, 'address of this APIC')
+
+class X86IntelMPInterruptType(Enum):
+ map = {'INT' : 0,
+ 'NMI' : 1,
+ 'SMI' : 2,
+ 'ExtInt' : 3
+ }
+
+class X86IntelMPPolarity(Enum):
+ map = {'ConformPolarity' : 0,
+ 'ActiveHigh' : 1,
+ 'ActiveLow' : 3
+ }
+
+class X86IntelMPTriggerMode(Enum):
+ map = {'ConformTrigger' : 0,
+ 'EdgeTrigger' : 1,
+ 'LevelTrigger' : 3
+ }
+
+class X86IntelMPIOIntAssignment(X86IntelMPBaseConfigEntry):
+ type = 'X86IntelMPIOIntAssignment'
+ cxx_class = 'X86ISA::IntelMP::IOIntAssignment'
+
+ interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt')
+
+ polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity')
+ trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode')
+
+ source_bus_id = Param.UInt8(0,
+ 'id of the bus from which the interrupt signal comes')
+ source_bus_irq = Param.UInt8(0,
+ 'which interrupt signal from the source bus')
+
+ dest_io_apic_id = Param.UInt8(0,
+ 'id of the IO APIC the interrupt is going to')
+ dest_io_apic_intin = Param.UInt8(0,
+ 'the INTIN pin on the IO APIC the interrupt is connected to')
+
+class X86IntelMPLocalIntAssignment(X86IntelMPBaseConfigEntry):
+ type = 'X86IntelMPLocalIntAssignment'
+ cxx_class = 'X86ISA::IntelMP::LocalIntAssignment'
+
+ interrupt_type = Param.X86IntelMPInterruptType('INT', 'type of interrupt')
+
+ polarity = Param.X86IntelMPPolarity('ConformPolarity', 'polarity')
+ trigger = Param.X86IntelMPTriggerMode('ConformTrigger', 'trigger mode')
+
+ source_bus_id = Param.UInt8(0,
+ 'id of the bus from which the interrupt signal comes')
+ source_bus_irq = Param.UInt8(0,
+ 'which interrupt signal from the source bus')
+
+ dest_local_apic_id = Param.UInt8(0,
+ 'id of the local APIC the interrupt is going to')
+ dest_local_apic_intin = Param.UInt8(0,
+ 'the INTIN pin on the local APIC the interrupt is connected to')
+
+class X86IntelMPAddressType(Enum):
+ map = {"IOAddress" : 0,
+ "MemoryAddress" : 1,
+ "PrefetchAddress" : 2
+ }
+
+class X86IntelMPAddrSpaceMapping(X86IntelMPExtConfigEntry):
+ type = 'X86IntelMPAddrSpaceMapping'
+ cxx_class = 'X86ISA::IntelMP::AddrSpaceMapping'
+
+ bus_id = Param.UInt8(0, 'id of the bus the address space is mapped to')
+ address_type = Param.X86IntelMPAddressType('IOAddress',
+ 'address type used to access bus')
+ address = Param.Addr(0, 'starting address of the mapping')
+ length = Param.UInt64(0, 'length of mapping in bytes')
+
+class X86IntelMPBusHierarchy(X86IntelMPExtConfigEntry):
+ type = 'X86IntelMPBusHierarchy'
+ cxx_class = 'X86ISA::IntelMP::BusHierarchy'
+
+ bus_id = Param.UInt8(0, 'id of the bus being described')
+ subtractive_decode = Param.Bool(False,
+ 'whether this bus contains all addresses not used by its children')
+ parent_bus = Param.UInt8(0, 'bus id of this busses parent')
+
+class X86IntelMPRangeList(Enum):
+ map = {"ISACompatible" : 0,
+ "VGACompatible" : 1
+ }
+
+class X86IntelMPCompatAddrSpaceMod(X86IntelMPExtConfigEntry):
+ type = 'X86IntelMPCompatAddrSpaceMod'
+ cxx_class = 'X86ISA::IntelMP::CompatAddrSpaceMod'
+
+ bus_id = Param.UInt8(0, 'id of the bus being described')
+ add = Param.Bool(False,
+ 'if the range should be added to the original mapping')
+ range_list = Param.X86IntelMPRangeList('ISACompatible',
+ 'which predefined range of addresses to use')
diff --git a/src/arch/x86/bios/SConscript b/src/arch/x86/bios/SConscript
new file mode 100644
index 000000000..912d6599c
--- /dev/null
+++ b/src/arch/x86/bios/SConscript
@@ -0,0 +1,77 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the
+# following conditions are met:
+#
+# The software must be used only for Non-Commercial Use which means any
+# use which is NOT directed to receiving any direct monetary
+# compensation for, or commercial advantage from such use. Illustrative
+# examples of non-commercial use are academic research, personal study,
+# teaching, education and corporate research & development.
+# Illustrative examples of commercial use are distributing products for
+# commercial advantage and providing services using the software for
+# commercial advantage.
+#
+# If you wish to use this software or functionality therein that may be
+# covered by patents for commercial use, please contact:
+# Director of Intellectual Property Licensing
+# Office of Strategy and Technology
+# Hewlett-Packard Company
+# 1501 Page Mill Road
+# Palo Alto, California 94304
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer. Redistributions
+# in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution. Neither the name of
+# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission. No right of
+# sublicense is granted herewith. Derivatives of the software and
+# output created using the software may be prepared, but only for
+# Non-Commercial Uses. Derivatives of the software may be shared with
+# others provided: (i) the others agree to abide by the list of
+# conditions herein which includes the Non-Commercial Use restrictions;
+# and (ii) such Derivatives of the software include the above copyright
+# notice to acknowledge the contribution from this software where
+# applicable, this list of conditions and the disclaimer below.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+Import('*')
+
+if env['TARGET_ISA'] == 'x86':
+ if env['FULL_SYSTEM']:
+ # The table generated by the bootloader using the BIOS and passed to
+ # the operating system which maps out physical memory.
+ SimObject('E820.py')
+ Source('e820.cc')
+
+ # The DMI tables.
+ SimObject('SMBios.py')
+ Source('smbios.cc')
+
+ # Intel Multiprocessor Specification Configuration Table
+ SimObject('IntelMP.py')
+ Source('intelmp.cc')
+
+ # ACPI system description tables
+ SimObject('ACPI.py')
+ Source('acpi.cc')
diff --git a/src/arch/x86/bios/SMBios.py b/src/arch/x86/bios/SMBios.py
new file mode 100644
index 000000000..4947b2854
--- /dev/null
+++ b/src/arch/x86/bios/SMBios.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use of this software in source and binary forms,
+# with or without modification, are permitted provided that the
+# following conditions are met:
+#
+# The software must be used only for Non-Commercial Use which means any
+# use which is NOT directed to receiving any direct monetary
+# compensation for, or commercial advantage from such use. Illustrative
+# examples of non-commercial use are academic research, personal study,
+# teaching, education and corporate research & development.
+# Illustrative examples of commercial use are distributing products for
+# commercial advantage and providing services using the software for
+# commercial advantage.
+#
+# If you wish to use this software or functionality therein that may be
+# covered by patents for commercial use, please contact:
+# Director of Intellectual Property Licensing
+# Office of Strategy and Technology
+# Hewlett-Packard Company
+# 1501 Page Mill Road
+# Palo Alto, California 94304
+#
+# Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer. Redistributions
+# in binary form must reproduce the above copyright notice, this list of
+# conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution. Neither the name of
+# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission. No right of
+# sublicense is granted herewith. Derivatives of the software and
+# output created using the software may be prepared, but only for
+# Non-Commercial Uses. Derivatives of the software may be shared with
+# others provided: (i) the others agree to abide by the list of
+# conditions herein which includes the Non-Commercial Use restrictions;
+# and (ii) such Derivatives of the software include the above copyright
+# notice to acknowledge the contribution from this software where
+# applicable, this list of conditions and the disclaimer below.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+class X86SMBiosSMBiosStructure(SimObject):
+ type = 'X86SMBiosSMBiosStructure'
+ cxx_class = 'X86ISA::SMBios::SMBiosStructure'
+ abstract = True
+
+class Characteristic(Enum):
+ map = {'Unknown' : 2,
+ 'Unsupported' : 3,
+ 'ISA' : 4,
+ 'MCA' : 5,
+ 'EISA' : 6,
+ 'PCI' : 7,
+ 'PCMCIA' : 8,
+ 'PnP' : 9,
+ 'APM' : 10,
+ 'Flash' : 11,
+ 'Shadow' : 12,
+ 'VL_Vesa' : 13,
+ 'ESCD' : 14,
+ 'CDBoot' : 15,
+ 'SelectBoot' : 16,
+ 'Socketed' : 17,
+ 'PCMCIABoot' : 18,
+ 'EDD' : 19,
+ 'NEC9800' : 20,
+ 'Toshiba' : 21,
+ 'Floppy_5_25_360KB' : 22,
+ 'Floppy_5_25_1_2MB' : 23,
+ 'Floppy_3_5_720KB' : 24,
+ 'Floppy_3_5_2_88MB' : 25,
+ 'PrintScreen' : 26,
+ 'Keyboard8024' : 27,
+ 'Serial' : 28,
+ 'Printer' : 29,
+ 'CGA_Mono' : 30,
+ 'NEC_PC_98' : 31
+ }
+
+class ExtCharacteristic(Enum):
+ map = {'ACPI' : 0,
+ 'USBLegacy' : 1,
+ 'AGP' : 2,
+ 'I20Boot' : 3,
+ 'LS_120Boot' : 4,
+ 'ZIPBoot' : 5,
+ 'FirewireBoot' : 6,
+ 'SmartBattery' : 7,
+ 'BootSpec' : 8,
+ 'NetServiceBoot' : 9,
+ 'TargetContent' : 10
+ }
+
+class X86SMBiosBiosInformation(X86SMBiosSMBiosStructure):
+ type = 'X86SMBiosBiosInformation'
+ cxx_class = 'X86ISA::SMBios::BiosInformation'
+
+ vendor = Param.String("", "vendor name string")
+ version = Param.String("", "version string")
+ starting_addr_segment = \
+ Param.UInt16(0, "segment location of bios starting address")
+ release_date = Param.String("06/08/2008", "release date")
+ rom_size = Param.UInt8(0, "rom size")
+ characteristics = VectorParam.Characteristic([],
+ "bios characteristic bit vector")
+ characteristic_ext_bytes = VectorParam.ExtCharacteristic([],
+ "extended bios characteristic bit vector")
+ major = Param.UInt8(0, "major version number")
+ minor = Param.UInt8(0, "minor version number")
+ emb_cont_firmware_major = Param.UInt8(0,
+ "embedded controller firmware major version number")
+
+ emb_cont_firmware_minor = Param.UInt8(0,
+ "embedded controller firmware minor version number")
+
+class X86SMBiosSMBiosTable(SimObject):
+ type = 'X86SMBiosSMBiosTable'
+ cxx_class = 'X86ISA::SMBios::SMBiosTable'
+
+ major_version = Param.UInt8(2, "major version number")
+ minor_version = Param.UInt8(5, "minor version number")
+
+ structures = VectorParam.X86SMBiosSMBiosStructure([], "smbios structures")
diff --git a/src/arch/x86/bios/acpi.cc b/src/arch/x86/bios/acpi.cc
new file mode 100644
index 000000000..15b3901eb
--- /dev/null
+++ b/src/arch/x86/bios/acpi.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/bios/acpi.hh"
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+#include "sim/sim_object.hh"
+
+#include "params/X86ACPIRSDP.hh"
+
+#include "params/X86ACPISysDescTable.hh"
+#include "params/X86ACPIRSDT.hh"
+#include "params/X86ACPIXSDT.hh"
+
+using namespace std;
+
+const char X86ISA::ACPI::RSDP::signature[] = "RSD PTR ";
+
+X86ISA::ACPI::RSDP::RSDP(Params *p) : SimObject(p), oemID(p->oem_id),
+ revision(p->revision), rsdt(p->rsdt), xsdt(p->xsdt)
+{}
+
+X86ISA::ACPI::SysDescTable::SysDescTable(Params *p,
+ const char * _signature, uint8_t _revision) : SimObject(p),
+ signature(_signature), revision(_revision),
+ oemID(p->oem_id), oemTableID(p->oem_table_id),
+ oemRevision(p->oem_revision),
+ creatorID(p->creator_id), creatorRevision(p->creator_revision)
+{}
+
+X86ISA::ACPI::RSDT::RSDT(Params *p) :
+ SysDescTable(p, "RSDT", 1), entries(p->entries)
+{}
+
+X86ISA::ACPI::XSDT::XSDT(Params *p) :
+ SysDescTable(p, "XSDT", 1), entries(p->entries)
+{}
+
+X86ISA::ACPI::RSDP *
+X86ACPIRSDPParams::create()
+{
+ return new X86ISA::ACPI::RSDP(this);
+}
+
+X86ISA::ACPI::RSDT *
+X86ACPIRSDTParams::create()
+{
+ return new X86ISA::ACPI::RSDT(this);
+}
+
+X86ISA::ACPI::XSDT *
+X86ACPIXSDTParams::create()
+{
+ return new X86ISA::ACPI::XSDT(this);
+}
diff --git a/src/arch/x86/bios/acpi.hh b/src/arch/x86/bios/acpi.hh
new file mode 100644
index 000000000..7bca17790
--- /dev/null
+++ b/src/arch/x86/bios/acpi.hh
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_BIOS_ACPI_HH__
+#define __ARCH_X86_BIOS_ACPI_HH__
+
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+#include <vector>
+#include <string>
+
+class Port;
+
+class X86ACPIRSDPParams;
+
+class X86ACPISysDescTableParams;
+class X86ACPIRSDTParams;
+class X86ACPIXSDTParams;
+
+namespace X86ISA
+{
+
+namespace ACPI
+{
+
+class RSDT;
+class XSDT;
+class SysDescTable;
+
+class RSDP : public SimObject
+{
+ protected:
+ typedef X86ACPIRSDPParams Params;
+
+ static const char signature[];
+
+ std::string oemID;
+ uint8_t revision;
+
+ RSDT * rsdt;
+ XSDT * xsdt;
+
+ public:
+ RSDP(Params *p);
+};
+
+class SysDescTable : public SimObject
+{
+ protected:
+ typedef X86ACPISysDescTableParams Params;
+
+ const char * signature;
+ uint8_t revision;
+
+ std::string oemID;
+ std::string oemTableID;
+ uint32_t oemRevision;
+
+ std::string creatorID;
+ uint32_t creatorRevision;
+
+ public:
+ SysDescTable(Params *p, const char * _signature, uint8_t _revision);
+};
+
+class RSDT : public SysDescTable
+{
+ protected:
+ typedef X86ACPIRSDTParams Params;
+
+ std::vector<SysDescTable *> entries;
+
+ public:
+ RSDT(Params *p);
+};
+
+class XSDT : public SysDescTable
+{
+ protected:
+ typedef X86ACPIXSDTParams Params;
+
+ std::vector<SysDescTable *> entries;
+
+ public:
+ XSDT(Params *p);
+};
+
+} // namespace ACPI
+
+} // namespace X86ISA
+
+#endif // __ARCH_X86_BIOS_E820_HH__
diff --git a/src/arch/x86/bios/e820.cc b/src/arch/x86/bios/e820.cc
new file mode 100644
index 000000000..47adb703a
--- /dev/null
+++ b/src/arch/x86/bios/e820.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/bios/e820.hh"
+#include "arch/x86/isa_traits.hh"
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+
+using namespace std;
+using namespace X86ISA;
+
+template<class T>
+void writeVal(T val, Port * port, Addr &addr)
+{
+ T guestVal = htog(val);
+ port->writeBlob(addr, (uint8_t *)&guestVal, sizeof(T));
+ addr += sizeof(T);
+}
+
+void X86ISA::E820Table::writeTo(Port * port, Addr countAddr, Addr addr)
+{
+ uint8_t e820Nr = entries.size();
+
+ // Make sure the number of entries isn't bigger than what the kernel
+ // would be capable of handling.
+ assert(e820Nr <= 128);
+
+ uint8_t guestE820Nr = htog(e820Nr);
+
+ port->writeBlob(countAddr, (uint8_t *)&guestE820Nr, sizeof(guestE820Nr));
+
+ for (int i = 0; i < e820Nr; i++) {
+ writeVal(entries[i]->addr, port, addr);
+ writeVal(entries[i]->size, port, addr);
+ writeVal(entries[i]->type, port, addr);
+ }
+}
+
+E820Table *
+X86E820TableParams::create()
+{
+ return new E820Table(this);
+}
+
+E820Entry *
+X86E820EntryParams::create()
+{
+ return new E820Entry(this);
+}
diff --git a/src/arch/x86/syscallreturn.hh b/src/arch/x86/bios/e820.hh
index 6a7fdba58..da738343b 100644
--- a/src/arch/x86/syscallreturn.hh
+++ b/src/arch/x86/bios/e820.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -55,20 +55,46 @@
* Authors: Gabe Black
*/
-#ifndef __ARCH_X86_SYSCALLRETURN_HH__
-#define __ARCH_X86_SYSCALLRETURN_HH__
+#ifndef __ARCH_X86_BIOS_E820_HH__
+#define __ARCH_X86_BIOS_E820_HH__
-#include "base/misc.hh"
-#include "cpu/thread_context.hh"
-#include "sim/syscallreturn.hh"
+#include "params/X86E820Entry.hh"
+#include "params/X86E820Table.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+#include <vector>
+
+class Port;
namespace X86ISA
{
- static inline void setSyscallReturn(SyscallReturn return_value,
- ThreadContext * tc)
+ class E820Entry : public SimObject
{
- tc->setIntReg(INTREG_RAX, return_value.value());
- }
+ public:
+ Addr addr;
+ Addr size;
+ uint32_t type;
+
+ public:
+ typedef X86E820EntryParams Params;
+ E820Entry(Params *p) :
+ SimObject(p), addr(p->addr), size(p->size), type(p->range_type)
+ {}
+ };
+
+ class E820Table : public SimObject
+ {
+ public:
+ std::vector<E820Entry *> entries;
+
+ public:
+ typedef X86E820TableParams Params;
+ E820Table(Params *p) : SimObject(p), entries(p->entries)
+ {}
+
+ void writeTo(Port * port, Addr countAddr, Addr addr);
+ };
};
-#endif // __ARCH_X86_SYSCALLRETURN_HH__
+#endif // __ARCH_X86_BIOS_E820_HH__
diff --git a/src/arch/x86/bios/intelmp.cc b/src/arch/x86/bios/intelmp.cc
new file mode 100644
index 000000000..2332e7a5c
--- /dev/null
+++ b/src/arch/x86/bios/intelmp.cc
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/bios/intelmp.hh"
+#include "arch/x86/isa_traits.hh"
+#include "base/misc.hh"
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+#include "sim/host.hh"
+
+// Config entry types
+#include "params/X86IntelMPBaseConfigEntry.hh"
+#include "params/X86IntelMPExtConfigEntry.hh"
+
+// General table structures
+#include "params/X86IntelMPConfigTable.hh"
+#include "params/X86IntelMPFloatingPointer.hh"
+
+// Base entry types
+#include "params/X86IntelMPBus.hh"
+#include "params/X86IntelMPIOAPIC.hh"
+#include "params/X86IntelMPIOIntAssignment.hh"
+#include "params/X86IntelMPLocalIntAssignment.hh"
+#include "params/X86IntelMPProcessor.hh"
+
+// Extended entry types
+#include "params/X86IntelMPAddrSpaceMapping.hh"
+#include "params/X86IntelMPBusHierarchy.hh"
+#include "params/X86IntelMPCompatAddrSpaceMod.hh"
+
+using namespace std;
+
+const char X86ISA::IntelMP::FloatingPointer::signature[] = "_MP_";
+
+template<class T>
+uint8_t
+writeOutField(FunctionalPort * port, Addr addr, T val)
+{
+ T guestVal = X86ISA::htog(val);
+ port->writeBlob(addr, (uint8_t *)(&guestVal), sizeof(T));
+
+ uint8_t checkSum = 0;
+ while(guestVal) {
+ checkSum += guestVal;
+ guestVal >>= 8;
+ }
+ return checkSum;
+}
+
+uint8_t
+writeOutString(FunctionalPort * port, Addr addr, string str, int length)
+{
+ char cleanedString[length + 1];
+ cleanedString[length] = 0;
+
+ if (str.length() > length) {
+ memcpy(cleanedString, str.c_str(), length);
+ warn("Intel MP configuration table string \"%s\" "
+ "will be truncated to \"%s\".\n", str, cleanedString);
+ } else {
+ memcpy(cleanedString, str.c_str(), str.length());
+ memset(cleanedString + str.length(), 0, length - str.length());
+ }
+ port->writeBlob(addr, (uint8_t *)(&cleanedString), length);
+
+ uint8_t checkSum = 0;
+ for (int i = 0; i < length; i++)
+ checkSum += cleanedString[i];
+
+ return checkSum;
+}
+
+Addr
+X86ISA::IntelMP::FloatingPointer::writeOut(FunctionalPort * port, Addr addr)
+{
+ // Make sure that either a config table is present or a default
+ // configuration was found but not both.
+ if (!tableAddr && !defaultConfig)
+ fatal("Either an MP configuration table or a default configuration "
+ "must be used.");
+ if (tableAddr && defaultConfig)
+ fatal("Both an MP configuration table and a default configuration "
+ "were set.");
+
+ uint8_t checkSum = 0;
+
+ port->writeBlob(addr, (uint8_t *)signature, 4);
+ for (int i = 0; i < 4; i++)
+ checkSum += signature[i];
+
+ checkSum += writeOutField(port, addr + 4, tableAddr);
+
+ // The length of the structure in paragraphs, aka 16 byte chunks.
+ uint8_t length = 1;
+ port->writeBlob(addr + 8, &length, 1);
+ checkSum += length;
+
+ port->writeBlob(addr + 9, &specRev, 1);
+ checkSum += specRev;
+
+ port->writeBlob(addr + 11, &defaultConfig, 1);
+ checkSum += defaultConfig;
+
+ uint32_t features2_5 = imcrPresent ? (1 << 7) : 0;
+ checkSum += writeOutField(port, addr + 12, features2_5);
+
+ checkSum = -checkSum;
+ port->writeBlob(addr + 10, &checkSum, 1);
+
+ return 16;
+}
+
+X86ISA::IntelMP::FloatingPointer::FloatingPointer(Params * p) :
+ SimObject(p), tableAddr(0), specRev(p->spec_rev),
+ defaultConfig(p->default_config), imcrPresent(p->imcr_present)
+{}
+
+X86ISA::IntelMP::FloatingPointer *
+X86IntelMPFloatingPointerParams::create()
+{
+ return new X86ISA::IntelMP::FloatingPointer(this);
+}
+
+Addr
+X86ISA::IntelMP::BaseConfigEntry::writeOut(FunctionalPort * port,
+ Addr addr, uint8_t &checkSum)
+{
+ port->writeBlob(addr, &type, 1);
+ checkSum += type;
+ return 1;
+}
+
+X86ISA::IntelMP::BaseConfigEntry::BaseConfigEntry(Params * p, uint8_t _type) :
+ SimObject(p), type(_type)
+{}
+
+Addr
+X86ISA::IntelMP::ExtConfigEntry::writeOut(FunctionalPort * port,
+ Addr addr, uint8_t &checkSum)
+{
+ port->writeBlob(addr, &type, 1);
+ checkSum += type;
+ port->writeBlob(addr + 1, &length, 1);
+ checkSum += length;
+ return 1;
+}
+
+X86ISA::IntelMP::ExtConfigEntry::ExtConfigEntry(Params * p,
+ uint8_t _type, uint8_t _length) :
+ SimObject(p), type(_type), length(_length)
+{}
+
+const char X86ISA::IntelMP::ConfigTable::signature[] = "PCMP";
+
+Addr
+X86ISA::IntelMP::ConfigTable::writeOut(FunctionalPort * port, Addr addr)
+{
+ uint8_t checkSum = 0;
+
+ port->writeBlob(addr, (uint8_t *)signature, 4);
+ for (int i = 0; i < 4; i++)
+ checkSum += signature[i];
+
+ // Base table length goes here but will be calculated later.
+
+ port->writeBlob(addr + 6, (uint8_t *)(&specRev), 1);
+ checkSum += specRev;
+
+ // The checksum goes here but is still being calculated.
+
+ checkSum += writeOutString(port, addr + 8, oemID, 8);
+ checkSum += writeOutString(port, addr + 16, productID, 12);
+
+ checkSum += writeOutField(port, addr + 28, oemTableAddr);
+ checkSum += writeOutField(port, addr + 32, oemTableSize);
+ checkSum += writeOutField(port, addr + 34, (uint16_t)baseEntries.size());
+ checkSum += writeOutField(port, addr + 36, localApic);
+
+ uint8_t reserved = 0;
+ port->writeBlob(addr + 43, &reserved, 1);
+ checkSum += reserved;
+
+ vector<BaseConfigEntry *>::iterator baseEnt;
+ uint16_t offset = 44;
+ for (baseEnt = baseEntries.begin();
+ baseEnt != baseEntries.end(); baseEnt++) {
+ offset += (*baseEnt)->writeOut(port, addr + offset, checkSum);
+ }
+
+ // We've found the end of the base table this point.
+ checkSum += writeOutField(port, addr + 4, offset);
+
+ vector<ExtConfigEntry *>::iterator extEnt;
+ uint16_t extOffset = 0;
+ uint8_t extCheckSum = 0;
+ for (extEnt = extEntries.begin();
+ extEnt != extEntries.end(); extEnt++) {
+ extOffset += (*extEnt)->writeOut(port,
+ addr + offset + extOffset, extCheckSum);
+ }
+
+ checkSum += writeOutField(port, addr + 40, extOffset);
+ extCheckSum = -extCheckSum;
+ checkSum += writeOutField(port, addr + 42, extCheckSum);
+
+ // And now, we finally have the whole check sum completed.
+ checkSum = -checkSum;
+ writeOutField(port, addr + 7, checkSum);
+
+ return offset + extOffset;
+};
+
+X86ISA::IntelMP::ConfigTable::ConfigTable(Params * p) : SimObject(p),
+ specRev(p->spec_rev), oemID(p->oem_id), productID(p->product_id),
+ oemTableAddr(p->oem_table_addr), oemTableSize(p->oem_table_size),
+ localApic(p->local_apic),
+ baseEntries(p->base_entries), extEntries(p->ext_entries)
+{}
+
+X86ISA::IntelMP::ConfigTable *
+X86IntelMPConfigTableParams::create()
+{
+ return new X86ISA::IntelMP::ConfigTable(this);
+}
+
+Addr
+X86ISA::IntelMP::Processor::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ BaseConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 1, localApicID);
+ checkSum += writeOutField(port, addr + 2, localApicVersion);
+ checkSum += writeOutField(port, addr + 3, cpuFlags);
+ checkSum += writeOutField(port, addr + 4, cpuSignature);
+ checkSum += writeOutField(port, addr + 8, featureFlags);
+
+ uint32_t reserved = 0;
+ port->writeBlob(addr + 12, (uint8_t *)(&reserved), 4);
+ port->writeBlob(addr + 16, (uint8_t *)(&reserved), 4);
+ return 20;
+}
+
+X86ISA::IntelMP::Processor::Processor(Params * p) : BaseConfigEntry(p, 0),
+ localApicID(p->local_apic_id), localApicVersion(p->local_apic_version),
+ cpuFlags(0), cpuSignature(0), featureFlags(p->feature_flags)
+{
+ if (p->enable)
+ cpuFlags |= (1 << 0);
+ if (p->bootstrap)
+ cpuFlags |= (1 << 1);
+
+ replaceBits(cpuSignature, 0, 3, p->stepping);
+ replaceBits(cpuSignature, 4, 7, p->model);
+ replaceBits(cpuSignature, 8, 11, p->family);
+}
+
+X86ISA::IntelMP::Processor *
+X86IntelMPProcessorParams::create()
+{
+ return new X86ISA::IntelMP::Processor(this);
+}
+
+Addr
+X86ISA::IntelMP::Bus::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ BaseConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 1, busID);
+ checkSum += writeOutString(port, addr + 2, busType, 6);
+ return 8;
+}
+
+X86ISA::IntelMP::Bus::Bus(Params * p) : BaseConfigEntry(p, 1),
+ busID(p->bus_id), busType(p->bus_type)
+{}
+
+X86ISA::IntelMP::Bus *
+X86IntelMPBusParams::create()
+{
+ return new X86ISA::IntelMP::Bus(this);
+}
+
+Addr
+X86ISA::IntelMP::IOAPIC::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ BaseConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 1, id);
+ checkSum += writeOutField(port, addr + 2, version);
+ checkSum += writeOutField(port, addr + 3, flags);
+ checkSum += writeOutField(port, addr + 4, address);
+ return 8;
+}
+
+X86ISA::IntelMP::IOAPIC::IOAPIC(Params * p) : BaseConfigEntry(p, 2),
+ id(p->id), version(p->version), flags(0), address(p->address)
+{
+ if (p->enable)
+ flags |= 1;
+}
+
+X86ISA::IntelMP::IOAPIC *
+X86IntelMPIOAPICParams::create()
+{
+ return new X86ISA::IntelMP::IOAPIC(this);
+}
+
+Addr
+X86ISA::IntelMP::IntAssignment::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ BaseConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 1, interruptType);
+ checkSum += writeOutField(port, addr + 2, flags);
+ checkSum += writeOutField(port, addr + 4, sourceBusID);
+ checkSum += writeOutField(port, addr + 5, sourceBusIRQ);
+ checkSum += writeOutField(port, addr + 6, destApicID);
+ checkSum += writeOutField(port, addr + 7, destApicIntIn);
+ return 8;
+}
+
+X86ISA::IntelMP::IOIntAssignment::IOIntAssignment(Params * p) :
+ IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 3,
+ p->source_bus_id, p->source_bus_irq,
+ p->dest_io_apic_id, p->dest_io_apic_intin)
+{}
+
+X86ISA::IntelMP::IOIntAssignment *
+X86IntelMPIOIntAssignmentParams::create()
+{
+ return new X86ISA::IntelMP::IOIntAssignment(this);
+}
+
+X86ISA::IntelMP::LocalIntAssignment::LocalIntAssignment(Params * p) :
+ IntAssignment(p, p->interrupt_type, p->polarity, p->trigger, 4,
+ p->source_bus_id, p->source_bus_irq,
+ p->dest_local_apic_id, p->dest_local_apic_intin)
+{}
+
+X86ISA::IntelMP::LocalIntAssignment *
+X86IntelMPLocalIntAssignmentParams::create()
+{
+ return new X86ISA::IntelMP::LocalIntAssignment(this);
+}
+
+Addr
+X86ISA::IntelMP::AddrSpaceMapping::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ ExtConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 2, busID);
+ checkSum += writeOutField(port, addr + 3, addrType);
+ checkSum += writeOutField(port, addr + 4, addr);
+ checkSum += writeOutField(port, addr + 12, addrLength);
+ return length;
+}
+
+X86ISA::IntelMP::AddrSpaceMapping::AddrSpaceMapping(Params * p) :
+ ExtConfigEntry(p, 128, 20),
+ busID(p->bus_id), addrType(p->address_type),
+ addr(p->address), addrLength(p->length)
+{}
+
+X86ISA::IntelMP::AddrSpaceMapping *
+X86IntelMPAddrSpaceMappingParams::create()
+{
+ return new X86ISA::IntelMP::AddrSpaceMapping(this);
+}
+
+Addr
+X86ISA::IntelMP::BusHierarchy::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ ExtConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 2, busID);
+ checkSum += writeOutField(port, addr + 3, info);
+ checkSum += writeOutField(port, addr + 4, parentBus);
+
+ uint32_t reserved = 0;
+ port->writeBlob(addr + 5, (uint8_t *)(&reserved), 3);
+
+ return length;
+}
+
+X86ISA::IntelMP::BusHierarchy::BusHierarchy(Params * p) :
+ ExtConfigEntry(p, 129, 8),
+ busID(p->bus_id), info(0), parentBus(p->parent_bus)
+{
+ if (p->subtractive_decode)
+ info |= 1;
+}
+
+X86ISA::IntelMP::BusHierarchy *
+X86IntelMPBusHierarchyParams::create()
+{
+ return new X86ISA::IntelMP::BusHierarchy(this);
+}
+
+Addr
+X86ISA::IntelMP::CompatAddrSpaceMod::writeOut(
+ FunctionalPort * port, Addr addr, uint8_t &checkSum)
+{
+ ExtConfigEntry::writeOut(port, addr, checkSum);
+ checkSum += writeOutField(port, addr + 2, busID);
+ checkSum += writeOutField(port, addr + 3, mod);
+ checkSum += writeOutField(port, addr + 4, rangeList);
+ return length;
+}
+
+X86ISA::IntelMP::CompatAddrSpaceMod::CompatAddrSpaceMod(Params * p) :
+ ExtConfigEntry(p, 130, 8),
+ busID(p->bus_id), mod(0), rangeList(p->range_list)
+{
+ if (p->add)
+ mod |= 1;
+}
+
+X86ISA::IntelMP::CompatAddrSpaceMod *
+X86IntelMPCompatAddrSpaceModParams::create()
+{
+ return new X86ISA::IntelMP::CompatAddrSpaceMod(this);
+}
diff --git a/src/arch/x86/bios/intelmp.hh b/src/arch/x86/bios/intelmp.hh
new file mode 100644
index 000000000..e8d1d656e
--- /dev/null
+++ b/src/arch/x86/bios/intelmp.hh
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_BIOS_INTELMP_HH__
+#define __ARCH_X86_BIOS_INTELMP_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/bitfield.hh"
+#include "sim/sim_object.hh"
+
+#include "enums/X86IntelMPAddressType.hh"
+#include "enums/X86IntelMPInterruptType.hh"
+#include "enums/X86IntelMPPolarity.hh"
+#include "enums/X86IntelMPRangeList.hh"
+#include "enums/X86IntelMPTriggerMode.hh"
+
+class FunctionalPort;
+
+// Config entry types
+class X86IntelMPBaseConfigEntryParams;
+class X86IntelMPExtConfigEntryParams;
+
+// General table structures
+class X86IntelMPConfigTableParams;
+class X86IntelMPFloatingPointerParams;
+
+// Base entry types
+class X86IntelMPBusParams;
+class X86IntelMPIOAPICParams;
+class X86IntelMPIOIntAssignmentParams;
+class X86IntelMPLocalIntAssignmentParams;
+class X86IntelMPProcessorParams;
+
+// Extended entry types
+class X86IntelMPAddrSpaceMappingParams;
+class X86IntelMPBusHierarchyParams;
+class X86IntelMPCompatAddrSpaceModParams;
+
+namespace X86ISA
+{
+
+namespace IntelMP
+{
+
+class FloatingPointer : public SimObject
+{
+ protected:
+ typedef X86IntelMPFloatingPointerParams Params;
+
+ uint32_t tableAddr;
+ uint8_t specRev;
+ uint8_t defaultConfig;
+ bool imcrPresent;
+
+ static const char signature[];
+
+ public:
+
+ Addr writeOut(FunctionalPort * port, Addr addr);
+
+ Addr getTableAddr()
+ {
+ return tableAddr;
+ }
+
+ void setTableAddr(Addr addr)
+ {
+ tableAddr = addr;
+ }
+
+ FloatingPointer(Params * p);
+};
+
+class BaseConfigEntry : public SimObject
+{
+ protected:
+ typedef X86IntelMPBaseConfigEntryParams Params;
+
+ uint8_t type;
+
+ public:
+
+ virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ BaseConfigEntry(Params * p, uint8_t _type);
+};
+
+class ExtConfigEntry : public SimObject
+{
+ protected:
+ typedef X86IntelMPExtConfigEntryParams Params;
+
+ uint8_t type;
+ uint8_t length;
+
+ public:
+
+ virtual Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ ExtConfigEntry(Params * p, uint8_t _type, uint8_t _length);
+};
+
+class ConfigTable : public SimObject
+{
+ protected:
+ typedef X86IntelMPConfigTableParams Params;
+
+ static const char signature[];
+
+ uint8_t specRev;
+ std::string oemID;
+ std::string productID;
+ uint32_t oemTableAddr;
+ uint16_t oemTableSize;
+ uint32_t localApic;
+
+ std::vector<BaseConfigEntry *> baseEntries;
+ std::vector<ExtConfigEntry *> extEntries;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr);
+
+ ConfigTable(Params * p);
+};
+
+class Processor : public BaseConfigEntry
+{
+ protected:
+ typedef X86IntelMPProcessorParams Params;
+
+ uint8_t localApicID;
+ uint8_t localApicVersion;
+ uint8_t cpuFlags;
+ uint32_t cpuSignature;
+ uint32_t featureFlags;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ Processor(Params * p);
+};
+
+class Bus : public BaseConfigEntry
+{
+ protected:
+ typedef X86IntelMPBusParams Params;
+
+ uint8_t busID;
+ std::string busType;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ Bus(Params * p);
+};
+
+class IOAPIC : public BaseConfigEntry
+{
+ protected:
+ typedef X86IntelMPIOAPICParams Params;
+
+ uint8_t id;
+ uint8_t version;
+ uint8_t flags;
+ uint32_t address;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ IOAPIC(Params * p);
+};
+
+class IntAssignment : public BaseConfigEntry
+{
+ protected:
+ uint8_t interruptType;
+
+ uint16_t flags;
+
+ uint8_t sourceBusID;
+ uint8_t sourceBusIRQ;
+
+ uint8_t destApicID;
+ uint8_t destApicIntIn;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ IntAssignment(X86IntelMPBaseConfigEntryParams * p,
+ Enums::X86IntelMPInterruptType _interruptType,
+ Enums::X86IntelMPPolarity polarity,
+ Enums::X86IntelMPTriggerMode trigger,
+ uint8_t _type,
+ uint8_t _sourceBusID, uint8_t _sourceBusIRQ,
+ uint8_t _destApicID, uint8_t _destApicIntIn) :
+ BaseConfigEntry(p, _type),
+ interruptType(_interruptType), flags(0),
+ sourceBusID(_sourceBusID), sourceBusIRQ(_sourceBusIRQ),
+ destApicID(_destApicID), destApicIntIn(_destApicIntIn)
+ {
+ replaceBits(flags, 0, 1, polarity);
+ replaceBits(flags, 2, 3, trigger);
+ }
+};
+
+class IOIntAssignment : public IntAssignment
+{
+ protected:
+ typedef X86IntelMPIOIntAssignmentParams Params;
+
+ public:
+ IOIntAssignment(Params * p);
+};
+
+class LocalIntAssignment : public IntAssignment
+{
+ protected:
+ typedef X86IntelMPLocalIntAssignmentParams Params;
+
+ public:
+ LocalIntAssignment(Params * p);
+};
+
+class AddrSpaceMapping : public ExtConfigEntry
+{
+ protected:
+ typedef X86IntelMPAddrSpaceMappingParams Params;
+
+ uint8_t busID;
+ uint8_t addrType;
+ uint64_t addr;
+ uint64_t addrLength;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ AddrSpaceMapping(Params * p);
+};
+
+class BusHierarchy : public ExtConfigEntry
+{
+ protected:
+ typedef X86IntelMPBusHierarchyParams Params;
+
+ uint8_t busID;
+ uint8_t info;
+ uint8_t parentBus;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ BusHierarchy(Params * p);
+};
+
+class CompatAddrSpaceMod : public ExtConfigEntry
+{
+ protected:
+ typedef X86IntelMPCompatAddrSpaceModParams Params;
+
+ uint8_t busID;
+ uint8_t mod;
+ uint32_t rangeList;
+
+ public:
+ Addr writeOut(FunctionalPort * port, Addr addr, uint8_t &checkSum);
+
+ CompatAddrSpaceMod(Params * p);
+};
+
+} //IntelMP
+
+} //X86ISA
+
+#endif
diff --git a/src/arch/x86/smbios.cc b/src/arch/x86/bios/smbios.cc
index 319650c1f..95ade1e4d 100644
--- a/src/arch/x86/smbios.cc
+++ b/src/arch/x86/bios/smbios.cc
@@ -85,12 +85,17 @@
* Authors: Gabe Black
*/
-#include "arch/x86/smbios.hh"
+#include "arch/x86/bios/smbios.hh"
#include "arch/x86/isa_traits.hh"
#include "mem/port.hh"
+#include "params/X86SMBiosBiosInformation.hh"
+#include "params/X86SMBiosSMBiosStructure.hh"
+#include "params/X86SMBiosSMBiosTable.hh"
#include "sim/byteswap.hh"
#include "sim/host.hh"
+using namespace std;
+
const char X86ISA::SMBios::SMBiosTable::SMBiosHeader::anchorString[] = "_SM_";
const uint8_t X86ISA::SMBios::SMBiosTable::
SMBiosHeader::formattedArea[] = {0,0,0,0,0};
@@ -101,6 +106,116 @@ const uint8_t X86ISA::SMBios::SMBiosTable::
const char X86ISA::SMBios::SMBiosTable::
SMBiosHeader::IntermediateHeader::anchorString[] = "_DMI_";
+template <class T>
+uint64_t
+composeBitVector(T vec)
+{
+ uint64_t val = 0;
+ typename T::iterator vecIt;
+ for (vecIt = vec.begin(); vecIt != vec.end(); vecIt++) {
+ val |= (1 << (*vecIt));
+ }
+ return val;
+}
+
+uint16_t
+X86ISA::SMBios::SMBiosStructure::writeOut(FunctionalPort * port, Addr addr)
+{
+ port->writeBlob(addr, (uint8_t *)(&type), 1);
+
+ uint8_t length = getLength();
+ port->writeBlob(addr + 1, (uint8_t *)(&length), 1);
+
+ uint16_t handleGuest = X86ISA::htog(handle);
+ port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2);
+
+ return length + getStringLength();
+}
+
+X86ISA::SMBios::SMBiosStructure::SMBiosStructure(Params * p, uint8_t _type) :
+ SimObject(p), type(_type), handle(0), stringFields(false)
+{}
+
+void
+X86ISA::SMBios::SMBiosStructure::writeOutStrings(
+ FunctionalPort * port, Addr addr)
+{
+ std::vector<std::string>::iterator it;
+ Addr offset = 0;
+
+ const uint8_t nullTerminator = 0;
+
+ // If there are string fields but none of them are used, that's a
+ // special case which is handled by this if.
+ if (strings.size() == 0 && stringFields) {
+ port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1);
+ offset++;
+ } else {
+ for (it = strings.begin(); it != strings.end(); it++) {
+ port->writeBlob(addr + offset,
+ (uint8_t *)it->c_str(), it->length() + 1);
+ offset += it->length() + 1;
+ }
+ }
+ port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1);
+}
+
+int
+X86ISA::SMBios::SMBiosStructure::getStringLength()
+{
+ int size = 0;
+ std::vector<std::string>::iterator it;
+
+ for (it = strings.begin(); it != strings.end(); it++) {
+ size += it->length() + 1;
+ }
+
+ return size + 1;
+}
+
+int
+X86ISA::SMBios::SMBiosStructure::addString(string & newString)
+{
+ stringFields = true;
+ // If a string is empty, treat it as not existing. The index for empty
+ // strings is 0.
+ if (newString.length() == 0)
+ return 0;
+ strings.push_back(newString);
+ return strings.size();
+}
+
+string
+X86ISA::SMBios::SMBiosStructure::readString(int n)
+{
+ assert(n > 0 && n <= strings.size());
+ return strings[n - 1];
+}
+
+void
+X86ISA::SMBios::SMBiosStructure::setString(int n, std::string & newString)
+{
+ assert(n > 0 && n <= strings.size());
+ strings[n - 1] = newString;
+}
+
+X86ISA::SMBios::BiosInformation::BiosInformation(Params * p) :
+ SMBiosStructure(p, Type),
+ startingAddrSegment(p->starting_addr_segment),
+ romSize(p->rom_size),
+ majorVer(p->major), minorVer(p->minor),
+ embContFirmwareMajor(p->emb_cont_firmware_major),
+ embContFirmwareMinor(p->emb_cont_firmware_minor)
+ {
+ vendor = addString(p->vendor);
+ version = addString(p->version);
+ releaseDate = addString(p->release_date);
+
+ characteristics = composeBitVector(p->characteristics);
+ characteristicExtBytes =
+ composeBitVector(p->characteristic_ext_bytes);
+ }
+
uint16_t
X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr)
{
@@ -122,8 +237,8 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr)
X86ISA::htog(characteristicExtBytes);
port->writeBlob(addr + 0x12, (uint8_t *)(&characteristicExtBytesGuest), 2);
- port->writeBlob(addr + 0x14, (uint8_t *)(&major), 1);
- port->writeBlob(addr + 0x15, (uint8_t *)(&minor), 1);
+ port->writeBlob(addr + 0x14, (uint8_t *)(&majorVer), 1);
+ port->writeBlob(addr + 0x15, (uint8_t *)(&minorVer), 1);
port->writeBlob(addr + 0x16, (uint8_t *)(&embContFirmwareMajor), 1);
port->writeBlob(addr + 0x17, (uint8_t *)(&embContFirmwareMinor), 1);
@@ -132,9 +247,22 @@ X86ISA::SMBios::BiosInformation::writeOut(FunctionalPort * port, Addr addr)
return size;
}
+X86ISA::SMBios::SMBiosTable::SMBiosTable(Params * p) :
+ SimObject(p), structures(p->structures)
+{
+ smbiosHeader.majorVersion = p->major_version;
+ smbiosHeader.minorVersion = p->minor_version;
+ assert(p->major_version <= 9);
+ assert(p->minor_version <= 9);
+ smbiosHeader.intermediateHeader.smbiosBCDRevision =
+ (p->major_version << 4) | p->minor_version;
+}
+
void
-X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr)
+X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr,
+ Addr &headerSize, Addr &structSize)
{
+ headerSize = 0x1F;
/*
* The main header
@@ -205,14 +333,16 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr)
Addr base = smbiosHeader.intermediateHeader.tableAddr;
Addr offset = 0;
uint16_t maxSize = 0;
- std::vector<SMBiosStructure>::iterator it;
+ std::vector<SMBiosStructure *>::iterator it;
for (it = structures.begin(); it != structures.end(); it++) {
- uint16_t size = it->writeOut(port, base + offset);
+ uint16_t size = (*it)->writeOut(port, base + offset);
if (size > maxSize)
maxSize = size;
offset += size;
}
+ structSize = offset;
+
/*
* Header
*/
@@ -243,3 +373,15 @@ X86ISA::SMBios::SMBiosTable::writeOut(FunctionalPort * port, Addr addr)
intChecksum = -intChecksum;
port->writeBlob(addr + 0x15, (uint8_t *)(&intChecksum), 1);
}
+
+X86ISA::SMBios::BiosInformation *
+X86SMBiosBiosInformationParams::create()
+{
+ return new X86ISA::SMBios::BiosInformation(this);
+}
+
+X86ISA::SMBios::SMBiosTable *
+X86SMBiosSMBiosTableParams::create()
+{
+ return new X86ISA::SMBios::SMBiosTable(this);
+}
diff --git a/src/arch/x86/smbios.hh b/src/arch/x86/bios/smbios.hh
index c126de220..1c50d0b48 100644
--- a/src/arch/x86/smbios.hh
+++ b/src/arch/x86/bios/smbios.hh
@@ -85,16 +85,21 @@
* Authors: Gabe Black
*/
-#ifndef __ARCH_X86_SMBIOS_HH__
-#define __ARCH_X86_SMBIOS_HH__
+#ifndef __ARCH_X86_BIOS_SMBIOS_HH__
+#define __ARCH_X86_BIOS_SMBIOS_HH__
#include <string>
#include <vector>
-#include "arch/x86/isa_traits.hh"
-#include "mem/port.hh"
-#include "sim/byteswap.hh"
+#include "enums/Characteristic.hh"
+#include "enums/ExtCharacteristic.hh"
#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+class FunctionalPort;
+class X86SMBiosBiosInformationParams;
+class X86SMBiosSMBiosStructureParams;
+class X86SMBiosSMBiosTableParams;
namespace X86ISA
{
@@ -102,8 +107,11 @@ namespace X86ISA
namespace SMBios
{
-class SMBiosStructure
+class SMBiosStructure : public SimObject
{
+ protected:
+ typedef X86SMBiosSMBiosStructureParams Params;
+
public:
virtual
@@ -126,73 +134,33 @@ class SMBiosStructure
return 4;
}
- virtual uint16_t
- writeOut(FunctionalPort * port, Addr addr)
- {
- port->writeBlob(addr, (uint8_t *)(&type), 1);
-
- uint8_t length = getLength();
- port->writeBlob(addr + 1, (uint8_t *)(&length), 1);
-
- uint16_t handleGuest = X86ISA::htog(handle);
- port->writeBlob(addr + 2, (uint8_t *)(&handleGuest), 2);
-
- return length + getStringLength();
- }
+ virtual uint16_t writeOut(FunctionalPort * port, Addr addr);
protected:
- std::vector<std::string> strings;
-
- void writeOutStrings(FunctionalPort * port, Addr addr)
- {
- std::vector<std::string>::iterator it;
- Addr offset = 0;
-
- for (it = strings.begin(); it != strings.end(); it++) {
- port->writeBlob(addr + offset,
- (uint8_t *)it->c_str(), it->length() + 1);
- offset += it->length() + 1;
- }
+ bool stringFields;
- const uint8_t nullTerminator = 0;
- port->writeBlob(addr + offset, (uint8_t *)(&nullTerminator), 1);
- }
+ SMBiosStructure(Params * p, uint8_t _type);
- int getStringLength()
- {
- int size = 0;
- std::vector<std::string>::iterator it;
+ std::vector<std::string> strings;
- for (it = strings.begin(); it != strings.end(); it++) {
- size += it->length() + 1;
- }
+ void writeOutStrings(FunctionalPort * port, Addr addr);
- return size + 1;
- }
+ int getStringLength();
public:
- int addString(std::string & newString)
- {
- strings.push_back(newString);
- return strings.size();
- }
-
- std::string readString(int n)
- {
- assert(n > 0 && n <= strings.size());
- return strings[n - 1];
- }
-
- void setString(int n, std::string & newString)
- {
- assert(n > 0 && n <= strings.size());
- strings[n - 1] = newString;
- }
+ int addString(std::string & newString);
+ std::string readString(int n);
+ void setString(int n, std::string & newString);
};
class BiosInformation : public SMBiosStructure
{
+ protected:
+ const static uint8_t Type = 0;
+
+ typedef X86SMBiosBiosInformationParams Params;
+
public:
// Offset 04h, 1 byte
uint8_t vendor;
@@ -211,21 +179,25 @@ class BiosInformation : public SMBiosStructure
// Offset 12h, 2 bytes
uint16_t characteristicExtBytes;
// Offset 14h, 1 byte
- uint8_t major;
+ uint8_t majorVer;
// Offset 15h, 1 byte
- uint8_t minor;
+ uint8_t minorVer;
// Offset 16h, 1 byte
uint8_t embContFirmwareMajor;
// Offset 17h, 1 byte
uint8_t embContFirmwareMinor;
+ BiosInformation(Params * p);
+
uint8_t getLength() { return 0x18; }
uint16_t writeOut(FunctionalPort * port, Addr addr);
};
-class SMBiosTable
+class SMBiosTable : public SimObject
{
- public:
+ protected:
+ typedef X86SMBiosSMBiosTableParams Params;
+
struct SMBiosHeader
{
SMBiosHeader()
@@ -281,9 +253,23 @@ class SMBiosTable
} intermediateHeader;
} smbiosHeader;
- void writeOut(FunctionalPort * port, Addr addr);
+ std::vector<SMBiosStructure *> structures;
+
+ public:
+ SMBiosTable(Params * p);
+
+ Addr getTableAddr()
+ {
+ return smbiosHeader.intermediateHeader.tableAddr;
+ }
+
+ void setTableAddr(Addr addr)
+ {
+ smbiosHeader.intermediateHeader.tableAddr = addr;
+ }
- std::vector<SMBiosStructure> structures;
+ void writeOut(FunctionalPort * port, Addr addr,
+ Addr &headerSize, Addr &structSize);
};
} //SMBios
diff --git a/src/arch/x86/cpuid.cc b/src/arch/x86/cpuid.cc
new file mode 100644
index 000000000..247965df4
--- /dev/null
+++ b/src/arch/x86/cpuid.cc
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/cpuid.hh"
+#include "base/bitfield.hh"
+#include "cpu/thread_context.hh"
+
+namespace X86ISA {
+ enum StandardCpuidFunction {
+ VendorAndLargestStdFunc,
+ FamilyModelStepping,
+ NumStandardCpuidFuncs
+ };
+
+ enum ExtendedCpuidFunctions {
+ VendorAndLargestExtFunc,
+ FamilyModelSteppingBrandFeatures,
+ NameString1,
+ NameString2,
+ NameString3,
+ L1CacheAndTLB,
+ L2L3CacheAndL2TLB,
+ APMInfo,
+
+ /*
+ * The following are defined by the spec but not yet implemented
+ */
+/* LongModeAddressSize,
+ // Function 9 is reserved
+ SVMInfo = 10,
+ // Functions 11-24 are reserved
+ TLB1GBPageInfo = 25,
+ PerformanceInfo,*/
+
+ NumExtendedCpuidFuncs
+ };
+
+ static const int vendorStringSize = 13;
+ static const char vendorString[vendorStringSize] = "AuthenticAMD";
+ static const int nameStringSize = 48;
+ static const char nameString[nameStringSize] = "Fake M5 x86_64 CPU";
+
+ uint64_t
+ stringToRegister(const char *str)
+ {
+ uint64_t reg = 0;
+ for (int pos = 3; pos >=0; pos--) {
+ reg <<= 8;
+ reg |= str[pos];
+ }
+ return reg;
+ }
+
+ bool
+ doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result)
+ {
+ uint16_t family = bits(function, 31, 16);
+ uint16_t funcNum = bits(function, 15, 0);
+ if (family == 0x8000) {
+ // The extended functions
+ switch (funcNum) {
+ case VendorAndLargestExtFunc:
+ assert(vendorStringSize >= 12);
+ result = CpuidResult(
+ NumExtendedCpuidFuncs - 1,
+ stringToRegister(vendorString),
+ stringToRegister(vendorString + 4),
+ stringToRegister(vendorString + 8));
+ break;
+ case FamilyModelSteppingBrandFeatures:
+ result = CpuidResult(0x00020f51, 0x00000405,
+ 0xe3d3fbff, 0x00000001);
+ break;
+ case NameString1:
+ case NameString2:
+ case NameString3:
+ {
+ // Zero fill anything beyond the end of the string. This
+ // should go away once the string is a vetted parameter.
+ char cleanName[nameStringSize];
+ memset(cleanName, '\0', nameStringSize);
+ strncpy(cleanName, nameString, nameStringSize);
+
+ int offset = (funcNum - NameString1) * 16;
+ assert(nameStringSize >= offset + 16);
+ result = CpuidResult(
+ stringToRegister(cleanName + offset + 0),
+ stringToRegister(cleanName + offset + 4),
+ stringToRegister(cleanName + offset + 8),
+ stringToRegister(cleanName + offset + 12));
+ }
+ break;
+ case L1CacheAndTLB:
+ result = CpuidResult(0xff08ff08, 0xff20ff20,
+ 0x40020140, 0x40020140);
+ break;
+ case L2L3CacheAndL2TLB:
+ result = CpuidResult(0x00000000, 0x42004200,
+ 0x00000000, 0x04008140);
+ break;
+ case APMInfo:
+ result = CpuidResult(0x80000018, 0x68747541,
+ 0x69746e65, 0x444d4163);
+ break;
+/* case LongModeAddressSize:
+ case SVMInfo:
+ case TLB1GBPageInfo:
+ case PerformanceInfo:*/
+ default:
+ return false;
+ }
+ } else if(family == 0x0000) {
+ // The standard functions
+ switch (funcNum) {
+ case VendorAndLargestStdFunc:
+ assert(vendorStringSize >= 12);
+ result = CpuidResult(
+ NumStandardCpuidFuncs - 1,
+ stringToRegister(vendorString),
+ stringToRegister(vendorString + 4),
+ stringToRegister(vendorString + 8));
+ break;
+ case FamilyModelStepping:
+ result = CpuidResult(0x00020f51, 0000000405,
+ 0xe3d3fbff, 0x00000001);
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+ }
+} //namespace X86ISA
diff --git a/src/arch/x86/cpuid.hh b/src/arch/x86/cpuid.hh
new file mode 100644
index 000000000..5cb4c7972
--- /dev/null
+++ b/src/arch/x86/cpuid.hh
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_CPUID_HH__
+#define __ARCH_X86_CPUID_HH__
+
+#include <inttypes.h>
+
+class ThreadContext;
+
+namespace X86ISA
+{
+ struct CpuidResult
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+
+ // These are not in alphebetical order on purpose. The order reflects
+ // how the CPUID orders the registers when it returns results.
+ CpuidResult(uint64_t _rax, uint64_t _rbx,
+ uint64_t _rdx, uint64_t _rcx) :
+ rax(_rax), rbx(_rbx), rcx(_rcx), rdx(_rdx)
+ {}
+
+ CpuidResult()
+ {}
+ };
+
+ bool doCpuid(ThreadContext * tc, uint32_t function, CpuidResult &result);
+} // namespace X86ISA
+
+#endif
diff --git a/src/arch/x86/emulenv.cc b/src/arch/x86/emulenv.cc
index 31b705d79..0d7b32130 100644
--- a/src/arch/x86/emulenv.cc
+++ b/src/arch/x86/emulenv.cc
@@ -55,6 +55,8 @@
* Authors: Gabe Black
*/
+#include <cassert>
+
#include "arch/x86/emulenv.hh"
#include "base/misc.hh"
@@ -91,7 +93,7 @@ void EmulEnv::doModRM(const ExtMachInst & machInst)
//Figure out what segment to use. This won't be entirely accurate since
//the presence of a displacement is supposed to make the instruction
//default to the data segment.
- if (base != INTREG_RBP && base != INTREG_RSP ||
+ if ((base != INTREG_RBP && base != INTREG_RSP) ||
0/*Has an immediate offset*/) {
seg = SEGMENT_REG_DS;
//Handle any segment override that might have been in the instruction
@@ -103,3 +105,11 @@ void EmulEnv::doModRM(const ExtMachInst & machInst)
}
}
+void EmulEnv::setSeg(const ExtMachInst & machInst)
+{
+ seg = SEGMENT_REG_DS;
+ //Handle any segment override that might have been in the instruction
+ int segFromInst = machInst.legacy.seg;
+ if (segFromInst)
+ seg = (SegmentRegIndex)(segFromInst - 1);
+}
diff --git a/src/arch/x86/emulenv.hh b/src/arch/x86/emulenv.hh
index 1044dbdf9..cdb1bf863 100644
--- a/src/arch/x86/emulenv.hh
+++ b/src/arch/x86/emulenv.hh
@@ -86,6 +86,7 @@ namespace X86ISA
{;}
void doModRM(const ExtMachInst & machInst);
+ void setSeg(const ExtMachInst & machInst);
};
};
diff --git a/src/arch/x86/faults.cc b/src/arch/x86/faults.cc
index 1c94a1251..b81400cc3 100644
--- a/src/arch/x86/faults.cc
+++ b/src/arch/x86/faults.cc
@@ -85,6 +85,7 @@
* Authors: Gabe Black
*/
+#include "arch/x86/decoder.hh"
#include "arch/x86/faults.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
@@ -100,71 +101,90 @@
namespace X86ISA
{
#if FULL_SYSTEM
- void X86Trap::invoke(ThreadContext * tc)
+ void X86FaultBase::invoke(ThreadContext * tc)
{
- panic("X86 faults are not implemented!");
+ Addr pc = tc->readPC();
+ DPRINTF(Faults, "RIP %#x: vector %d: %s\n", pc, vector, describe());
+ using namespace X86ISAInst::RomLabels;
+ HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ MicroPC entry;
+ if (m5reg.mode == LongMode) {
+ if (isSoft()) {
+ entry = extern_label_longModeSoftInterrupt;
+ } else {
+ entry = extern_label_longModeInterrupt;
+ }
+ } else {
+ entry = extern_label_legacyModeInterrupt;
+ }
+ tc->setIntReg(INTREG_MICRO(1), vector);
+ tc->setIntReg(INTREG_MICRO(7), pc);
+ if (errorCode != (uint64_t)(-1)) {
+ if (m5reg.mode == LongMode) {
+ entry = extern_label_longModeInterruptWithError;
+ } else {
+ panic("Legacy mode interrupts with error codes "
+ "aren't implementde.\n");
+ }
+ // Software interrupts shouldn't have error codes. If one does,
+ // there would need to be microcode to set it up.
+ assert(!isSoft());
+ tc->setIntReg(INTREG_MICRO(15), errorCode);
+ }
+ tc->setMicroPC(romMicroPC(entry));
+ tc->setNextMicroPC(romMicroPC(entry) + 1);
}
- void X86Abort::invoke(ThreadContext * tc)
+ std::string
+ X86FaultBase::describe() const
{
- panic("X86 faults are not implemented!");
- }
+ std::stringstream ss;
+ ccprintf(ss, "%s", mnemonic());
+ if (errorCode != (uint64_t)(-1)) {
+ ccprintf(ss, "(%#x)", errorCode);
+ }
- void X86Interrupt::invoke(ThreadContext * tc)
- {
- panic("X86 faults are not implemented!");
+ return ss.str();
}
-
- void FakeITLBFault::invoke(ThreadContext * tc)
+
+ void X86Trap::invoke(ThreadContext * tc)
{
- // Start the page table walker.
- tc->getITBPtr()->walk(tc, vaddr);
+ X86FaultBase::invoke(tc);
+ // This is the same as a fault, but it happens -after- the instruction.
+ tc->setPC(tc->readNextPC());
+ tc->setNextPC(tc->readNextNPC());
+ tc->setNextNPC(tc->readNextNPC() + sizeof(MachInst));
}
- void FakeDTLBFault::invoke(ThreadContext * tc)
+ void X86Abort::invoke(ThreadContext * tc)
{
- // Start the page table walker.
- tc->getDTBPtr()->walk(tc, vaddr);
+ panic("Abort exception!");
}
-#else // !FULL_SYSTEM
- void FakeITLBFault::invoke(ThreadContext * tc)
+ void PageFault::invoke(ThreadContext * tc)
{
- DPRINTF(TLB, "Invoking an ITLB fault for address %#x at pc %#x.\n",
- vaddr, tc->readPC());
- Process *p = tc->getProcessPtr();
- TlbEntry entry;
- bool success = p->pTable->lookup(vaddr, entry);
- if(!success) {
- panic("Tried to execute unmapped address %#x.\n", vaddr);
+ HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ X86FaultBase::invoke(tc);
+ /*
+ * If something bad happens while trying to enter the page fault
+ * handler, I'm pretty sure that's a double fault and then all bets are
+ * off. That means it should be safe to update this state now.
+ */
+ if (m5reg.mode == LongMode) {
+ tc->setMiscReg(MISCREG_CR2, addr);
} else {
- Addr alignedVaddr = p->pTable->pageAlign(vaddr);
- DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr,
- entry.pageStart());
- tc->getITBPtr()->insert(alignedVaddr, entry);
+ tc->setMiscReg(MISCREG_CR2, (uint32_t)addr);
}
}
- void FakeDTLBFault::invoke(ThreadContext * tc)
+ std::string
+ PageFault::describe() const
{
- DPRINTF(TLB, "Invoking an DTLB fault for address %#x at pc %#x.\n",
- vaddr, tc->readPC());
- Process *p = tc->getProcessPtr();
- TlbEntry entry;
- bool success = p->pTable->lookup(vaddr, entry);
- if(!success) {
- p->checkAndAllocNextPage(vaddr);
- success = p->pTable->lookup(vaddr, entry);
- }
- if(!success) {
- panic("Tried to access unmapped address %#x.\n", vaddr);
- } else {
- Addr alignedVaddr = p->pTable->pageAlign(vaddr);
- DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr,
- entry.pageStart());
- tc->getDTBPtr()->insert(alignedVaddr, entry);
- }
+ std::stringstream ss;
+ ccprintf(ss, "%s at %#x", X86FaultBase::describe(), addr);
+ return ss.str();
}
+
#endif
} // namespace X86ISA
diff --git a/src/arch/x86/faults.hh b/src/arch/x86/faults.hh
index 78a55d0e1..fe5132994 100644
--- a/src/arch/x86/faults.hh
+++ b/src/arch/x86/faults.hh
@@ -58,9 +58,12 @@
#ifndef __ARCH_X86_FAULTS_HH__
#define __ARCH_X86_FAULTS_HH__
+#include "base/bitunion.hh"
#include "base/misc.hh"
#include "sim/faults.hh"
+#include <string>
+
namespace X86ISA
{
// Base class for all x86 "faults" where faults is in the m5 sense
@@ -69,11 +72,13 @@ namespace X86ISA
protected:
const char * faultName;
const char * mnem;
+ uint8_t vector;
uint64_t errorCode;
X86FaultBase(const char * _faultName, const char * _mnem,
- uint64_t _errorCode = 0) :
- faultName(_faultName), mnem(_mnem), errorCode(_errorCode)
+ const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1)
+ : faultName(_faultName), mnem(_mnem),
+ vector(_vector), errorCode(_errorCode)
{
}
@@ -91,6 +96,17 @@ namespace X86ISA
{
return mnem;
}
+
+ virtual bool isSoft()
+ {
+ return false;
+ }
+
+#if FULL_SYSTEM
+ void invoke(ThreadContext * tc);
+
+ virtual std::string describe() const;
+#endif
};
// Base class for x86 faults which behave as if the underlying instruction
@@ -99,8 +115,8 @@ namespace X86ISA
{
protected:
X86Fault(const char * name, const char * mnem,
- uint64_t _errorCode = 0) :
- X86FaultBase(name, mnem, _errorCode)
+ const uint8_t vector, uint64_t _errorCode = (uint64_t)-1)
+ : X86FaultBase(name, mnem, vector, _errorCode)
{}
};
@@ -110,8 +126,8 @@ namespace X86ISA
{
protected:
X86Trap(const char * name, const char * mnem,
- uint64_t _errorCode = 0) :
- X86FaultBase(name, mnem, _errorCode)
+ const uint8_t vector, uint64_t _errorCode = (uint64_t)-1)
+ : X86FaultBase(name, mnem, vector, _errorCode)
{}
#if FULL_SYSTEM
@@ -124,8 +140,8 @@ namespace X86ISA
{
protected:
X86Abort(const char * name, const char * mnem,
- uint64_t _errorCode = 0) :
- X86FaultBase(name, mnem, _errorCode)
+ const uint8_t vector, uint64_t _errorCode = (uint64_t)-1)
+ : X86FaultBase(name, mnem, vector, _errorCode)
{}
#if FULL_SYSTEM
@@ -138,13 +154,9 @@ namespace X86ISA
{
protected:
X86Interrupt(const char * name, const char * mnem,
- uint64_t _errorCode = 0) :
- X86FaultBase(name, mnem, _errorCode)
+ const uint8_t _vector, uint64_t _errorCode = (uint64_t)-1)
+ : X86FaultBase(name, mnem, _vector, _errorCode)
{}
-
-#if FULL_SYSTEM
- void invoke(ThreadContext * tc);
-#endif
};
class UnimpInstFault : public FaultBase
@@ -201,7 +213,7 @@ namespace X86ISA
{
public:
DivideByZero() :
- X86Fault("Divide-by-Zero-Error", "#DE")
+ X86Fault("Divide-by-Zero-Error", "#DE", 0)
{}
};
@@ -209,15 +221,15 @@ namespace X86ISA
{
public:
DebugException() :
- X86FaultBase("Debug", "#DB")
+ X86FaultBase("Debug", "#DB", 1)
{}
};
class NonMaskableInterrupt : public X86Interrupt
{
public:
- NonMaskableInterrupt() :
- X86Interrupt("Non-Maskable-Interrupt", "#NMI")
+ NonMaskableInterrupt(uint8_t _vector) :
+ X86Interrupt("Non Maskable Interrupt", "#NMI", 2, _vector)
{}
};
@@ -225,7 +237,7 @@ namespace X86ISA
{
public:
Breakpoint() :
- X86Trap("Breakpoint", "#BP")
+ X86Trap("Breakpoint", "#BP", 3)
{}
};
@@ -233,7 +245,7 @@ namespace X86ISA
{
public:
OverflowTrap() :
- X86Trap("Overflow", "#OF")
+ X86Trap("Overflow", "#OF", 4)
{}
};
@@ -241,7 +253,7 @@ namespace X86ISA
{
public:
BoundRange() :
- X86Fault("Bound-Range", "#BR")
+ X86Fault("Bound-Range", "#BR", 5)
{}
};
@@ -249,7 +261,7 @@ namespace X86ISA
{
public:
InvalidOpcode() :
- X86Fault("Invalid-Opcode", "#UD")
+ X86Fault("Invalid-Opcode", "#UD", 6)
{}
};
@@ -257,7 +269,7 @@ namespace X86ISA
{
public:
DeviceNotAvailable() :
- X86Fault("Device-Not-Available", "#NM")
+ X86Fault("Device-Not-Available", "#NM", 7)
{}
};
@@ -265,132 +277,156 @@ namespace X86ISA
{
public:
DoubleFault() :
- X86Abort("Double-Fault", "#DF")
+ X86Abort("Double-Fault", "#DF", 8, 0)
{}
};
class InvalidTSS : public X86Fault
{
public:
- InvalidTSS() :
- X86Fault("Invalid-TSS", "#TS")
+ InvalidTSS(uint32_t _errorCode) :
+ X86Fault("Invalid-TSS", "#TS", 10, _errorCode)
{}
};
class SegmentNotPresent : public X86Fault
{
public:
- SegmentNotPresent() :
- X86Fault("Segment-Not-Present", "#NP")
+ SegmentNotPresent(uint32_t _errorCode) :
+ X86Fault("Segment-Not-Present", "#NP", 11, _errorCode)
{}
};
class StackFault : public X86Fault
{
public:
- StackFault() :
- X86Fault("Stack", "#SS")
+ StackFault(uint32_t _errorCode) :
+ X86Fault("Stack", "#SS", 12, _errorCode)
{}
};
class GeneralProtection : public X86Fault
{
public:
- GeneralProtection(uint64_t _errorCode) :
- X86Fault("General-Protection", "#GP", _errorCode)
+ GeneralProtection(uint32_t _errorCode) :
+ X86Fault("General-Protection", "#GP", 13, _errorCode)
{}
};
class PageFault : public X86Fault
{
+ protected:
+ BitUnion32(PageFaultErrorCode)
+ Bitfield<0> present;
+ Bitfield<1> write;
+ Bitfield<2> user;
+ Bitfield<3> reserved;
+ Bitfield<4> fetch;
+ EndBitUnion(PageFaultErrorCode)
+
+ Addr addr;
+
public:
- PageFault() :
- X86Fault("Page-Fault", "#PF")
+ PageFault(Addr _addr, uint32_t _errorCode) :
+ X86Fault("Page-Fault", "#PF", 14, _errorCode), addr(_addr)
{}
+
+ PageFault(Addr _addr, bool present, bool write,
+ bool user, bool reserved, bool fetch) :
+ X86Fault("Page-Fault", "#PF", 14, 0), addr(_addr)
+ {
+ PageFaultErrorCode code = 0;
+ code.present = present;
+ code.write = write;
+ code.user = user;
+ code.reserved = reserved;
+ code.fetch = fetch;
+ errorCode = code;
+ }
+
+#if FULL_SYSTEM
+ void invoke(ThreadContext * tc);
+
+ virtual std::string describe() const;
+#endif
};
class X87FpExceptionPending : public X86Fault
{
public:
X87FpExceptionPending() :
- X86Fault("x87 Floating-Point Exception Pending", "#MF")
+ X86Fault("x87 Floating-Point Exception Pending", "#MF", 16)
{}
};
- class AlignmentCheck : X86Fault
+ class AlignmentCheck : public X86Fault
{
public:
AlignmentCheck() :
- X86Fault("Alignment-Check", "#AC")
+ X86Fault("Alignment-Check", "#AC", 17, 0)
{}
};
- class MachineCheck : X86Abort
+ class MachineCheck : public X86Abort
{
public:
MachineCheck() :
- X86Abort("Machine-Check", "#MC")
+ X86Abort("Machine-Check", "#MC", 18)
{}
};
- class SIMDFloatingPointFault : X86Fault
+ class SIMDFloatingPointFault : public X86Fault
{
public:
SIMDFloatingPointFault() :
- X86Fault("SIMD Floating-Point", "#XF")
+ X86Fault("SIMD Floating-Point", "#XF", 19)
{}
};
- class SecurityException : X86FaultBase
+ class SecurityException : public X86FaultBase
{
public:
SecurityException() :
- X86FaultBase("Security Exception", "#SX")
+ X86FaultBase("Security Exception", "#SX", 30)
{}
};
- class ExternalInterrupt : X86Interrupt
+ class ExternalInterrupt : public X86Interrupt
{
public:
- ExternalInterrupt() :
- X86Interrupt("External Interrupt", "#INTR")
+ ExternalInterrupt(uint8_t _vector) :
+ X86Interrupt("External Interrupt", "#INTR", _vector)
{}
};
- class SoftwareInterrupt : X86Interrupt
+ class SystemManagementInterrupt : public X86Interrupt
{
public:
- SoftwareInterrupt() :
- X86Interrupt("Software Interrupt", "INTn")
+ SystemManagementInterrupt() :
+ X86Interrupt("System Management Interrupt", "#SMI", 0)
{}
};
- // These faults aren't part of the ISA definition. They trigger filling
- // the tlb on a miss and are to take the place of a hardware table walker.
- class FakeITLBFault : public X86Fault
+ class InitInterrupt : public X86Interrupt
{
- protected:
- Addr vaddr;
+ uint8_t vector;
public:
- FakeITLBFault(Addr _vaddr) :
- X86Fault("fake instruction tlb fault", "itlb"),
- vaddr(_vaddr)
+ InitInterrupt(uint8_t _vector) :
+ X86Interrupt("INIT Interrupt", "#INIT", _vector)
{}
-
- void invoke(ThreadContext * tc);
};
- class FakeDTLBFault : public X86Fault
+ class SoftwareInterrupt : public X86Interrupt
{
- protected:
- Addr vaddr;
public:
- FakeDTLBFault(Addr _vaddr) :
- X86Fault("fake data tlb fault", "dtlb"),
- vaddr(_vaddr)
+ SoftwareInterrupt(uint8_t _vector) :
+ X86Interrupt("Software Interrupt", "#INTR", _vector)
{}
- void invoke(ThreadContext * tc);
+ bool isSoft()
+ {
+ return true;
+ }
};
};
diff --git a/src/arch/x86/floatregfile.cc b/src/arch/x86/floatregfile.cc
index 1c49ea9c6..fce7f4868 100644
--- a/src/arch/x86/floatregfile.cc
+++ b/src/arch/x86/floatregfile.cc
@@ -96,15 +96,6 @@ using namespace std;
class Checkpoint;
-string X86ISA::getFloatRegName(RegIndex index)
-{
- static std::string floatRegName[NumFloatRegs] =
- {"mmx0", "mmx1", "mmx2", "mmx3", "mmx4", "mmx5", "mmx6", "mmx7",
- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
- "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"};
- return floatRegName[index];
-}
-
void FloatRegFile::clear()
{
memset(q, 0, sizeof(FloatReg) * NumFloatRegs);
@@ -113,27 +104,27 @@ void FloatRegFile::clear()
FloatReg FloatRegFile::readReg(int floatReg, int width)
{
FloatReg reg = d[floatReg];
- DPRINTF(X86, "Reading %f from register %d.\n", reg, floatReg);
+ DPRINTF(FloatRegs, "Reading %f from register %d.\n", reg, floatReg);
return reg;
}
FloatRegBits FloatRegFile::readRegBits(int floatReg, int width)
{
FloatRegBits reg = q[floatReg];
- DPRINTF(X86, "Reading %#x from register %d.\n", reg, floatReg);
+ DPRINTF(FloatRegs, "Reading %#x from register %d.\n", reg, floatReg);
return reg;
}
Fault FloatRegFile::setReg(int floatReg, const FloatReg &val, int width)
{
- DPRINTF(X86, "Writing %f to register %d.\n", val, floatReg);
+ DPRINTF(FloatRegs, "Writing %f to register %d.\n", val, floatReg);
d[floatReg] = val;
return NoFault;
}
Fault FloatRegFile::setRegBits(int floatReg, const FloatRegBits &val, int width)
{
- DPRINTF(X86, "Writing bits %#x to register %d.\n", val, floatReg);
+ DPRINTF(FloatRegs, "Writing bits %#x to register %d.\n", val, floatReg);
q[floatReg] = val;
return NoFault;
}
diff --git a/src/arch/x86/floatregfile.hh b/src/arch/x86/floatregfile.hh
index b77ddb0eb..ab239dd7d 100644
--- a/src/arch/x86/floatregfile.hh
+++ b/src/arch/x86/floatregfile.hh
@@ -98,8 +98,6 @@ class Checkpoint;
namespace X86ISA
{
- std::string getFloatRegName(RegIndex);
-
//Each 128 bit xmm register is broken into two effective 64 bit registers.
const int NumFloatRegs =
NumMMXRegs + 2 * NumXMMRegs + NumMicroFpRegs;
diff --git a/src/arch/x86/insts/macroop.hh b/src/arch/x86/insts/macroop.hh
new file mode 100644
index 000000000..d6925a1a5
--- /dev/null
+++ b/src/arch/x86/insts/macroop.hh
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_INSTS_MACROOP_HH__
+#define __ARCH_X86_INSTS_MACROOP_HH__
+
+#include "arch/x86/emulenv.hh"
+#include "arch/x86/types.hh"
+#include "arch/x86/insts/static_inst.hh"
+
+namespace X86ISA
+{
+// Base class for combinationally generated macroops
+class MacroopBase : public X86StaticInst
+{
+ protected:
+ const char *macrocodeBlock;
+
+ const uint32_t numMicroops;
+ X86ISA::EmulEnv env;
+
+ //Constructor.
+ MacroopBase(const char *mnem, ExtMachInst _machInst,
+ uint32_t _numMicroops, X86ISA::EmulEnv _env) :
+ X86StaticInst(mnem, _machInst, No_OpClass),
+ numMicroops(_numMicroops), env(_env)
+ {
+ assert(numMicroops);
+ microops = new StaticInstPtr[numMicroops];
+ flags[IsMacroop] = true;
+ }
+
+ ~MacroopBase()
+ {
+ delete [] microops;
+ }
+
+ StaticInstPtr * microops;
+
+ StaticInstPtr fetchMicroop(MicroPC microPC)
+ {
+ assert(microPC < numMicroops);
+ return microops[microPC];
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return mnemonic;
+ }
+
+ public:
+ ExtMachInst
+ getExtMachInst()
+ {
+ return machInst;
+ }
+
+ X86ISA::EmulEnv
+ getEmulEnv()
+ {
+ return env;
+ }
+};
+}
+
+#endif //__ARCH_X86_INSTS_MACROOP_HH__
diff --git a/src/arch/x86/insts/microldstop.cc b/src/arch/x86/insts/microldstop.cc
index 9638a2ae3..7cc6a330f 100644
--- a/src/arch/x86/insts/microldstop.cc
+++ b/src/arch/x86/insts/microldstop.cc
@@ -64,7 +64,6 @@ namespace X86ISA
const SymbolTable *symtab) const
{
std::stringstream response;
- bool someAddr = false;
printMnemonic(response, instMnem, mnemonic);
if(flags[IsLoad])
@@ -72,32 +71,8 @@ namespace X86ISA
else
printSrcReg(response, 2, dataSize);
response << ", ";
- printSegment(response, segment);
- response << ":[";
- if(scale != 0 && _srcRegIdx[0] != ZeroReg)
- {
- if(scale != 1)
- ccprintf(response, "%d*", scale);
- printSrcReg(response, 0, addressSize);
- someAddr = true;
- }
- if(_srcRegIdx[1] != ZeroReg)
- {
- if(someAddr)
- response << " + ";
- printSrcReg(response, 1, addressSize);
- someAddr = true;
- }
- if(disp != 0)
- {
- if(someAddr)
- response << " + ";
- ccprintf(response, "%#x", disp);
- someAddr = true;
- }
- if(!someAddr)
- response << "0";
- response << "]";
+ printMem(response, segment, scale, index, base, disp,
+ addressSize, false);
return response.str();
}
}
diff --git a/src/arch/x86/insts/microldstop.hh b/src/arch/x86/insts/microldstop.hh
index 5b1210d69..1774454c3 100644
--- a/src/arch/x86/insts/microldstop.hh
+++ b/src/arch/x86/insts/microldstop.hh
@@ -59,9 +59,18 @@
#define __ARCH_X86_INSTS_MICROLDSTOP_HH__
#include "arch/x86/insts/microop.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
namespace X86ISA
{
+ static const Request::FlagsType SegmentFlagMask = mask(4);
+ static const int FlagShift = 4;
+ enum FlagBit {
+ CPL0FlagBit = 1,
+ AddrSizeFlagBit = 2
+ };
+
/**
* Base class for load and store ops
*/
@@ -76,6 +85,7 @@ namespace X86ISA
const RegIndex data;
const uint8_t dataSize;
const uint8_t addressSize;
+ const Request::FlagsType memFlags;
RegIndex foldOBit, foldABit;
//Constructor
@@ -86,13 +96,15 @@ namespace X86ISA
uint64_t _disp, uint8_t _segment,
RegIndex _data,
uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags,
OpClass __opClass) :
X86MicroopBase(machInst, mnem, _instMnem,
isMicro, isDelayed, isFirst, isLast, __opClass),
scale(_scale), index(_index), base(_base),
disp(_disp), segment(_segment),
data(_data),
- dataSize(_dataSize), addressSize(_addressSize)
+ dataSize(_dataSize), addressSize(_addressSize),
+ memFlags(_memFlags | _segment)
{
foldOBit = (dataSize == 1 && !_machInst.rex.present) ? 1 << 6 : 0;
foldABit =
@@ -149,6 +161,25 @@ namespace X86ISA
}
return fault;
}
+
+ uint64_t
+ get(PacketPtr pkt) const
+ {
+ switch(dataSize)
+ {
+ case 1:
+ return pkt->get<uint8_t>();
+ case 2:
+ return pkt->get<uint16_t>();
+ case 4:
+ return pkt->get<uint32_t>();
+ case 8:
+ return pkt->get<uint64_t>();
+ default:
+ panic("Bad operand size %d for read at %#x.\n",
+ dataSize, pkt->getAddr());
+ }
+ }
};
}
diff --git a/src/arch/x86/insts/microop.cc b/src/arch/x86/insts/microop.cc
index 494c0b303..c7bfc3703 100644
--- a/src/arch/x86/insts/microop.cc
+++ b/src/arch/x86/insts/microop.cc
@@ -98,7 +98,7 @@ namespace X86ISA
case ConditionTests::SxOF:
return ccflags.sf ^ ccflags.of;
case ConditionTests::SxOvZF:
- return ccflags.sf ^ ccflags.of | ccflags.zf;
+ return (ccflags.sf ^ ccflags.of) | ccflags.zf;
case ConditionTests::False:
return false;
case ConditionTests::NotECF:
@@ -131,7 +131,7 @@ namespace X86ISA
case ConditionTests::NotSxOF:
return !(ccflags.sf ^ ccflags.of);
case ConditionTests::NotSxOvZF:
- return !(ccflags.sf ^ ccflags.of | ccflags.zf);
+ return !((ccflags.sf ^ ccflags.of) | ccflags.zf);
}
panic("Unknown condition: %d\n", condition);
return true;
diff --git a/src/arch/x86/insts/microregop.cc b/src/arch/x86/insts/microregop.cc
index 080926627..2ea975746 100644
--- a/src/arch/x86/insts/microregop.cc
+++ b/src/arch/x86/insts/microregop.cc
@@ -67,6 +67,9 @@ namespace X86ISA
bool subtract) const
{
DPRINTF(X86, "flagMask = %#x\n", flagMask);
+ if (_destRegIdx[0] & (1 << 6)) {
+ _dest >>= 8;
+ }
uint64_t flags = oldFlags & ~flagMask;
if(flagMask & (ECFBit | CFBit))
{
diff --git a/src/arch/x86/insts/static_inst.cc b/src/arch/x86/insts/static_inst.cc
index 0c1508d5a..f4ed44603 100644
--- a/src/arch/x86/insts/static_inst.cc
+++ b/src/arch/x86/insts/static_inst.cc
@@ -63,13 +63,13 @@ namespace X86ISA
void X86StaticInst::printMnemonic(std::ostream &os,
const char * mnemonic) const
{
- ccprintf(os, "\t%s ", mnemonic);
+ ccprintf(os, " %s ", mnemonic);
}
void X86StaticInst::printMnemonic(std::ostream &os,
const char * instMnemonic, const char * mnemonic) const
{
- ccprintf(os, "\t%s : %s ", instMnemonic, mnemonic);
+ ccprintf(os, " %s : %s ", instMnemonic, mnemonic);
}
void X86StaticInst::printSegment(std::ostream &os, int segment) const
@@ -240,6 +240,44 @@ namespace X86ISA
}
}
+ void X86StaticInst::printMem(std::ostream &os, uint8_t segment,
+ uint8_t scale, RegIndex index, RegIndex base,
+ uint64_t disp, uint8_t addressSize, bool rip) const
+ {
+ bool someAddr = false;
+ printSegment(os, segment);
+ os << ":[";
+ if (rip) {
+ os << "rip";
+ someAddr = true;
+ } else {
+ if (scale != 0 && index != ZeroReg)
+ {
+ if(scale != 1)
+ ccprintf(os, "%d*", scale);
+ printReg(os, index, addressSize);
+ someAddr = true;
+ }
+ if (base != ZeroReg)
+ {
+ if(someAddr)
+ os << " + ";
+ printReg(os, base, addressSize);
+ someAddr = true;
+ }
+ }
+ if (disp != 0)
+ {
+ if(someAddr)
+ os << " + ";
+ ccprintf(os, "%#x", disp);
+ someAddr = true;
+ }
+ if (!someAddr)
+ os << "0";
+ os << "]";
+ }
+
std::string X86StaticInst::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
diff --git a/src/arch/x86/insts/static_inst.hh b/src/arch/x86/insts/static_inst.hh
index e5c333e75..8480f2713 100644
--- a/src/arch/x86/insts/static_inst.hh
+++ b/src/arch/x86/insts/static_inst.hh
@@ -89,6 +89,9 @@ namespace X86ISA
void printReg(std::ostream &os, int reg, int size) const;
void printSrcReg(std::ostream &os, int reg, int size) const;
void printDestReg(std::ostream &os, int reg, int size) const;
+ void printMem(std::ostream &os, uint8_t segment,
+ uint8_t scale, RegIndex index, RegIndex base,
+ uint64_t disp, uint8_t addressSize, bool rip) const;
inline uint64_t merge(uint64_t into, uint64_t val, int size) const
{
diff --git a/src/arch/x86/interrupts.cc b/src/arch/x86/interrupts.cc
new file mode 100644
index 000000000..30c532c2b
--- /dev/null
+++ b/src/arch/x86/interrupts.cc
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use of this software in source and binary forms,
+ * with or without modification, are permitted provided that the
+ * following conditions are met:
+ *
+ * The software must be used only for Non-Commercial Use which means any
+ * use which is NOT directed to receiving any direct monetary
+ * compensation for, or commercial advantage from such use. Illustrative
+ * examples of non-commercial use are academic research, personal study,
+ * teaching, education and corporate research & development.
+ * Illustrative examples of commercial use are distributing products for
+ * commercial advantage and providing services using the software for
+ * commercial advantage.
+ *
+ * If you wish to use this software or functionality therein that may be
+ * covered by patents for commercial use, please contact:
+ * Director of Intellectual Property Licensing
+ * Office of Strategy and Technology
+ * Hewlett-Packard Company
+ * 1501 Page Mill Road
+ * Palo Alto, California 94304
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer. Redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution. Neither the name of
+ * the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission. No right of
+ * sublicense is granted herewith. Derivatives of the software and
+ * output created using the software may be prepared, but only for
+ * Non-Commercial Uses. Derivatives of the software may be shared with
+ * others provided: (i) the others agree to abide by the list of
+ * conditions herein which includes the Non-Commercial Use restrictions;
+ * and (ii) such Derivatives of the software include the above copyright
+ * notice to acknowledge the contribution from this software where
+ * applicable, this list of conditions and the disclaimer below.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/apicregs.hh"
+#include "arch/x86/interrupts.hh"
+#include "arch/x86/intmessage.hh"
+#include "cpu/base.hh"
+#include "mem/packet_access.hh"
+
+int
+divideFromConf(uint32_t conf)
+{
+ // This figures out what division we want from the division configuration
+ // register in the local APIC. The encoding is a little odd but it can
+ // be deciphered fairly easily.
+ int shift = ((conf & 0x8) >> 1) | (conf & 0x3);
+ shift = (shift + 1) % 8;
+ return 1 << shift;
+}
+
+namespace X86ISA
+{
+
+ApicRegIndex
+decodeAddr(Addr paddr)
+{
+ ApicRegIndex regNum;
+ paddr &= ~mask(3);
+ switch (paddr)
+ {
+ case 0x20:
+ regNum = APIC_ID;
+ break;
+ case 0x30:
+ regNum = APIC_VERSION;
+ break;
+ case 0x80:
+ regNum = APIC_TASK_PRIORITY;
+ break;
+ case 0x90:
+ regNum = APIC_ARBITRATION_PRIORITY;
+ break;
+ case 0xA0:
+ regNum = APIC_PROCESSOR_PRIORITY;
+ break;
+ case 0xB0:
+ regNum = APIC_EOI;
+ break;
+ case 0xD0:
+ regNum = APIC_LOGICAL_DESTINATION;
+ break;
+ case 0xE0:
+ regNum = APIC_DESTINATION_FORMAT;
+ break;
+ case 0xF0:
+ regNum = APIC_SPURIOUS_INTERRUPT_VECTOR;
+ break;
+ case 0x100:
+ case 0x108:
+ case 0x110:
+ case 0x118:
+ case 0x120:
+ case 0x128:
+ case 0x130:
+ case 0x138:
+ case 0x140:
+ case 0x148:
+ case 0x150:
+ case 0x158:
+ case 0x160:
+ case 0x168:
+ case 0x170:
+ case 0x178:
+ regNum = APIC_IN_SERVICE((paddr - 0x100) / 0x8);
+ break;
+ case 0x180:
+ case 0x188:
+ case 0x190:
+ case 0x198:
+ case 0x1A0:
+ case 0x1A8:
+ case 0x1B0:
+ case 0x1B8:
+ case 0x1C0:
+ case 0x1C8:
+ case 0x1D0:
+ case 0x1D8:
+ case 0x1E0:
+ case 0x1E8:
+ case 0x1F0:
+ case 0x1F8:
+ regNum = APIC_TRIGGER_MODE((paddr - 0x180) / 0x8);
+ break;
+ case 0x200:
+ case 0x208:
+ case 0x210:
+ case 0x218:
+ case 0x220:
+ case 0x228:
+ case 0x230:
+ case 0x238:
+ case 0x240:
+ case 0x248:
+ case 0x250:
+ case 0x258:
+ case 0x260:
+ case 0x268:
+ case 0x270:
+ case 0x278:
+ regNum = APIC_INTERRUPT_REQUEST((paddr - 0x200) / 0x8);
+ break;
+ case 0x280:
+ regNum = APIC_ERROR_STATUS;
+ break;
+ case 0x300:
+ regNum = APIC_INTERRUPT_COMMAND_LOW;
+ break;
+ case 0x310:
+ regNum = APIC_INTERRUPT_COMMAND_HIGH;
+ break;
+ case 0x320:
+ regNum = APIC_LVT_TIMER;
+ break;
+ case 0x330:
+ regNum = APIC_LVT_THERMAL_SENSOR;
+ break;
+ case 0x340:
+ regNum = APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
+ break;
+ case 0x350:
+ regNum = APIC_LVT_LINT0;
+ break;
+ case 0x360:
+ regNum = APIC_LVT_LINT1;
+ break;
+ case 0x370:
+ regNum = APIC_LVT_ERROR;
+ break;
+ case 0x380:
+ regNum = APIC_INITIAL_COUNT;
+ break;
+ case 0x390:
+ regNum = APIC_CURRENT_COUNT;
+ break;
+ case 0x3E0:
+ regNum = APIC_DIVIDE_CONFIGURATION;
+ break;
+ default:
+ // A reserved register field.
+ panic("Accessed reserved register field %#x.\n", paddr);
+ break;
+ }
+ return regNum;
+}
+}
+
+Tick
+X86ISA::Interrupts::read(PacketPtr pkt)
+{
+ Addr offset = pkt->getAddr() - pioAddr;
+ //Make sure we're at least only accessing one register.
+ if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
+ panic("Accessed more than one register at a time in the APIC!\n");
+ ApicRegIndex reg = decodeAddr(offset);
+ uint32_t val = htog(readReg(reg));
+ DPRINTF(LocalApic,
+ "Reading Local APIC register %d at offset %#x as %#x.\n",
+ reg, offset, val);
+ pkt->setData(((uint8_t *)&val) + (offset & mask(3)));
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::Interrupts::write(PacketPtr pkt)
+{
+ Addr offset = pkt->getAddr() - pioAddr;
+ //Make sure we're at least only accessing one register.
+ if ((offset & ~mask(3)) != ((offset + pkt->getSize()) & ~mask(3)))
+ panic("Accessed more than one register at a time in the APIC!\n");
+ ApicRegIndex reg = decodeAddr(offset);
+ uint32_t val = regs[reg];
+ pkt->writeData(((uint8_t *)&val) + (offset & mask(3)));
+ DPRINTF(LocalApic,
+ "Writing Local APIC register %d at offset %#x as %#x.\n",
+ reg, offset, gtoh(val));
+ setReg(reg, gtoh(val));
+ pkt->makeAtomicResponse();
+ return latency;
+}
+void
+X86ISA::Interrupts::requestInterrupt(uint8_t vector,
+ uint8_t deliveryMode, bool level)
+{
+ /*
+ * Fixed and lowest-priority delivery mode interrupts are handled
+ * using the IRR/ISR registers, checking against the TPR, etc.
+ * The SMI, NMI, ExtInt, INIT, etc interrupts go straight through.
+ */
+ if (deliveryMode == DeliveryMode::Fixed ||
+ deliveryMode == DeliveryMode::LowestPriority) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
+ DeliveryMode::names[deliveryMode]);
+ // Queue up the interrupt in the IRR.
+ if (vector > IRRV)
+ IRRV = vector;
+ if (!getRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector)) {
+ setRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, vector);
+ if (level) {
+ setRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ } else {
+ clearRegArrayBit(APIC_TRIGGER_MODE_BASE, vector);
+ }
+ }
+ } else if (!DeliveryMode::isReserved(deliveryMode)) {
+ DPRINTF(LocalApic, "Interrupt is an %s.\n",
+ DeliveryMode::names[deliveryMode]);
+ if (deliveryMode == DeliveryMode::SMI && !pendingSmi) {
+ pendingUnmaskableInt = pendingSmi = true;
+ smiVector = vector;
+ } else if (deliveryMode == DeliveryMode::NMI && !pendingNmi) {
+ pendingUnmaskableInt = pendingNmi = true;
+ nmiVector = vector;
+ } else if (deliveryMode == DeliveryMode::ExtInt && !pendingExtInt) {
+ pendingExtInt = true;
+ extIntVector = vector;
+ } else if (deliveryMode == DeliveryMode::INIT && !pendingInit) {
+ pendingUnmaskableInt = pendingInit = true;
+ initVector = vector;
+ }
+ }
+ cpu->wakeup();
+}
+
+Tick
+X86ISA::Interrupts::recvMessage(PacketPtr pkt)
+{
+ uint8_t id = 0;
+ Addr offset = pkt->getAddr() - x86InterruptAddress(id, 0);
+ assert(pkt->cmd == MemCmd::MessageReq);
+ switch(offset)
+ {
+ case 0:
+ {
+ TriggerIntMessage message = pkt->get<TriggerIntMessage>();
+ DPRINTF(LocalApic,
+ "Got Trigger Interrupt message with vector %#x.\n",
+ message.vector);
+ // Make sure we're really supposed to get this.
+ assert((message.destMode == 0 && message.destination == id) ||
+ (bits((int)message.destination, id)));
+
+ requestInterrupt(message.vector,
+ message.deliveryMode, message.trigger);
+ }
+ break;
+ default:
+ panic("Local apic got unknown interrupt message at offset %#x.\n",
+ offset);
+ break;
+ }
+ delete pkt->req;
+ delete pkt;
+ return latency;
+}
+
+
+uint32_t
+X86ISA::Interrupts::readReg(ApicRegIndex reg)
+{
+ if (reg >= APIC_TRIGGER_MODE(0) &&
+ reg <= APIC_TRIGGER_MODE(15)) {
+ panic("Local APIC Trigger Mode registers are unimplemented.\n");
+ }
+ switch (reg) {
+ case APIC_ARBITRATION_PRIORITY:
+ panic("Local APIC Arbitration Priority register unimplemented.\n");
+ break;
+ case APIC_PROCESSOR_PRIORITY:
+ panic("Local APIC Processor Priority register unimplemented.\n");
+ break;
+ case APIC_ERROR_STATUS:
+ regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
+ break;
+ case APIC_INTERRUPT_COMMAND_LOW:
+ panic("Local APIC Interrupt Command low"
+ " register unimplemented.\n");
+ break;
+ case APIC_INTERRUPT_COMMAND_HIGH:
+ panic("Local APIC Interrupt Command high"
+ " register unimplemented.\n");
+ break;
+ case APIC_CURRENT_COUNT:
+ {
+ if (apicTimerEvent.scheduled()) {
+ assert(clock);
+ // Compute how many m5 ticks happen per count.
+ uint64_t ticksPerCount = clock *
+ divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]);
+ // Compute how many m5 ticks are left.
+ uint64_t val = apicTimerEvent.when() - curTick;
+ // Turn that into a count.
+ val = (val + ticksPerCount - 1) / ticksPerCount;
+ return val;
+ } else {
+ return 0;
+ }
+ }
+ default:
+ break;
+ }
+ return regs[reg];
+}
+
+void
+X86ISA::Interrupts::setReg(ApicRegIndex reg, uint32_t val)
+{
+ uint32_t newVal = val;
+ if (reg >= APIC_IN_SERVICE(0) &&
+ reg <= APIC_IN_SERVICE(15)) {
+ panic("Local APIC In-Service registers are unimplemented.\n");
+ }
+ if (reg >= APIC_TRIGGER_MODE(0) &&
+ reg <= APIC_TRIGGER_MODE(15)) {
+ panic("Local APIC Trigger Mode registers are unimplemented.\n");
+ }
+ if (reg >= APIC_INTERRUPT_REQUEST(0) &&
+ reg <= APIC_INTERRUPT_REQUEST(15)) {
+ panic("Local APIC Interrupt Request registers "
+ "are unimplemented.\n");
+ }
+ switch (reg) {
+ case APIC_ID:
+ newVal = val & 0xFF;
+ break;
+ case APIC_VERSION:
+ // The Local APIC Version register is read only.
+ return;
+ case APIC_TASK_PRIORITY:
+ newVal = val & 0xFF;
+ break;
+ case APIC_ARBITRATION_PRIORITY:
+ panic("Local APIC Arbitration Priority register unimplemented.\n");
+ break;
+ case APIC_PROCESSOR_PRIORITY:
+ panic("Local APIC Processor Priority register unimplemented.\n");
+ break;
+ case APIC_EOI:
+ // Remove the interrupt that just completed from the local apic state.
+ clearRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
+ updateISRV();
+ return;
+ case APIC_LOGICAL_DESTINATION:
+ newVal = val & 0xFF000000;
+ break;
+ case APIC_DESTINATION_FORMAT:
+ newVal = val | 0x0FFFFFFF;
+ break;
+ case APIC_SPURIOUS_INTERRUPT_VECTOR:
+ regs[APIC_INTERNAL_STATE] &= ~ULL(1 << 1);
+ regs[APIC_INTERNAL_STATE] |= val & (1 << 8);
+ if (val & (1 << 9))
+ warn("Focus processor checking not implemented.\n");
+ break;
+ case APIC_ERROR_STATUS:
+ {
+ if (regs[APIC_INTERNAL_STATE] & 0x1) {
+ regs[APIC_INTERNAL_STATE] &= ~ULL(0x1);
+ newVal = 0;
+ } else {
+ regs[APIC_INTERNAL_STATE] |= ULL(0x1);
+ return;
+ }
+
+ }
+ break;
+ case APIC_INTERRUPT_COMMAND_LOW:
+ panic("Local APIC Interrupt Command low"
+ " register unimplemented.\n");
+ break;
+ case APIC_INTERRUPT_COMMAND_HIGH:
+ panic("Local APIC Interrupt Command high"
+ " register unimplemented.\n");
+ break;
+ case APIC_LVT_TIMER:
+ case APIC_LVT_THERMAL_SENSOR:
+ case APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
+ case APIC_LVT_LINT0:
+ case APIC_LVT_LINT1:
+ case APIC_LVT_ERROR:
+ {
+ uint64_t readOnlyMask = (1 << 12) | (1 << 14);
+ newVal = (val & ~readOnlyMask) |
+ (regs[reg] & readOnlyMask);
+ }
+ break;
+ case APIC_INITIAL_COUNT:
+ {
+ assert(clock);
+ newVal = bits(val, 31, 0);
+ // Compute how many timer ticks we're being programmed for.
+ uint64_t newCount = newVal *
+ (divideFromConf(regs[APIC_DIVIDE_CONFIGURATION]));
+ // Schedule on the edge of the next tick plus the new count.
+ Tick offset = curTick % clock;
+ if (offset) {
+ reschedule(apicTimerEvent,
+ curTick + (newCount + 1) * clock - offset, true);
+ } else {
+ reschedule(apicTimerEvent,
+ curTick + newCount * clock, true);
+ }
+ }
+ break;
+ case APIC_CURRENT_COUNT:
+ //Local APIC Current Count register is read only.
+ return;
+ case APIC_DIVIDE_CONFIGURATION:
+ newVal = val & 0xB;
+ break;
+ default:
+ break;
+ }
+ regs[reg] = newVal;
+ return;
+}
+
+bool
+X86ISA::Interrupts::checkInterrupts(ThreadContext *tc) const
+{
+ RFLAGS rflags = tc->readMiscRegNoEffect(MISCREG_RFLAGS);
+ if (pendingUnmaskableInt) {
+ DPRINTF(LocalApic, "Reported pending unmaskable interrupt.\n");
+ return true;
+ }
+ if (rflags.intf) {
+ if (pendingExtInt) {
+ DPRINTF(LocalApic, "Reported pending external interrupt.\n");
+ return true;
+ }
+ if (IRRV > ISRV && bits(IRRV, 7, 4) >
+ bits(regs[APIC_TASK_PRIORITY], 7, 4)) {
+ DPRINTF(LocalApic, "Reported pending regular interrupt.\n");
+ return true;
+ }
+ }
+ return false;
+}
+
+Fault
+X86ISA::Interrupts::getInterrupt(ThreadContext *tc)
+{
+ assert(checkInterrupts(tc));
+ // These are all probably fairly uncommon, so we'll make them easier to
+ // check for.
+ if (pendingUnmaskableInt) {
+ if (pendingSmi) {
+ DPRINTF(LocalApic, "Generated SMI fault object.\n");
+ return new SystemManagementInterrupt();
+ } else if (pendingNmi) {
+ DPRINTF(LocalApic, "Generated NMI fault object.\n");
+ return new NonMaskableInterrupt(nmiVector);
+ } else if (pendingInit) {
+ DPRINTF(LocalApic, "Generated INIT fault object.\n");
+ return new InitInterrupt(initVector);
+ } else {
+ panic("pendingUnmaskableInt set, but no unmaskable "
+ "ints were pending.\n");
+ return NoFault;
+ }
+ } else if (pendingExtInt) {
+ DPRINTF(LocalApic, "Generated external interrupt fault object.\n");
+ return new ExternalInterrupt(extIntVector);
+ } else {
+ DPRINTF(LocalApic, "Generated regular interrupt fault object.\n");
+ // The only thing left are fixed and lowest priority interrupts.
+ return new ExternalInterrupt(IRRV);
+ }
+}
+
+void
+X86ISA::Interrupts::updateIntrInfo(ThreadContext *tc)
+{
+ assert(checkInterrupts(tc));
+ if (pendingUnmaskableInt) {
+ if (pendingSmi) {
+ DPRINTF(LocalApic, "SMI sent to core.\n");
+ pendingSmi = false;
+ } else if (pendingNmi) {
+ DPRINTF(LocalApic, "NMI sent to core.\n");
+ pendingNmi = false;
+ } else if (pendingInit) {
+ DPRINTF(LocalApic, "Init sent to core.\n");
+ pendingInit = false;
+ }
+ if (!(pendingSmi || pendingNmi || pendingInit))
+ pendingUnmaskableInt = false;
+ } else if (pendingExtInt) {
+ pendingExtInt = false;
+ } else {
+ DPRINTF(LocalApic, "Interrupt %d sent to core.\n", IRRV);
+ // Mark the interrupt as "in service".
+ ISRV = IRRV;
+ setRegArrayBit(APIC_IN_SERVICE_BASE, ISRV);
+ // Clear it out of the IRR.
+ clearRegArrayBit(APIC_INTERRUPT_REQUEST_BASE, IRRV);
+ updateIRRV();
+ }
+}
+
+X86ISA::Interrupts *
+X86LocalApicParams::create()
+{
+ return new X86ISA::Interrupts(this);
+}
diff --git a/src/arch/x86/interrupts.hh b/src/arch/x86/interrupts.hh
index cf9109e22..c5e3bde0d 100644
--- a/src/arch/x86/interrupts.hh
+++ b/src/arch/x86/interrupts.hh
@@ -58,73 +58,274 @@
#ifndef __ARCH_X86_INTERRUPTS_HH__
#define __ARCH_X86_INTERRUPTS_HH__
+#include "arch/x86/apicregs.hh"
#include "arch/x86/faults.hh"
+#include "arch/x86/intmessage.hh"
+#include "base/bitfield.hh"
#include "cpu/thread_context.hh"
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/X86LocalApic.hh"
+#include "sim/eventq.hh"
-namespace X86ISA
-{
+class ThreadContext;
+class BaseCPU;
+
+namespace X86ISA {
-class Interrupts
+class Interrupts : public BasicPioDevice, IntDev
{
+ protected:
+ // Storage for the APIC registers
+ uint32_t regs[NUM_APIC_REGS];
+
+ BitUnion32(LVTEntry)
+ Bitfield<7, 0> vector;
+ Bitfield<10, 8> deliveryMode;
+ Bitfield<12> status;
+ Bitfield<13> polarity;
+ Bitfield<14> remoteIRR;
+ Bitfield<15> trigger;
+ Bitfield<16> masked;
+ Bitfield<17> periodic;
+ EndBitUnion(LVTEntry)
+
+ /*
+ * Timing related stuff.
+ */
+ Tick latency;
+ Tick clock;
+
+ class ApicTimerEvent : public Event
+ {
+ private:
+ Interrupts *localApic;
+ public:
+ ApicTimerEvent(Interrupts *_localApic) :
+ Event(), localApic(_localApic)
+ {}
+
+ void process()
+ {
+ assert(localApic);
+ if (localApic->triggerTimerInterrupt()) {
+ localApic->setReg(APIC_INITIAL_COUNT,
+ localApic->readReg(APIC_INITIAL_COUNT));
+ }
+ }
+ };
+
+ ApicTimerEvent apicTimerEvent;
+
+ /*
+ * A set of variables to keep track of interrupts that don't go through
+ * the IRR.
+ */
+ bool pendingSmi;
+ uint8_t smiVector;
+ bool pendingNmi;
+ uint8_t nmiVector;
+ bool pendingExtInt;
+ uint8_t extIntVector;
+ bool pendingInit;
+ uint8_t initVector;
+
+ // This is a quick check whether any of the above (except ExtInt) are set.
+ bool pendingUnmaskableInt;
+
+ /*
+ * IRR and ISR maintenance.
+ */
+ uint8_t IRRV;
+ uint8_t ISRV;
+
+ int
+ findRegArrayMSB(ApicRegIndex base)
+ {
+ int offset = 7;
+ do {
+ if (regs[base + offset] != 0) {
+ return offset * 32 + findMsbSet(regs[base + offset]);
+ }
+ } while (offset--);
+ return 0;
+ }
+
+ void
+ updateIRRV()
+ {
+ IRRV = findRegArrayMSB(APIC_INTERRUPT_REQUEST_BASE);
+ }
+
+ void
+ updateISRV()
+ {
+ ISRV = findRegArrayMSB(APIC_IN_SERVICE_BASE);
+ }
+
+ void
+ setRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ regs[base + (vector % 32)] |= (1 << (vector >> 5));
+ }
+
+ void
+ clearRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ regs[base + (vector % 32)] &= ~(1 << (vector >> 5));
+ }
+
+ bool
+ getRegArrayBit(ApicRegIndex base, uint8_t vector)
+ {
+ return bits(regs[base + (vector % 32)], vector >> 5);
+ }
+
+ void requestInterrupt(uint8_t vector, uint8_t deliveryMode, bool level);
+
+ BaseCPU *cpu;
+
public:
- Interrupts()
+ /*
+ * Params stuff.
+ */
+ typedef X86LocalApicParams Params;
+
+ void
+ setCPU(BaseCPU * newCPU)
{
- clear_all();
+ cpu = newCPU;
}
- int InterruptLevel(uint64_t softint)
+ void
+ setClock(Tick newClock)
{
- panic("Interrupts::InterruptLevel unimplemented!\n");
- return 0;
+ clock = newClock;
}
- void post(int int_num, int index)
+ const Params *
+ params() const
{
- panic("Interrupts::post unimplemented!\n");
+ return dynamic_cast<const Params *>(_params);
}
- void clear(int int_num, int index)
+ /*
+ * Functions to interact with the interrupt port from IntDev.
+ */
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+ Tick recvMessage(PacketPtr pkt);
+
+ bool
+ triggerTimerInterrupt()
{
- warn("Interrupts::clear unimplemented!\n");
+ LVTEntry entry = regs[APIC_LVT_TIMER];
+ if (!entry.masked)
+ requestInterrupt(entry.vector, entry.deliveryMode, entry.trigger);
+ return entry.periodic;
}
- void clear_all()
+ void addressRanges(AddrRangeList &range_list)
{
- warn("Interrupts::clear_all unimplemented!\n");
+ range_list.clear();
+ range_list.push_back(RangeEx(x86LocalAPICAddress(0, 0),
+ x86LocalAPICAddress(0, 0) + PageBytes));
}
- bool check_interrupts(ThreadContext * tc) const
+ void getIntAddrRange(AddrRangeList &range_list)
{
- return false;
+ range_list.clear();
+ range_list.push_back(RangeEx(x86InterruptAddress(0, 0),
+ x86InterruptAddress(0, 0) + PhysAddrAPICRangeSize));
}
- Fault getInterrupt(ThreadContext * tc)
+ Port *getPort(const std::string &if_name, int idx = -1)
{
- return NoFault;
+ if (if_name == "int_port")
+ return intPort;
+ return BasicPioDevice::getPort(if_name, idx);
}
- void updateIntrInfo(ThreadContext * tc)
+ /*
+ * Functions to access and manipulate the APIC's registers.
+ */
+
+ uint32_t readReg(ApicRegIndex miscReg);
+ void setReg(ApicRegIndex reg, uint32_t val);
+ void
+ setRegNoEffect(ApicRegIndex reg, uint32_t val)
{
- panic("Interrupts::updateIntrInfo unimplemented!\n");
+ regs[reg] = val;
}
- uint64_t get_vec(int int_num)
+ /*
+ * Constructor.
+ */
+
+ Interrupts(Params * p)
+ : BasicPioDevice(p), IntDev(this), latency(p->pio_latency), clock(0),
+ apicTimerEvent(this),
+ pendingSmi(false), smiVector(0),
+ pendingNmi(false), nmiVector(0),
+ pendingExtInt(false), extIntVector(0),
+ pendingInit(false), initVector(0),
+ pendingUnmaskableInt(false)
{
- panic("Interrupts::get_vec unimplemented!\n");
- return 0;
+ pioSize = PageBytes;
+ memset(regs, 0, sizeof(regs));
+ //Set the local apic DFR to the flat model.
+ regs[APIC_DESTINATION_FORMAT] = (uint32_t)(-1);
+ ISRV = 0;
+ IRRV = 0;
}
- void serialize(std::ostream & os)
+ /*
+ * Functions for retrieving interrupts for the CPU to handle.
+ */
+
+ bool checkInterrupts(ThreadContext *tc) const;
+ Fault getInterrupt(ThreadContext *tc);
+ void updateIntrInfo(ThreadContext *tc);
+
+ /*
+ * Serialization.
+ */
+
+ void
+ serialize(std::ostream &os)
{
panic("Interrupts::serialize unimplemented!\n");
}
- void unserialize(Checkpoint * cp, const std::string & section)
+ void
+ unserialize(Checkpoint *cp, const std::string &section)
{
panic("Interrupts::unserialize unimplemented!\n");
}
-};
+ /*
+ * Old functions needed for compatability but which will be phased out
+ * eventually.
+ */
+ void
+ post(int int_num, int index)
+ {
+ panic("Interrupts::post unimplemented!\n");
+ }
+
+ void
+ clear(int int_num, int index)
+ {
+ panic("Interrupts::clear unimplemented!\n");
+ }
+
+ void
+ clearAll()
+ {
+ panic("Interrupts::clearAll unimplemented!\n");
+ }
};
+} // namespace X86ISA
+
#endif // __ARCH_X86_INTERRUPTS_HH__
diff --git a/src/arch/x86/intmessage.hh b/src/arch/x86/intmessage.hh
new file mode 100644
index 000000000..f5f8519e2
--- /dev/null
+++ b/src/arch/x86/intmessage.hh
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_INTMESSAGE_HH__
+#define __ARCH_X86_INTMESSAGE_HH__
+
+#include "arch/x86/x86_traits.hh"
+#include "base/bitunion.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+#include "sim/host.hh"
+
+namespace X86ISA
+{
+ BitUnion32(TriggerIntMessage)
+ Bitfield<7, 0> destination;
+ Bitfield<15, 8> vector;
+ Bitfield<18, 16> deliveryMode;
+ Bitfield<19> destMode;
+ Bitfield<20> level;
+ Bitfield<21> trigger;
+ EndBitUnion(TriggerIntMessage)
+
+ namespace DeliveryMode
+ {
+ enum IntDeliveryMode {
+ Fixed = 0,
+ LowestPriority = 1,
+ SMI = 2,
+ NMI = 4,
+ INIT = 5,
+ ExtInt = 7,
+ NumModes
+ };
+
+ static const char * const names[NumModes] = {
+ "Fixed", "LowestPriority", "SMI", "Reserved",
+ "NMI", "INIT", "Reserved", "ExtInt"
+ };
+
+ static inline bool
+ isReserved(int mode)
+ {
+ return mode == 3 || mode == 6;
+ }
+ }
+
+ static const Addr TriggerIntOffset = 0;
+
+ static inline PacketPtr
+ prepIntRequest(const uint8_t id, Addr offset, Addr size)
+ {
+ RequestPtr req = new Request(x86InterruptAddress(id, offset),
+ size, Request::UNCACHEABLE);
+ PacketPtr pkt = new Packet(req, MemCmd::MessageReq, Packet::Broadcast);
+ pkt->allocate();
+ return pkt;
+ }
+
+ template<class T>
+ PacketPtr
+ buildIntRequest(const uint8_t id, T payload, Addr offset, Addr size)
+ {
+ PacketPtr pkt = prepIntRequest(id, offset, size);
+ pkt->set<T>(payload);
+ return pkt;
+ }
+
+ static inline PacketPtr
+ buildIntRequest(const uint8_t id, TriggerIntMessage payload)
+ {
+ return buildIntRequest(id, payload, TriggerIntOffset,
+ sizeof(TriggerIntMessage));
+ }
+
+ static inline PacketPtr
+ buildIntResponse()
+ {
+ panic("buildIntResponse not implemented.\n");
+ }
+}
+
+#endif
diff --git a/src/arch/x86/intregfile.cc b/src/arch/x86/intregfile.cc
index 9c9ea134e..58a37cb9e 100644
--- a/src/arch/x86/intregfile.cc
+++ b/src/arch/x86/intregfile.cc
@@ -97,17 +97,6 @@ using namespace std;
class Checkpoint;
-string X86ISA::getIntRegName(RegIndex index)
-{
- //These might appear to be out of order, but they match
- //the encoding for the registers. Who knows why the indexes
- //are out of order
- static std::string intRegName[NumIntArchRegs] =
- {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
- "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"};
- return intRegName[index];
-}
-
int IntRegFile::flattenIndex(int reg)
{
return reg;
@@ -120,13 +109,15 @@ void IntRegFile::clear()
IntReg IntRegFile::readReg(int intReg)
{
- DPRINTF(X86, "Read int reg %d and got value %#x\n", intReg, regs[intReg]);
+ DPRINTF(IntRegs, "Read int reg %d and got value %#x\n",
+ intReg, regs[intReg]);
return regs[intReg];
}
void IntRegFile::setReg(int intReg, const IntReg &val)
{
- DPRINTF(X86, "Setting int reg %d to value %#x\n", intReg, val);
+ DPRINTF(IntRegs, "Setting int reg %d to value %#x\n",
+ intReg, val);
regs[intReg] = val;
}
diff --git a/src/arch/x86/intregfile.hh b/src/arch/x86/intregfile.hh
index b4d256a04..131245352 100644
--- a/src/arch/x86/intregfile.hh
+++ b/src/arch/x86/intregfile.hh
@@ -100,9 +100,6 @@ namespace X86ISA
{
class Regfile;
- //This function translates integer register file indices into names
- std::string getIntRegName(RegIndex);
-
const int NumIntArchRegs = NUM_INTREGS;
const int NumIntRegs =
NumIntArchRegs + NumMicroIntRegs +
diff --git a/src/arch/x86/isa/decoder/one_byte_opcodes.isa b/src/arch/x86/isa/decoder/one_byte_opcodes.isa
index 332ae1641..817986232 100644
--- a/src/arch/x86/isa/decoder/one_byte_opcodes.isa
+++ b/src/arch/x86/isa/decoder/one_byte_opcodes.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -418,12 +418,27 @@
default: Inst::RET_FAR();
}
0x4: int3();
+#if FULL_SYSTEM
0x5: int_Ib();
+#else
+ // Really only the LSB matters, but the predecoder will sign
+ // extend it, and there's no easy way to specify only checking
+ // the first byte.
+ 0x5: decode IMMEDIATE {
+ 0xffffffffffffff80:
+ SyscallInst::int80('xc->syscall(Rax)', IsSyscall);
+ default: int_Ib();
+ }
+#endif
0x6: decode MODE_SUBMODE {
0x0: Inst::UD2();
default: into();
}
- 0x7: iret();
+ 0x7: decode MODE_SUBMODE {
+ 0x4: Inst::IRET_REAL();
+ 0x3: Inst::IRET_VIRT();
+ default: Inst::IRET_PROT();
+ }
}
}
0x1A: decode OPCODE_OP_BOTTOM3 {
@@ -549,8 +564,8 @@
0x1F: decode OPCODE_OP_BOTTOM3 {
0x0: CLC();
0x1: STC();
- 0x2: WarnUnimpl::cli();
- 0x3: WarnUnimpl::sti();
+ 0x2: CLI();
+ 0x3: STI();
0x4: CLD();
0x5: STD();
//0x6: group4();
diff --git a/src/arch/x86/isa/decoder/two_byte_opcodes.isa b/src/arch/x86/isa/decoder/two_byte_opcodes.isa
index 8135a1fdb..1ee62142a 100644
--- a/src/arch/x86/isa/decoder/two_byte_opcodes.isa
+++ b/src/arch/x86/isa/decoder/two_byte_opcodes.isa
@@ -93,8 +93,8 @@
0x00: decode MODRM_REG {
0x0: sldt_Mw_or_Rv();
0x1: str_Mw_or_Rv();
- 0x2: lldt_Mw_or_Rv();
- 0x3: ltr_Mw_or_Rv();
+ 0x2: Inst::LLDT(Ew);
+ 0x3: Inst::LTR(Ew);
0x4: verr_Mw_or_Rv();
0x5: verw_Mw_or_Rv();
//0x6: jmpe_Ev(); // IA-64
@@ -128,7 +128,7 @@
0x4: smsw_Rv();
0x6: lmsw_Rv();
0x7: decode MODRM_RM {
- 0x0: swapgs();
+ 0x0: Inst::SWAPGS();
0x1: rdtscp();
default: Inst::UD2();
}
@@ -163,17 +163,117 @@
}
0x02: lar_Gv_Ew();
0x03: lsl_Gv_Ew();
- //sandpile.org doesn't seem to know what this is... ?
- 0x04: loadall_or_reset_or_hang();
+ // sandpile.org doesn't seem to know what this is...? We'll
+ // use it for pseudo instructions. We've got 16 bits of space
+ // to play with so there can be quite a few pseudo
+ // instructions.
+ //0x04: loadall_or_reset_or_hang();
+ 0x4: decode IMMEDIATE {
+ format BasicOperate {
#if FULL_SYSTEM
- 0x05: syscall();
+ 0x00: m5arm({{
+ PseudoInst::arm(xc->tcBase());
+ }}, IsNonSpeculative);
+ 0x01: m5quiesce({{
+ PseudoInst::quiesce(xc->tcBase());
+ }}, IsNonSpeculative);
+ 0x02: m5quiesceNs({{
+ PseudoInst::quiesceNs(xc->tcBase(), Rdi);
+ }}, IsNonSpeculative);
+ 0x03: m5quiesceCycle({{
+ PseudoInst::quiesceCycles(xc->tcBase(), Rdi);
+ }}, IsNonSpeculative);
+ 0x04: m5quiesceTime({{
+ Rax = PseudoInst::quiesceTime(xc->tcBase());
+ }}, IsNonSpeculative);
+#endif
+ 0x07: m5rpns({{
+ Rax = PseudoInst::rpns(xc->tcBase());
+ }}, IsNonSpeculative);
+ 0x21: m5exit({{
+ PseudoInst::m5exit(xc->tcBase(), Rdi);
+ }}, IsNonSpeculative);
+#if FULL_SYSTEM
+ 0x30: m5initparam({{
+ Rax = xc->tcBase()->getCpuPtr()->
+ system->init_param;
+ }}, IsNonSpeculative);
+ 0x31: m5loadsymbol({{
+ PseudoInst::loadsymbol(xc->tcBase());
+ }}, IsNonSpeculative);
+#endif
+ 0x40: m5resetstats({{
+ PseudoInst::resetstats(xc->tcBase(), Rdi, Rsi);
+ }}, IsNonSpeculative);
+ 0x41: m5dumpstats({{
+ PseudoInst::dumpstats(xc->tcBase(), Rdi, Rsi);
+ }}, IsNonSpeculative);
+ 0x42: m5dumpresetstats({{
+ PseudoInst::dumpresetstats(xc->tcBase(), Rdi, Rsi);
+ }}, IsNonSpeculative);
+ 0x43: m5checkpoint({{
+ PseudoInst::m5checkpoint(xc->tcBase(), Rdi, Rsi);
+ }}, IsNonSpeculative);
+#if FULL_SYSTEM
+ 0x50: m5readfile({{
+ Rax = PseudoInst::readfile(
+ xc->tcBase(), Rdi, Rsi, Rdx);
+ }}, IsNonSpeculative);
+#endif
+ 0x51: m5debugbreak({{
+ PseudoInst::debugbreak(xc->tcBase());
+ }}, IsNonSpeculative);
+ 0x52: m5switchcpu({{
+ PseudoInst::switchcpu(xc->tcBase());
+ }}, IsNonSpeculative);
+#if FULL_SYSTEM
+ 0x53: m5addsymbol({{
+ PseudoInst::addsymbol(xc->tcBase(), Rdi, Rsi);
+ }}, IsNonSpeculative);
+#endif
+ 0x54: m5panic({{
+ panic("M5 panic instruction called at pc=%#x.\n",
+ xc->readPC());
+ }}, IsNonSpeculative);
+ 0x55: m5reserved1({{
+ warn("M5 reserved opcode 1 ignored.\n");
+ }}, IsNonSpeculative);
+ 0x56: m5reserved2({{
+ warn("M5 reserved opcode 2 ignored.\n");
+ }}, IsNonSpeculative);
+ 0x57: m5reserved3({{
+ warn("M5 reserved opcode 3 ignored.\n");
+ }}, IsNonSpeculative);
+ 0x58: m5reserved4({{
+ warn("M5 reserved opcode 4 ignored.\n");
+ }}, IsNonSpeculative);
+ 0x59: m5reserved5({{
+ warn("M5 reserved opcode 5 ignored.\n");
+ }}, IsNonSpeculative);
+ default: Inst::UD2();
+ }
+ }
+#if FULL_SYSTEM
+ 0x05: decode MODE_MODE {
+ 0x0: decode MODE_SUBMODE {
+ 0x0: Inst::SYSCALL_64();
+ 0x1: Inst::SYSCALL_COMPAT();
+ }
+ 0x1: Inst::SYSCALL_LEGACY();
+ }
#else
- 0x05: SyscallInst::syscall('xc->syscall(rax)', IsSyscall);
+ 0x05: SyscallInst::syscall('xc->syscall(Rax)', IsSyscall);
#endif
- 0x06: clts();
- //sandpile.org says (AMD) after sysret, so I might want to check
- //if that means amd64 or AMD machines
- 0x07: loadall_or_sysret();
+ 0x06: Inst::CLTS();
+ 0x07: decode MODE_SUBMODE {
+ 0x0: decode OPSIZE {
+ // Return to 64 bit mode.
+ 0x8: Inst::SYSRET_TO_64();
+ // Return to compatibility mode.
+ default: Inst::SYSRET_TO_COMPAT();
+ }
+ default: Inst::SYSRET_NON_64();
+ }
}
0x01: decode OPCODE_OP_BOTTOM3 {
0x0: invd();
@@ -181,9 +281,9 @@
0x2: Inst::UD2();
0x3: Inst::UD2();
0x4: Inst::UD2();
- 0x5: threednow();
- 0x6: threednow();
- 0x7: threednow();
+ 0x5: Inst::PREFETCH(Mb);
+ 0x6: FailUnimpl::femms();
+ 0x7: FailUnimpl::threednow();
}
0x02: decode LEGACY_DECODEVAL {
// no prefix
@@ -235,7 +335,7 @@
//group17();
0x0: decode MODRM_REG {
0x0: prefetch_nta();
- 0x1: prefetch_t0();
+ 0x1: Inst::PREFETCH_T0(Mb);
0x2: prefetch_t1();
0x3: prefetch_t2();
default: Inst::HINT_NOP();
@@ -252,9 +352,9 @@
// no prefix
0x0: decode OPCODE_OP_BOTTOM3 {
0x0: Inst::MOV(Rd,Cd);
- 0x1: mov_Rd_Dd();
+ 0x1: Inst::MOV(Rd,Dd);
0x2: Inst::MOV(Cd,Rd);
- 0x3: mov_Dd_Rd();
+ 0x3: Inst::MOV(Dd,Rd);
0x4: mov_Rd_Td();
0x6: mov_Td_Rd();
default: Inst::UD2();
@@ -317,10 +417,14 @@
}
0x06: decode OPCODE_OP_BOTTOM3 {
0x0: Inst::WRMSR();
- 0x1: rdtsc();
+ 0x1: Inst::RDTSC();
0x2: Inst::RDMSR();
0x3: rdpmc();
+#if FULL_SYSTEM
0x4: sysenter();
+#else
+ 0x4: SyscallInst::sysenter('xc->syscall(Rax)', IsSyscall);
+#endif
0x5: sysexit();
0x6: Inst::UD2();
0x7: getsec();
@@ -707,7 +811,14 @@
0x14: decode OPCODE_OP_BOTTOM3 {
0x0: push_fs();
0x1: pop_fs();
- 0x2: Inst::CPUID(rAd);
+ 0x2: CPUIDInst::CPUID({{
+ CpuidResult result;
+ success = doCpuid(xc->tcBase(), Rax, result);
+ Rax = result.rax;
+ Rbx = result.rbx;
+ Rcx = result.rcx;
+ Rdx = result.rdx;
+ }});
0x3: Inst::BT(Ev,Gv);
0x4: shld_Ev_Gv_Ib();
0x5: shld_Ev_Gv_rCl();
@@ -719,20 +830,28 @@
0x1: pop_gs();
0x2: rsm_smm();
0x3: Inst::BTS(Ev,Gv);
- 0x4: shrd_Ev_Gv_Ib();
+ 0x4: Inst::SHRD(Ev,Gv,Ib);
0x5: shrd_Ev_Gv_rCl();
//0x6: group16();
- 0x6: decode MODRM_MOD {
- 0x3: decode MODRM_REG {
- 0x5: lfence();
- 0x6: mfence();
- 0x7: sfence();
+ 0x6: decode MODRM_REG {
+ 0x0: fxsave();
+ 0x1: fxrstor();
+ 0x2: ldmxcsr();
+ 0x3: stmxcsr();
+ 0x4: Inst::UD2();
+ 0x5: decode MODRM_MOD {
+ 0x3: BasicOperate::LFENCE(
+ {{/*Nothing*/}}, IsReadBarrier);
default: Inst::UD2();
}
- default: decode MODRM_REG {
- 0x0: fxsave();
- 0x1: fxrstor();
- 0x7: clflush();
+ 0x6: decode MODRM_MOD {
+ 0x3: BasicOperate::MFENCE(
+ {{/*Nothing*/}}, IsMemBarrier);
+ default: Inst::UD2();
+ }
+ 0x7: decode MODRM_MOD {
+ 0x3: BasicOperate::SFENCE(
+ {{/*Nothing*/}}, IsWriteBarrier);
default: Inst::UD2();
}
}
@@ -775,8 +894,8 @@
0x7: Inst::MOVSX_W(Gv,Ev);
}
0x18: decode OPCODE_OP_BOTTOM3 {
- 0x0: xadd_Eb_Gb();
- 0x1: xadd_Ev_Gv();
+ 0x0: Inst::XADD(Eb,Gb);
+ 0x1: Inst::XADD(Ev,Gv);
//0x7: group9();
0x7: decode MODRM_REG {
0x1: cmpxchg_Mq();
@@ -820,7 +939,11 @@
default: Inst::UD2();
}
}
- 0x19: bswap_B();
+ 0x19: decode OPSIZE {
+ 4: Inst::BSWAP_D(Bd);
+ 8: Inst::BSWAP_Q(Bq);
+ default: Inst::UD2();
+ }
0x1A: decode LEGACY_DECODEVAL {
// no prefix
0x0: decode OPCODE_OP_BOTTOM3 {
diff --git a/src/arch/x86/isa/formats/basic.isa b/src/arch/x86/isa/formats/basic.isa
index 7aea7085f..b96bae238 100644
--- a/src/arch/x86/isa/formats/basic.isa
+++ b/src/arch/x86/isa/formats/basic.isa
@@ -147,3 +147,11 @@ def template BasicDecode {{
def template BasicDecodeWithMnemonic {{
return new %(class_name)s("%(mnemonic)s", machInst);
}};
+
+def format BasicOperate(code, *flags) {{
+ iop = InstObjParams(name, Name, 'X86ISA::X86StaticInst', 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/x86/isa/formats/cpuid.isa b/src/arch/x86/isa/formats/cpuid.isa
new file mode 100644
index 000000000..204270556
--- /dev/null
+++ b/src/arch/x86/isa/formats/cpuid.isa
@@ -0,0 +1,110 @@
+// Copyright (c) 2008 The Hewlett-Packard Development Company
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the
+// following conditions are met:
+//
+// The software must be used only for Non-Commercial Use which means any
+// use which is NOT directed to receiving any direct monetary
+// compensation for, or commercial advantage from such use. Illustrative
+// examples of non-commercial use are academic research, personal study,
+// teaching, education and corporate research & development.
+// Illustrative examples of commercial use are distributing products for
+// commercial advantage and providing services using the software for
+// commercial advantage.
+//
+// If you wish to use this software or functionality therein that may be
+// covered by patents for commercial use, please contact:
+// Director of Intellectual Property Licensing
+// Office of Strategy and Technology
+// Hewlett-Packard Company
+// 1501 Page Mill Road
+// Palo Alto, California 94304
+//
+// Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer. Redistributions
+// in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution. Neither the name of
+// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission. No right of
+// sublicense is granted herewith. Derivatives of the software and
+// output created using the software may be prepared, but only for
+// Non-Commercial Uses. Derivatives of the software may be shared with
+// others provided: (i) the others agree to abide by the list of
+// conditions herein which includes the Non-Commercial Use restrictions;
+// and (ii) such Derivatives of the software include the above copyright
+// notice to acknowledge the contribution from this software where
+// applicable, this list of conditions and the disclaimer below.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+output header {{
+ class CPUIDInst : public X86ISA::X86StaticInst
+ {
+ public:
+ static const RegIndex foldOBit = 0;
+ /// Constructor
+ CPUIDInst(const char *_mnemonic, ExtMachInst _machInst,
+ OpClass __opClass) :
+ X86ISA::X86StaticInst(_mnemonic, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ std::string CPUIDInst::generateDisassembly(Addr PC,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, mnemonic);
+ ccprintf(response, " ");
+ printReg(response, _srcRegIdx[0], machInst.opSize);
+ return response.str();
+ }
+}};
+
+def template CPUIDExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ // If the CPUID instruction used a valid function number, this will
+ // be set to true. Otherwise, the instruction does nothing.
+ bool success;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+ if (success) {
+ %(op_wb)s;
+ }
+ return NoFault;
+ }
+}};
+
+def format CPUIDInst(code, *opt_flags) {{
+ iop = InstObjParams(name, Name, 'CPUIDInst', code, opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = CPUIDExecute.subst(iop)
+}};
+
diff --git a/src/arch/x86/isa/formats/formats.isa b/src/arch/x86/isa/formats/formats.isa
index 6906413c0..81179ab45 100644
--- a/src/arch/x86/isa/formats/formats.isa
+++ b/src/arch/x86/isa/formats/formats.isa
@@ -85,6 +85,9 @@
//Templates from this format are used later
##include "basic.isa"
+//Include a format to generate a CPUID instruction.
+##include "cpuid.isa"
+
//Include the "unknown" format
##include "unknown.isa"
diff --git a/src/arch/x86/isa/includes.isa b/src/arch/x86/isa/includes.isa
index 6724ea9b0..8626f117a 100644
--- a/src/arch/x86/isa/includes.isa
+++ b/src/arch/x86/isa/includes.isa
@@ -26,7 +26,7 @@
//
// Authors: Gabe Black
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -97,6 +97,7 @@ output header {{
#include <iostream>
#include "arch/x86/emulenv.hh"
+#include "arch/x86/insts/macroop.hh"
#include "arch/x86/insts/microfpop.hh"
#include "arch/x86/insts/microldstop.hh"
#include "arch/x86/insts/microregop.hh"
@@ -113,10 +114,13 @@ output header {{
output decoder {{
#include "arch/x86/faults.hh"
#include "arch/x86/floatregs.hh"
+#include "arch/x86/microcode_rom.hh"
#include "arch/x86/miscregs.hh"
#include "arch/x86/segmentregs.hh"
+#include "arch/x86/tlb.hh"
#include "base/cprintf.hh"
#include "base/loader/symtab.hh"
+#include "base/misc.hh"
#include "cpu/thread_context.hh" // for Jump::branchTarget()
#include "mem/packet.hh"
@@ -144,6 +148,7 @@ output exec {{
#include <limits>
#include <cmath>
+#include "arch/x86/cpuid.hh"
#include "arch/x86/miscregs.hh"
#include "arch/x86/tlb.hh"
#include "base/bigint.hh"
@@ -152,6 +157,8 @@ output exec {{
#include "sim/sim_exit.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
+#include "mem/request.hh"
+#include "sim/pseudo_inst.hh"
using namespace X86ISA;
using namespace std;
diff --git a/src/arch/x86/isa/insts/__init__.py b/src/arch/x86/isa/insts/__init__.py
index 0ef617a87..d7a8bde19 100644
--- a/src/arch/x86/isa/insts/__init__.py
+++ b/src/arch/x86/isa/insts/__init__.py
@@ -53,7 +53,8 @@
#
# Authors: Gabe Black
-categories = ["general_purpose",
+categories = ["romutil",
+ "general_purpose",
"simd128",
"simd64",
"system",
diff --git a/src/arch/x86/isa/insts/general_purpose/__init__.py b/src/arch/x86/isa/insts/general_purpose/__init__.py
index 4f77cb233..23f955f08 100644
--- a/src/arch/x86/isa/insts/general_purpose/__init__.py
+++ b/src/arch/x86/isa/insts/general_purpose/__init__.py
@@ -65,7 +65,6 @@ categories = ["arithmetic",
"load_segment_registers",
"logical",
"no_operation",
- "processor_information",
"rotate_and_shift",
"semaphores",
"string",
diff --git a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py
index a9b53acac..19d1c7789 100644
--- a/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py
+++ b/src/arch/x86/isa/insts/general_purpose/arithmetic/multiply_and_divide.py
@@ -246,7 +246,7 @@ def macroop DIV_B_R
divLoopTop:
div2 t1, rax, t1, dataSize=1
div2 t1, rax, t1, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax, dataSize=1
@@ -269,7 +269,7 @@ def macroop DIV_B_M
divLoopTop:
div2 t1, rax, t1, dataSize=1
div2 t1, rax, t1, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax, dataSize=1
@@ -293,7 +293,7 @@ def macroop DIV_B_P
divLoopTop:
div2 t1, rax, t1, dataSize=1
div2 t1, rax, t1, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax, dataSize=1
@@ -321,7 +321,7 @@ divLoopTop:
div2 t1, rax, t1
div2 t1, rax, t1
div2 t1, rax, t1, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax
@@ -347,7 +347,7 @@ divLoopTop:
div2 t1, rax, t1
div2 t1, rax, t1
div2 t1, rax, t1, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax
@@ -374,7 +374,7 @@ divLoopTop:
div2 t1, rax, t1
div2 t1, rax, t1
div2 t1, rax, t1, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq rax
@@ -422,7 +422,7 @@ def macroop IDIV_B_R
divLoopTop:
div2 t4, t1, t4, dataSize=1
div2 t4, t1, t4, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5, dataSize=1
@@ -495,7 +495,7 @@ def macroop IDIV_B_M
divLoopTop:
div2 t4, t1, t4, dataSize=1
div2 t4, t1, t4, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5, dataSize=1
@@ -569,7 +569,7 @@ def macroop IDIV_B_P
divLoopTop:
div2 t4, t1, t4, dataSize=1
div2 t4, t1, t4, flags=(EZF,), dataSize=1
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5, dataSize=1
@@ -646,7 +646,7 @@ divLoopTop:
div2 t4, t1, t4
div2 t4, t1, t4
div2 t4, t1, t4, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5
@@ -721,7 +721,7 @@ divLoopTop:
div2 t4, t1, t4
div2 t4, t1, t4
div2 t4, t1, t4, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5
@@ -797,7 +797,7 @@ divLoopTop:
div2 t4, t1, t4
div2 t4, t1, t4
div2 t4, t1, t4, flags=(EZF,)
- bri t0, label("divLoopTop"), flags=(nCEZF,)
+ br label("divLoopTop"), flags=(nCEZF,)
#Unload the answer
divq t5
diff --git a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py
index b5fc43fcd..dbd2d8b84 100644
--- a/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py
+++ b/src/arch/x86/isa/insts/general_purpose/cache_and_memory_management.py
@@ -53,20 +53,42 @@
#
# Authors: Gabe Black
-microcode = ""
+microcode = '''
+def macroop PREFETCH_M
+{
+ ld t0, seg, sib, disp, dataSize=1, prefetch=True
+};
+
+def macroop PREFETCH_P
+{
+ rdip t7
+ ld t0, seg, riprel, disp, dataSize=1, prefetch=True
+};
+
+def macroop PREFETCH_T0_M
+{
+ ld t0, seg, sib, disp, dataSize=1, prefetch=True
+};
+
+def macroop PREFETCH_T0_P
+{
+ rdip t7
+ ld t0, seg, riprel, disp, dataSize=1, prefetch=True
+};
+
+'''
+
#let {{
# class LFENCE(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class SFENCE(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class MFENCE(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class PREFETCHlevel(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class PREFETCH(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class PREFETCHW(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class CLFLUSH(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py
index 71059e80d..22364e038 100644
--- a/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py
+++ b/src/arch/x86/isa/insts/general_purpose/compare_and_test/bit_scan.py
@@ -82,11 +82,11 @@
# Authors: Gabe Black
microcode = '''
-def macroop BSF_R_R {
+def macroop BSR_R_R {
# Determine if the input was zero, and also move it to a temp reg.
movi t1, t1, t0, dataSize=8
and t1, regm, regm, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
movi reg, reg, 0x0
@@ -125,20 +125,19 @@ def macroop BSF_R_R {
srli t3, t1, 1, dataSize=8, flags=(EZF,)
ori t4, reg, 0x1
mov reg, reg, t4, flags=(nCEZF,)
- mov t1, t1, t3, flags=(nCEZF,)
end:
fault "NoFault"
};
-def macroop BSF_R_M {
+def macroop BSR_R_M {
movi t1, t1, t0, dataSize=8
ld t1, seg, sib, disp
# Determine if the input was zero, and also move it to a temp reg.
and t1, t1, t1, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
movi reg, reg, 0x0
@@ -177,13 +176,12 @@ def macroop BSF_R_M {
srli t3, t1, 1, dataSize=8, flags=(EZF,)
ori t4, reg, 0x1
mov reg, reg, t4, flags=(nCEZF,)
- mov t1, t1, t3, flags=(nCEZF,)
end:
fault "NoFault"
};
-def macroop BSF_R_P {
+def macroop BSR_R_P {
rdip t7
movi t1, t1, t0, dataSize=8
@@ -191,7 +189,7 @@ def macroop BSF_R_P {
# Determine if the input was zero, and also move it to a temp reg.
and t1, t1, t1, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
movi reg, reg, 0x0
@@ -230,17 +228,16 @@ def macroop BSF_R_P {
srli t3, t1, 1, dataSize=8, flags=(EZF,)
ori t4, reg, 0x1
mov reg, reg, t4, flags=(nCEZF,)
- mov t1, t1, t3, flags=(nCEZF,)
end:
fault "NoFault"
};
-def macroop BSR_R_R {
+def macroop BSF_R_R {
# Determine if the input was zero, and also move it to a temp reg.
mov t1, t1, t0, dataSize=8
and t1, regm, regm, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
movi reg, reg, 0
@@ -248,48 +245,54 @@ def macroop BSR_R_R {
subi t2, t1, 1
xor t1, t2, t1
+
# Bit 6
- srli t3, t1, 32, dataSize=8
- andi t3, t3, 32
- or reg, reg, t3
+ srli t3, t1, 32, dataSize=8, flags=(EZF,)
+ ori t4, reg, 32
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 5
- srli t3, t1, 16, dataSize=8
- andi t3, t3, 16
- or reg, reg, t3
+ srli t3, t1, 16, dataSize=8, flags=(EZF,)
+ ori t4, reg, 16
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 4
- srli t3, t1, 8, dataSize=8
- andi t3, t3, 8
- or reg, reg, t3
+ srli t3, t1, 8, dataSize=8, flags=(EZF,)
+ ori t4, reg, 8
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 3
- srli t3, t1, 4, dataSize=8
- andi t3, t3, 4
- or reg, reg, t3
+ srli t3, t1, 4, dataSize=8, flags=(EZF,)
+ ori t4, reg, 4
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 2
- srli t3, t1, 2, dataSize=8
- andi t3, t3, 2
- or reg, reg, t3
+ srli t3, t1, 2, dataSize=8, flags=(EZF,)
+ ori t4, reg, 2
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 1
- srli t3, t1, 1, dataSize=8
- andi t3, t3, 1
- or reg, reg, t3
+ srli t3, t1, 1, dataSize=8, flags=(EZF,)
+ ori t4, reg, 1
+ mov reg, reg, t4, flags=(nCEZF,)
end:
fault "NoFault"
};
-def macroop BSR_R_M {
+def macroop BSF_R_M {
mov t1, t1, t0, dataSize=8
ld t1, seg, sib, disp
# Determine if the input was zero, and also move it to a temp reg.
and t1, t1, t1, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
mov reg, reg, t0
@@ -298,40 +301,46 @@ def macroop BSR_R_M {
xor t1, t2, t1
# Bit 6
- srli t3, t1, 32, dataSize=8
- andi t3, t3, 32
- or reg, reg, t3
+ srli t3, t1, 32, dataSize=8, flags=(EZF,)
+ ori t4, reg, 32
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 5
- srli t3, t1, 16, dataSize=8
- andi t3, t3, 16
- or reg, reg, t3
+ srli t3, t1, 16, dataSize=8, flags=(EZF,)
+ ori t4, reg, 16
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 4
- srli t3, t1, 8, dataSize=8
- andi t3, t3, 8
- or reg, reg, t3
+ srli t3, t1, 8, dataSize=8, flags=(EZF,)
+ ori t4, reg, 8
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 3
- srli t3, t1, 4, dataSize=8
- andi t3, t3, 4
- or reg, reg, t3
+ srli t3, t1, 4, dataSize=8, flags=(EZF,)
+ ori t4, reg, 4
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 2
- srli t3, t1, 2, dataSize=8
- andi t3, t3, 2
- or reg, reg, t3
+ srli t3, t1, 2, dataSize=8, flags=(EZF,)
+ ori t4, reg, 2
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 1
- srli t3, t1, 1, dataSize=8
- andi t3, t3, 1
- or reg, reg, t3
+ srli t3, t1, 1, dataSize=8, flags=(EZF,)
+ ori t4, reg, 1
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
end:
fault "NoFault"
};
-def macroop BSR_R_P {
+def macroop BSF_R_P {
rdip t7
mov t1, t1, t0, dataSize=8
@@ -339,7 +348,7 @@ def macroop BSR_R_P {
# Determine if the input was zero, and also move it to a temp reg.
and t1, t1, t1, flags=(ZF,)
- bri t0, label("end"), flags=(CZF,)
+ br label("end"), flags=(CZF,)
# Zero out the result register
mov reg, reg, t0
@@ -348,34 +357,40 @@ def macroop BSR_R_P {
xor t1, t2, t1
# Bit 6
- srli t3, t1, 32, dataSize=8
- andi t3, t3, 32
- or reg, reg, t3
+ srli t3, t1, 32, dataSize=8, flags=(EZF,)
+ ori t4, reg, 32
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 5
- srli t3, t1, 16, dataSize=8
- andi t3, t3, 16
- or reg, reg, t3
+ srli t3, t1, 16, dataSize=8, flags=(EZF,)
+ ori t4, reg, 16
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 4
- srli t3, t1, 8, dataSize=8
- andi t3, t3, 8
- or reg, reg, t3
+ srli t3, t1, 8, dataSize=8, flags=(EZF,)
+ ori t4, reg, 8
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 3
- srli t3, t1, 4, dataSize=8
- andi t3, t3, 4
- or reg, reg, t3
+ srli t3, t1, 4, dataSize=8, flags=(EZF,)
+ ori t4, reg, 4
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 2
- srli t3, t1, 2, dataSize=8
- andi t3, t3, 2
- or reg, reg, t3
+ srli t3, t1, 2, dataSize=8, flags=(EZF,)
+ ori t4, reg, 2
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
# Bit 1
- srli t3, t1, 1, dataSize=8
- andi t3, t3, 1
- or reg, reg, t3
+ srli t3, t1, 1, dataSize=8, flags=(EZF,)
+ ori t4, reg, 1
+ mov reg, reg, t4, flags=(nCEZF,)
+ mov t1, t1, t3, flags=(nCEZF,)
end:
fault "NoFault"
diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py
index 45a7822fb..7abafe253 100644
--- a/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py
+++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/call.py
@@ -103,5 +103,5 @@ def macroop CALL_NEAR_P
'''
#let {{
# class CALL(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py
index 7039b4b5c..8203f7c2c 100644
--- a/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py
+++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/interrupts_and_exceptions.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -53,16 +53,194 @@
#
# Authors: Gabe Black
-microcode = ""
+microcode = '''
+def macroop IRET_REAL {
+ panic "Real mode iret isn't implemented!"
+};
+
+def macroop IRET_PROT {
+ .adjust_env oszIn64Override
+
+ # Check for a nested task. This isn't supported at the moment.
+ rflag t1, NT
+ panic "Task switching with iret is unimplemented!", flags=(nCEZF,)
+
+ #t1 = temp_RIP
+ #t2 = temp_CS
+ #t3 = temp_RFLAGS
+ #t4 = handy m5 register
+
+ # Pop temp_RIP, temp_CS, and temp_RFLAGS
+ ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz
+ ld t2, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz
+ ld t3, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz
+
+ # Read the handy m5 register for use later
+ rdm5reg t4
+
+
+###
+### Handle if we're returning to virtual 8086 mode.
+###
+
+ #IF ((temp_RFLAGS.VM=1) && (CPL=0) && (LEGACY_MODE))
+ # IRET_FROM_PROTECTED_TO_VIRTUAL
+
+ #temp_RFLAGS.VM != 1
+ rcri t0, t3, 18, flags=(ECF,)
+ br label("protToVirtFallThrough"), flags=(nCECF,)
+
+ #CPL=0
+ andi t0, t4, 0x30, flags=(EZF,)
+ br label("protToVirtFallThrough"), flags=(nCEZF,)
+
+ #(LEGACY_MODE)
+ rcri t0, t4, 1, flags=(ECF,)
+ br label("protToVirtFallThrough"), flags=(nCECF,)
+
+ panic "iret to virtual mode not supported"
+
+protToVirtFallThrough:
+
+
+
+ #temp_CPL = temp_CS.rpl
+ andi t5, t2, 0x3
+
+
+###
+### Read in the info for the new CS segment.
+###
+
+ #CS = READ_DESCRIPTOR (temp_CS, iret_chk)
+ andi t0, t2, 0xFC, flags=(EZF,), dataSize=2
+ br label("processCSDescriptor"), flags=(CEZF,)
+ andi t6, t2, 0xF8, dataSize=8
+ andi t0, t2, 0x4, flags=(EZF,), dataSize=2
+ br label("globalCSDescriptor"), flags=(CEZF,)
+ ld t8, tsl, [1, t0, t6], dataSize=8
+ br label("processCSDescriptor")
+globalCSDescriptor:
+ ld t8, tsg, [1, t0, t6], dataSize=8
+processCSDescriptor:
+ chks t2, t6, dataSize=8
+
+
+###
+### Get the new stack pointer and stack segment off the old stack if necessary,
+### and piggyback on the logic to check the new RIP value.
+###
+ #IF ((64BIT_MODE) || (temp_CPL!=CPL))
+ #{
+
+ #(64BIT_MODE)
+ andi t0, t4, 0xE, flags=(EZF,)
+ # Since we just found out we're in 64 bit mode, take advantage and
+ # do the appropriate RIP checks.
+ br label("doPopStackStuffAndCheckRIP"), flags=(CEZF,)
+
+ # Here, we know we're -not- in 64 bit mode, so we should do the
+ # appropriate/other RIP checks.
+ # if temp_RIP > CS.limit throw #GP(0)
+ rdlimit t6, cs, dataSize=8
+ subi t0, t1, t6, flags=(ECF,)
+ fault "new GeneralProtection(0)", flags=(CECF,)
+
+ #(temp_CPL!=CPL)
+ srli t7, t4, 4
+ xor t7, t7, t5
+ andi t0, t7, 0x3, flags=(EZF,)
+ br label("doPopStackStuff"), flags=(nCEZF,)
+ # We can modify user visible state here because we're know
+ # we're done with things that can fault.
+ addi rsp, rsp, "3 * env.stackSize"
+ br label("fallThroughPopStackStuff")
+
+doPopStackStuffAndCheckRIP:
+ # Check if the RIP is canonical.
+ sra t7, t1, 47, flags=(EZF,), dataSize=ssz
+ # if t7 isn't 0 or -1, it wasn't canonical.
+ br label("doPopStackStuff"), flags=(CEZF,)
+ addi t0, t7, 1, flags=(EZF,), dataSize=ssz
+ fault "new GeneralProtection(0)", flags=(nCEZF,)
+
+doPopStackStuff:
+ # POP.v temp_RSP
+ ld t6, ss, [1, t0, rsp], "3 * env.dataSize", dataSize=ssz
+ # POP.v temp_SS
+ ld t9, ss, [1, t0, rsp], "4 * env.dataSize", dataSize=ssz
+ # SS = READ_DESCRIPTOR (temp_SS, ss_chk)
+ andi t0, t9, 0xFC, flags=(EZF,), dataSize=2
+ br label("processSSDescriptor"), flags=(CEZF,)
+ andi t7, t9, 0xF8, dataSize=8
+ andi t0, t9, 0x4, flags=(EZF,), dataSize=2
+ br label("globalSSDescriptor"), flags=(CEZF,)
+ ld t7, tsl, [1, t0, t7], dataSize=8
+ br label("processSSDescriptor")
+globalSSDescriptor:
+ ld t7, tsg, [1, t0, t7], dataSize=8
+processSSDescriptor:
+ chks t9, t7, dataSize=8
+
+ # This actually updates state which is wrong. It should wait until we know
+ # we're not going to fault. Unfortunately, that's hard to do.
+ wrdl ss, t7, t9
+ wrsel ss, t9
+
+###
+### From this point downwards, we can't fault. We can update user visible state.
+###
+ # RSP.s = temp_RSP
+ mov rsp, rsp, t6, dataSize=ssz
+
+ #}
+
+fallThroughPopStackStuff:
+
+ # Update CS
+ wrdl cs, t8, t2
+ wrsel cs, t2
+
+ #CPL = temp_CPL
+
+ #IF (changing CPL)
+ #{
+ srli t7, t4, 4
+ xor t7, t7, t5
+ andi t0, t7, 0x3, flags=(EZF,)
+ br label("skipSegmentSquashing"), flags=(CEZF,)
+
+ # The attribute register needs to keep track of more info before this will
+ # work the way it needs to.
+ # FOR (seg = ES, DS, FS, GS)
+ # IF ((seg.attr.dpl < cpl && ((seg.attr.type = 'data')
+ # || (seg.attr.type = 'non-conforming-code')))
+ # {
+ # seg = NULL
+ # }
+ #}
+
+skipSegmentSquashing:
+
+ # Ignore this for now.
+ #RFLAGS.v = temp_RFLAGS
+ wrflags t0, t3
+ # VIF,VIP,IOPL only changed if (old_CPL = 0)
+ # IF only changed if (old_CPL <= old_RFLAGS.IOPL)
+ # VM unchanged
+ # RF cleared
+
+ #RIP = temp_RIP
+ wrip t0, t1, dataSize=ssz
+};
+
+def macroop IRET_VIRT {
+ panic "Virtual mode iret isn't implemented!"
+};
+'''
#let {{
# class INT(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class INTO(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class IRET(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class IRETD(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class IRETQ(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py
index 0b2e81cbd..57ec9da26 100644
--- a/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py
+++ b/src/arch/x86/isa/insts/general_purpose/control_transfer/xreturn.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -85,7 +85,7 @@ def macroop RET_FAR {
ld t1, ss, [1, t0, rsp]
# Get the return CS
- ld t2, ss, [1, t0, rsp], dsz
+ ld t2, ss, [1, t0, rsp], ssz
# Get the rpl
andi t3, t2, 0x3
@@ -96,14 +96,23 @@ def macroop RET_FAR {
# that doesn't happen yet.
# Do stuff if they're equal
- chks t4, t2, flags=(EZF,)
- fault "new GeneralProtection(0)", flags=(CEZF,)
- ld t3, flatseg, [1, t0, t4], addressSize=8, dataSize=8
- wrdl cs, t3, t2
+ andi t0, t2, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t3, t2, 0xF8, dataSize=8
+ andi t0, t2, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t3], dataSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t3], dataSize=8
+processDescriptor:
+ chks t2, t3, IretCheck, dataSize=8
# There should be validity checks on the RIP checks here, but I'll do
# that later.
+ wrdl cs, t3, t2
+ wrsel cs, t2
wrip t0, t1
- bri t0, label("end")
+ br label("end")
# Do other stuff if they're not.
end:
diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py
index a1e322e56..2cbdd1ad8 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/ascii_adjust.py
@@ -56,11 +56,11 @@
microcode = ""
#let {{
# class AAA(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class AAD(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class AAM(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class AAS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py
index 213724768..d220fdeb6 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/bcd_adjust.py
@@ -56,7 +56,7 @@
microcode = ""
#let {{
# class DAA(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class DAS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py
index b98d09816..ac2343462 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/endian_conversion.py
@@ -53,8 +53,26 @@
#
# Authors: Gabe Black
-microcode = ""
+microcode = '''
+def macroop BSWAP_D_R
+{
+ roli reg, reg, 8, dataSize=2
+ roli reg, reg, 16, dataSize=4
+ roli reg, reg, 8, dataSize=2
+};
+
+def macroop BSWAP_Q_R
+{
+ roli reg, reg, 8, dataSize=2
+ roli reg, reg, 16, dataSize=4
+ roli reg, reg, 8, dataSize=2
+ roli reg, reg, 32, dataSize=8
+ roli reg, reg, 8, dataSize=2
+ roli reg, reg, 16, dataSize=4
+ roli reg, reg, 8, dataSize=2
+};
+'''
#let {{
# class BSWAP(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py
index 1e0810594..01fa280fc 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/extract_sign_mask.py
@@ -56,7 +56,7 @@
microcode = ""
#let {{
# class MOVMSKPS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class MOVMSKPD(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py
index d6ae7885a..c334693e5 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_conversion/translate.py
@@ -55,7 +55,7 @@
microcode = '''
def macroop XLAT {
- zexti t1, rax, 7
+ zexti t1, rax, 7, dataSize=8
# Here, t1 can be used directly. The value of al is supposed to be treated
# as unsigned. Since we zero extended it from 8 bits above and the address
# size has to be at least 16 bits, t1 will not be sign extended.
diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py
index 3b8608c48..60c046d04 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/move.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -126,18 +126,19 @@ def macroop MOVSXD_R_P {
};
def macroop MOVSX_B_R_R {
- sexti reg, regm, 7
+ mov t1, t1, regm, dataSize=1
+ sexti reg, t1, 7
};
def macroop MOVSX_B_R_M {
- ld reg, seg, sib, disp, dataSize=1
- sexti reg, reg, 7
+ ld t1, seg, sib, disp, dataSize=1
+ sexti reg, t1, 7
};
def macroop MOVSX_B_R_P {
rdip t7
- ld reg, seg, riprel, disp, dataSize=1
- sexti reg, reg, 7
+ ld t1, seg, riprel, disp, dataSize=1
+ sexti reg, t1, 7
};
def macroop MOVSX_W_R_R {
@@ -160,7 +161,8 @@ def macroop MOVSX_W_R_P {
#
def macroop MOVZX_B_R_R {
- zexti reg, regm, 7
+ mov t1, t1, regm, dataSize=1
+ zexti reg, t1, 7
};
def macroop MOVZX_B_R_M {
@@ -190,13 +192,25 @@ def macroop MOVZX_W_R_P {
};
def macroop MOV_C_R {
+ .adjust_env maxOsz
wrcr reg, regm
};
def macroop MOV_R_C {
+ .adjust_env maxOsz
rdcr reg, regm
};
+def macroop MOV_D_R {
+ .adjust_env maxOsz
+ wrdr reg, regm
+};
+
+def macroop MOV_R_D {
+ .adjust_env maxOsz
+ rddr reg, regm
+};
+
def macroop MOV_R_S {
rdsel reg, regm
};
@@ -213,7 +227,7 @@ def macroop MOV_P_S {
};
def macroop MOV_REAL_S_R {
- zext t2, regm, 15
+ zexti t2, regm, 15, dataSize=8
slli t3, t2, 2, dataSize=8
wrsel reg, regm
wrbase reg, t3
@@ -221,87 +235,121 @@ def macroop MOV_REAL_S_R {
def macroop MOV_REAL_S_M {
ld t1, seg, sib, disp, dataSize=2
- zext t2, t1, 15
+ zexti t2, t1, 15, dataSize=8
slli t3, t2, 2, dataSize=8
wrsel reg, t1
wrbase reg, t3
};
def macroop MOV_REAL_S_P {
- rdip t7
- ld t1, seg, riprel, disp, dataSize=2
- zext t2, t1, 15
- slli t3, t2, 2, dataSize=8
- wrsel reg, t1
- wrbase reg, t3
+ panic "RIP relative addressing shouldn't happen in real mode"
};
def macroop MOV_S_R {
- chks t1, regm, flags=(EZF,), dataSize=8
- bri t0, label("end"), flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, regm
-end:
+ andi t0, regm, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, regm, 0xF8, dataSize=8
+ andi t0, regm, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks regm, t3, dataSize=8
+ wrdl reg, t3, regm
wrsel reg, regm
};
def macroop MOV_S_M {
ld t1, seg, sib, disp, dataSize=2
- chks t2, t1, flags=(EZF,), dataSize=8
- bri t0, label("end"), flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, t1
-end:
+ andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, t1, 0xF8, dataSize=8
+ andi t0, t1, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks t1, t3, dataSize=8
+ wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOV_S_P {
rdip t7
ld t1, seg, riprel, disp, dataSize=2
- chks t2, t1, flags=(EZF,), dataSize=8
- bri t0, label("end"), flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, t1
-end:
+ andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, t1, 0xF8, dataSize=8
+ andi t0, t1, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks t1, t3, dataSize=8
+ wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOVSS_S_R {
- chks t1, regm, flags=(EZF,), dataSize=8
- # This actually needs to use the selector as the error code, but it would
- # be hard to get that information into the instruction at the moment.
- fault "new GeneralProtection(0)", flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, regm
+ andi t0, regm, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, regm, 0xF8, dataSize=8
+ andi t0, regm, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks regm, t3, SSCheck, dataSize=8
+ wrdl reg, t3, regm
wrsel reg, regm
};
def macroop MOVSS_S_M {
ld t1, seg, sib, disp, dataSize=2
- chks t2, t1, flags=(EZF,), dataSize=8
- # This actually needs to use the selector as the error code, but it would
- # be hard to get that information into the instruction at the moment.
- fault "new GeneralProtection(0)", flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, t1
+ andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, t1, 0xF8, dataSize=8
+ andi t0, t1, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks t1, t3, SSCheck, dataSize=8
+ wrdl reg, t3, t1
wrsel reg, t1
};
def macroop MOVSS_S_P {
rdip t7
ld t1, seg, riprel, disp, dataSize=2
- chks t2, t1, flags=(EZF,), dataSize=8
- # This actually needs to use the selector as the error code, but it would
- # be hard to get that information into the instruction at the moment.
- fault "new GeneralProtection(0)", flags=(CEZF,)
- ld t2, flatseg, [1, t0, t1], addressSize=8, dataSize=8
- wrdl reg, t2, t1
+ andi t0, t1, 0xFC, flags=(EZF,), dataSize=2
+ br label("processDescriptor"), flags=(CEZF,)
+ andi t2, t1, 0xF8, dataSize=8
+ andi t0, t1, 0x4, flags=(EZF,), dataSize=2
+ br label("globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t2], dataSize=8, addressSize=8
+ br label("processDescriptor")
+globalDescriptor:
+ ld t3, tsg, [1, t0, t2], dataSize=8, addressSize=8
+processDescriptor:
+ chks t1, t3, SSCheck, dataSize=8
+ wrdl reg, t3, t1
wrsel reg, t1
};
'''
#let {{
# class MOVD(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class MOVNTI(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py
index 6c51f3171..82fdffc63 100644
--- a/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py
+++ b/src/arch/x86/isa/insts/general_purpose/data_transfer/stack_operations.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -58,8 +58,8 @@ def macroop POP_R {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env oszIn64Override
- ld t1, ss, [1, t0, rsp]
- addi rsp, rsp, dsz
+ ld t1, ss, [1, t0, rsp], dataSize=ssz
+ addi rsp, rsp, ssz, dataSize=asz
mov reg, reg, t1
};
@@ -67,10 +67,10 @@ def macroop POP_M {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env oszIn64Override
- ld t1, ss, [1, t0, rsp]
- cda seg, sib, disp
- addi rsp, rsp, dsz
- st t1, seg, sib, disp
+ ld t1, ss, [1, t0, rsp], dataSize=ssz
+ cda seg, sib, disp, dataSize=ssz
+ addi rsp, rsp, ssz, dataSize=asz
+ st t1, seg, sib, disp, dataSize=ssz
};
def macroop POP_P {
@@ -78,17 +78,17 @@ def macroop POP_P {
.adjust_env oszIn64Override
rdip t7
- ld t1, ss, [1, t0, rsp]
- cda seg, sib, disp
- addi rsp, rsp, dsz
- st t1, seg, riprel, disp
+ ld t1, ss, [1, t0, rsp], dataSize=ssz
+ cda seg, sib, disp, dataSize=ssz
+ addi rsp, rsp, ssz, dataSize=asz
+ st t1, seg, riprel, disp, dataSize=ssz
};
def macroop PUSH_R {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env oszIn64Override
- stupd reg, ss, [1, t0, rsp], "-env.dataSize"
+ stupd reg, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop PUSH_I {
@@ -96,15 +96,15 @@ def macroop PUSH_I {
.adjust_env oszIn64Override
limm t1, imm
- stupd t1, ss, [1, t0, rsp], "-env.dataSize"
+ stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop PUSH_M {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env oszIn64Override
- ld t1, seg, sib, disp
- stupd t1, ss, [1, t0, rsp], "-env.dataSize"
+ ld t1, seg, sib, disp, dataSize=ssz
+ stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop PUSH_P {
@@ -112,48 +112,48 @@ def macroop PUSH_P {
.adjust_env oszIn64Override
rdip t7
- ld t1, seg, riprel, disp
- stupd t1, ss, [1, t0, rsp], "-env.dataSize"
+ ld t1, seg, riprel, disp, dataSize=ssz
+ stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop PUSHA {
# Check all the stack addresses. We'll assume that if the beginning and
# end are ok, then the stuff in the middle should be as well.
- cda ss, [1, t0, rsp], "-env.dataSize"
- cda ss, [1, t0, rsp], "-8 * env.dataSize"
- stupd rax, ss, [1, t0, rsp], "-env.dataSize"
- stupd rcx, ss, [1, t0, rsp], "-env.dataSize"
- stupd rdx, ss, [1, t0, rsp], "-env.dataSize"
- stupd rbx, ss, [1, t0, rsp], "-env.dataSize"
- stupd rsp, ss, [1, t0, rsp], "-env.dataSize"
- stupd rbp, ss, [1, t0, rsp], "-env.dataSize"
- stupd rsi, ss, [1, t0, rsp], "-env.dataSize"
- stupd rdi, ss, [1, t0, rsp], "-env.dataSize"
+ cda ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ cda ss, [1, t0, rsp], "-8 * env.stackSize", dataSize=ssz
+ stupd rax, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rcx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rdx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rbx, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rsp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rsi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
+ stupd rdi, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop POPA {
# Check all the stack addresses. We'll assume that if the beginning and
# end are ok, then the stuff in the middle should be as well.
- ld t1, ss, [1, t0, rsp], "0 * env.dataSize"
- ld t2, ss, [1, t0, rsp], "7 * env.dataSize"
- mov rdi, rdi, t1
- ld rsi, ss, [1, t0, rsp], "1 * env.dataSize"
- ld rbp, ss, [1, t0, rsp], "2 * env.dataSize"
- ld rbx, ss, [1, t0, rsp], "4 * env.dataSize"
- ld rdx, ss, [1, t0, rsp], "5 * env.dataSize"
- ld rcx, ss, [1, t0, rsp], "6 * env.dataSize"
- mov rax, rax, t2
- addi rsp, rsp, "8 * env.dataSize"
+ ld t1, ss, [1, t0, rsp], "0 * env.stackSize", dataSize=ssz
+ ld t2, ss, [1, t0, rsp], "7 * env.stackSize", dataSize=ssz
+ mov rdi, rdi, t1, dataSize=ssz
+ ld rsi, ss, [1, t0, rsp], "1 * env.stackSize", dataSize=ssz
+ ld rbp, ss, [1, t0, rsp], "2 * env.stackSize", dataSize=ssz
+ ld rbx, ss, [1, t0, rsp], "4 * env.stackSize", dataSize=ssz
+ ld rdx, ss, [1, t0, rsp], "5 * env.stackSize", dataSize=ssz
+ ld rcx, ss, [1, t0, rsp], "6 * env.stackSize", dataSize=ssz
+ mov rax, rax, t2, dataSize=ssz
+ addi rsp, rsp, "8 * env.stackSize", dataSize=asz
};
def macroop LEAVE {
# Make the default data size of pops 64 bits in 64 bit mode
.adjust_env oszIn64Override
- mov t1, t1, rbp
- ld rbp, ss, [1, t0, t1]
- mov rsp, rsp, t1
- addi rsp, rsp, dsz
+ mov t1, t1, rbp, dataSize=asz
+ ld rbp, ss, [1, t0, t1], dataSize=ssz
+ mov rsp, rsp, t1, dataSize=asz
+ addi rsp, rsp, ssz, dataSize=asz
};
def macroop ENTER_I_I {
@@ -162,41 +162,41 @@ def macroop ENTER_I_I {
# Pull the different components out of the immediate
limm t1, imm
- zexti t2, t1, 15, dataSize=2
+ zexti t2, t1, 15, dataSize=8
srl t1, t1, 16
- zexti t1, t1, 5
+ zexti t1, t1, 5, dataSize=8
# t1 is now the masked nesting level, and t2 is the amount of storage.
# Push rbp.
- stupd rbp, ss, [1, t0, rsp], "-env.dataSize"
+ stupd rbp, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
# Save the stack pointer for later
- mov t6, t6, rsp
+ mov t6, t6, rsp, dataSize=asz
# If the nesting level is zero, skip all this stuff.
subi t0, t1, t0, flags=(EZF,), dataSize=2
- bri t0, label("skipLoop"), flags=(CEZF,)
+ br label("skipLoop"), flags=(CEZF,)
# If the level was 1, only push the saved rbp
subi t0, t1, 1, flags=(EZF,)
- bri t0, label("bottomOfLoop"), flags=(CEZF,)
+ br label("bottomOfLoop"), flags=(CEZF,)
limm t4, "ULL(-1)", dataSize=8
topOfLoop:
- ld t5, ss, [dsz, t4, rbp]
- stupd t5, ss, [1, t0, rsp], "-env.dataSize"
+ ld t5, ss, [ssz, t4, rbp], dataSize=ssz
+ stupd t5, ss, [1, t0, rsp], "-env.stackSize"
# If we're not done yet, loop
subi t4, t4, 1, dataSize=8
add t0, t4, t1, flags=(EZF,)
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ br label("topOfLoop"), flags=(nCEZF,)
bottomOfLoop:
# Push the old rbp onto the stack
- stupd t6, ss, [1, t0, rsp], "-env.dataSize"
+ stupd t6, ss, [1, t0, rsp], "-env.stackSize"
skipLoop:
- sub rsp, rsp, t2
- mov rbp, rbp, t6
+ sub rsp, rsp, t2, dataSize=asz
+ mov rbp, rbp, t6, dataSize=asz
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py
index fe60350c1..59f6aaec2 100644
--- a/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py
+++ b/src/arch/x86/isa/insts/general_purpose/flags/push_and_pop.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -57,17 +57,15 @@ microcode = '''
def macroop PUSHF {
.adjust_env oszIn64Override
- # This should really read the whole flags register, not just user flags.
- ruflags t1
- stupd t1, ss, [1, t0, rsp], "-env.dataSize"
+ rflags t1
+ stupd t1, ss, [1, t0, rsp], "-env.stackSize", dataSize=ssz
};
def macroop POPF {
.adjust_env oszIn64Override
- ld t1, ss, [1, t0, rsp]
- addi rsp, rsp, dsz
- # This should really write the whole flags register, not just user flags.
- wruflags t1, t0
+ ld t1, ss, [1, t0, rsp], dataSize=ssz
+ addi rsp, rsp, ssz
+ wrflags t1, t0
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py
index 4c655e0b2..e151dc61d 100644
--- a/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py
+++ b/src/arch/x86/isa/insts/general_purpose/flags/set_and_clear.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -84,10 +84,18 @@ def macroop CMC {
ruflags t1
wruflagsi t1, "CFBit"
};
+
+def macroop STI {
+ rflags t1
+ limm t2, "IFBit"
+ or t1, t1, t2
+ wrflags t1, t0
+};
+
+def macroop CLI {
+ rflags t1
+ limm t2, "~IFBit"
+ and t1, t1, t2
+ wrflags t1, t0
+};
'''
-#let {{
-# class CLI(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class STI(Inst):
-# "GenFault ${new UnimpInstFault}"
-#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py
index 1986a322e..4e3c9b316 100644
--- a/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py
+++ b/src/arch/x86/isa/insts/general_purpose/input_output/general_io.py
@@ -84,25 +84,23 @@
microcode = '''
def macroop IN_R_I {
.adjust_imm trimImm(8)
- limm t1, "IntAddrPrefixIO", dataSize=8
- ld reg, intseg, [1, t1, t0], imm, addressSize=8
+ limm t1, imm, dataSize=asz
+ ld reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8
};
def macroop IN_R_R {
- limm t1, "IntAddrPrefixIO", dataSize=8
- zexti t2, regm, 15, dataSize=2
- ld reg, intseg, [1, t1, t2], addressSize=8
+ zexti t2, regm, 15, dataSize=8
+ ld reg, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
};
def macroop OUT_I_R {
.adjust_imm trimImm(8)
- limm t1, "IntAddrPrefixIO", dataSize=8
- st reg, intseg, [1, t1, t0], imm, addressSize=8
+ limm t1, imm, dataSize=8
+ st reg, intseg, [1, t1, t0], "IntAddrPrefixIO << 3", addressSize=8
};
def macroop OUT_R_R {
- limm t1, "IntAddrPrefixIO", dataSize=8
- zexti t2, reg, 15, dataSize=2
- st regm, intseg, [1, t1, t2], addressSize=8
+ zexti t2, reg, 15, dataSize=8
+ st regm, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py
index b44203d9c..b3bc5ab67 100644
--- a/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py
+++ b/src/arch/x86/isa/insts/general_purpose/input_output/string_io.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -61,32 +61,33 @@ def macroop INS_M_R {
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
- limm t1, "IntAddrPrefixIO"
- zexti t2, reg, 15, dataSize=2
+ zexti t2, reg, 15, dataSize=8
- ld t6, intseg, [1, t1, t2], addressSize=8
+ ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
st t6, es, [1, t0, rdi]
add rdi, rdi, t3, dataSize=asz
};
def macroop INS_E_M_R {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
- limm t1, "IntAddrPrefixIO"
- zexti t2, reg, 15, dataSize=2
+ zexti t2, reg, 15, dataSize=8
topOfLoop:
- ld t6, intseg, [1, t1, t2], addressSize=8
+ ld t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
st t6, es, [1, t0, rdi]
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t3, dataSize=asz
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ br label("topOfLoop"), flags=(nCEZF,)
+end:
fault "NoFault"
};
@@ -97,32 +98,33 @@ def macroop OUTS_R_M {
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
- limm t1, "IntAddrPrefixIO"
- zexti t2, reg, 15, dataSize=2
+ zexti t2, reg, 15, dataSize=8
ld t6, ds, [1, t0, rsi]
- st t6, intseg, [1, t1, t2], addressSize=8
+ st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
add rsi, rsi, t3, dataSize=asz
};
def macroop OUTS_E_R_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
- limm t1, "IntAddrPrefixIO"
- zexti t2, reg, 15, dataSize=2
+ zexti t2, reg, 15, dataSize=8
topOfLoop:
ld t6, ds, [1, t0, rsi]
- st t6, intseg, [1, t1, t2], addressSize=8
+ st t6, intseg, [1, t2, t0], "IntAddrPrefixIO << 3", addressSize=8
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rsi, rsi, t3, dataSize=asz
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ br label("topOfLoop"), flags=(nCEZF,)
+end:
fault "NoFault"
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py
index 8aec4b99e..e6633ee1a 100644
--- a/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py
+++ b/src/arch/x86/isa/insts/general_purpose/load_segment_registers.py
@@ -56,17 +56,17 @@
microcode = ""
#let {{
# class LDS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class LES(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class LFS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class LGS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class LSS(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class MOV_SEG(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class POP(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/processor_information.py b/src/arch/x86/isa/insts/general_purpose/processor_information.py
deleted file mode 100644
index 6070169ac..000000000
--- a/src/arch/x86/isa/insts/general_purpose/processor_information.py
+++ /dev/null
@@ -1,405 +0,0 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
-# All rights reserved.
-#
-# Redistribution and use of this software in source and binary forms,
-# with or without modification, are permitted provided that the
-# following conditions are met:
-#
-# The software must be used only for Non-Commercial Use which means any
-# use which is NOT directed to receiving any direct monetary
-# compensation for, or commercial advantage from such use. Illustrative
-# examples of non-commercial use are academic research, personal study,
-# teaching, education and corporate research & development.
-# Illustrative examples of commercial use are distributing products for
-# commercial advantage and providing services using the software for
-# commercial advantage.
-#
-# If you wish to use this software or functionality therein that may be
-# covered by patents for commercial use, please contact:
-# Director of Intellectual Property Licensing
-# Office of Strategy and Technology
-# Hewlett-Packard Company
-# 1501 Page Mill Road
-# Palo Alto, California 94304
-#
-# Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer. Redistributions
-# in binary form must reproduce the above copyright notice, this list of
-# conditions and the following disclaimer in the documentation and/or
-# other materials provided with the distribution. Neither the name of
-# the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission. No right of
-# sublicense is granted herewith. Derivatives of the software and
-# output created using the software may be prepared, but only for
-# Non-Commercial Uses. Derivatives of the software may be shared with
-# others provided: (i) the others agree to abide by the list of
-# conditions herein which includes the Non-Commercial Use restrictions;
-# and (ii) such Derivatives of the software include the above copyright
-# notice to acknowledge the contribution from this software where
-# applicable, this list of conditions and the disclaimer below.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (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
-
-microcode = '''
-def macroop CPUID_R {
-
-#
-# Find which type of cpuid function it is by checking bit 31. Also clear that
-# bit to form an offset into the functions of that type.
-#
- limm t1, 0x80000000, dataSize=4
- and t2, t1, rax, flags=(EZF,)
- # clear the bit
- xor t1, t2, rax
-
-#
-# Do range checking on the offset
-#
- # If EZF is set, the function is standard and the max is 0x1.
- movi t2, t2, 0x1, flags=(CEZF,)
- # If EZF is cleared, the function is extended and the max is 0x18.
- movi t2, t2, 0x18, flags=(nCEZF,)
- subi t0, t1, t2, flags=(ECF,)
- # ECF will be set if the offset is too large.
- bri t0, label("end"), flags=(nCECF,)
-
-
-#
-# Jump to the right portion
-#
- movi t2, t2, label("standardStart"), flags=(CEZF,)
- movi t2, t2, label("extendedStart"), flags=(nCEZF,)
- # This gives each function 8 microops to use. It's wasteful because only
- # 5 will be needed, but a multiply would be expensive. In the system
- # described in the RISC86 patent, the fifth instruction would really be
- # the sequencing field on an op quad, so each function would be implemented
- # by -exactly- one op quad. Since we're approximating, this should be ok.
- slli t1, t1, 3
- br t2, t1
-
-#############################################################################
-#############################################################################
-
-#
-# Standard functions.
-#
-
-standardStart:
-
-# 0x00000000 -- Processor Vendor and Largest Standard Function Number
- limm rax, 0x00000001, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x00000001 -- Family, Model, Stepping Identifiers
- limm rax, 0x00020f51, dataSize=4
- limm rbx, 0x00000405, dataSize=4
- limm rdx, 0xe3d3fbff, dataSize=4
- limm rcx, 0x00000001, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-#
-# Extended functions.
-#
-
-extendedStart:
-
-# 0x80000000 -- Processor Vendor and Largest Extended Function Number
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000001 -- EAX: AMD Family, Model, Stepping
-# EBX: BrandId Identifier
-# ECX: Feature Identifiers
-# EDX: Feature Identifiers
- limm rax, 0x00020f51, dataSize=4
- limm rbx, 0x00000405, dataSize=4
- limm rdx, 0xe3d3fbff, dataSize=4
- limm rcx, 0x00000001, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000002 -- Processor Name String Identifier
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000003 -- Processor Name String Identifier
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000004 -- Processor Name String Identifier
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000005 -- L1 Cache and TLB Identifiers
- limm rax, 0xff08ff08, dataSize=4
- limm rbx, 0xff20ff20, dataSize=4
- limm rdx, 0x40020140, dataSize=4
- limm rcx, 0x40020140, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000006 -- L2/L3 Cache and L2 TLB Identifiers
- limm rax, 0x00000000, dataSize=4
- limm rbx, 0x42004200, dataSize=4
- limm rdx, 0x00000000, dataSize=4
- limm rcx, 0x04008140, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000007 -- Advanced Power Management Information
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000008 -- Long Mode Address Size Identification
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000009 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000A -- SVM Revision and Feature Identification
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000B -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000C -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000D -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000E -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x8000000F -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000010 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000011 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000012 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000013 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000014 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000015 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000016 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000017 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-# 0x80000018 -- Reserved
- # JUNK VALUES
- limm rax, 0x80000018, dataSize=4
- limm rbx, 0x68747541, dataSize=4
- limm rdx, 0x69746e65, dataSize=4
- limm rcx, 0x444d4163, dataSize=4
- bri t0, label("end")
- fault "NoFault"
- fault "NoFault"
- fault "NoFault"
-
-end:
- fault "NoFault"
-};
-'''
diff --git a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py
index ed7d761b8..caaeca974 100644
--- a/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py
+++ b/src/arch/x86/isa/insts/general_purpose/rotate_and_shift/shift.py
@@ -56,13 +56,13 @@
microcode = '''
def macroop SAL_R_I
{
- slli reg, reg, imm, flags=(SF,ZF,PF)
+ slli reg, reg, imm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAL_M_I
{
ldst t1, seg, sib, disp
- slli t1, t1, imm, flags=(SF,ZF,PF)
+ slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -70,19 +70,19 @@ def macroop SAL_P_I
{
rdip t7
ldst t1, seg, riprel, disp
- slli t1, t1, imm, flags=(SF,ZF,PF)
+ slli t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SAL_1_R
{
- slli reg, reg, 1, flags=(SF,ZF,PF)
+ slli reg, reg, 1, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAL_1_M
{
ldst t1, seg, sib, disp
- slli t1, t1, 1, flags=(SF,ZF,PF)
+ slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -90,19 +90,19 @@ def macroop SAL_1_P
{
rdip t7
ldst t1, seg, riprel, disp
- slli t1, t1, 1, flags=(SF,ZF,PF)
+ slli t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SAL_R_R
{
- sll reg, reg, regm, flags=(SF,ZF,PF)
+ sll reg, reg, regm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAL_M_R
{
ldst t1, seg, sib, disp
- sll t1, t1, reg, flags=(SF,ZF,PF)
+ sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -110,19 +110,19 @@ def macroop SAL_P_R
{
rdip t7
ldst t1, seg, riprel, disp
- sll t1, t1, reg, flags=(SF,ZF,PF)
+ sll t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SHR_R_I
{
- srli reg, reg, imm, flags=(SF,ZF,PF)
+ srli reg, reg, imm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SHR_M_I
{
ldst t1, seg, sib, disp
- srli t1, t1, imm, flags=(SF,ZF,PF)
+ srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -130,19 +130,19 @@ def macroop SHR_P_I
{
rdip t7
ldst t1, seg, riprel, disp
- srli t1, t1, imm, flags=(SF,ZF,PF)
+ srli t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SHR_1_R
{
- srli reg, reg, 1, flags=(SF,ZF,PF)
+ srli reg, reg, 1, flags=(CF,OF,SF,ZF,PF)
};
def macroop SHR_1_M
{
ldst t1, seg, sib, disp
- srli t1, t1, 1, flags=(SF,ZF,PF)
+ srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -150,19 +150,19 @@ def macroop SHR_1_P
{
rdip t7
ldst t1, seg, riprel, disp
- srli t1, t1, 1, flags=(SF,ZF,PF)
+ srli t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SHR_R_R
{
- srl reg, reg, regm, flags=(SF,ZF,PF)
+ srl reg, reg, regm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SHR_M_R
{
ldst t1, seg, sib, disp
- srl t1, t1, reg, flags=(SF,ZF,PF)
+ srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -170,19 +170,54 @@ def macroop SHR_P_R
{
rdip t7
ldst t1, seg, riprel, disp
- srl t1, t1, reg, flags=(SF,ZF,PF)
+ srl t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
+ st t1, seg, riprel, disp
+};
+
+# SHRD will not set OF correctly when the shift count is 1.
+def macroop SHRD_R_R_I
+{
+ srli t1, reg, imm, flags=(CF,)
+ rori t2, regm, imm
+ srli t3, regm, imm
+ xor t2, t2, t3
+ or reg, t1, t2
+};
+
+# SHRD will not set OF correctly when the shift count is 1.
+def macroop SHRD_M_R_I
+{
+ ldst t1, seg, sib, disp
+ srli t1, t1, imm, flags=(CF,)
+ rori t2, reg, imm
+ srli t3, reg, imm
+ xor t2, t2, t3
+ or t1, t1, t2
+ st t1, seg, sib, disp
+};
+
+# SHRD will not set OF correctly when the shift count is 1.
+def macroop SHRD_P_R_I
+{
+ rdip t7
+ ldst t1, seg, riprel, disp
+ srli t1, t1, imm, flags=(CF,)
+ rori t2, reg, imm
+ srli t3, reg, imm
+ xor t2, t2, t3
+ or t1, t1, t2
st t1, seg, riprel, disp
};
def macroop SAR_R_I
{
- srai reg, reg, imm, flags=(SF,ZF,PF)
+ srai reg, reg, imm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAR_M_I
{
ldst t1, seg, sib, disp
- srai t1, t1, imm, flags=(SF,ZF,PF)
+ srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -190,19 +225,19 @@ def macroop SAR_P_I
{
rdip t7
ldst t1, seg, riprel, disp
- srai t1, t1, imm, flags=(SF,ZF,PF)
+ srai t1, t1, imm, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SAR_1_R
{
- srai reg, reg, 1, flags=(SF,ZF,PF)
+ srai reg, reg, 1, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAR_1_M
{
ldst t1, seg, sib, disp
- srai t1, t1, 1, flags=(SF,ZF,PF)
+ srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -210,19 +245,19 @@ def macroop SAR_1_P
{
rdip t7
ldst t1, seg, riprel, disp
- srai t1, t1, 1, flags=(SF,ZF,PF)
+ srai t1, t1, 1, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
def macroop SAR_R_R
{
- sra reg, reg, regm, flags=(SF,ZF,PF)
+ sra reg, reg, regm, flags=(CF,OF,SF,ZF,PF)
};
def macroop SAR_M_R
{
ldst t1, seg, sib, disp
- sra t1, t1, reg, flags=(SF,ZF,PF)
+ sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
st t1, seg, sib, disp
};
@@ -230,7 +265,7 @@ def macroop SAR_P_R
{
rdip t7
ldst t1, seg, riprel, disp
- sra t1, t1, reg, flags=(SF,ZF,PF)
+ sra t1, t1, reg, flags=(CF,OF,SF,ZF,PF)
st t1, seg, riprel, disp
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/semaphores.py b/src/arch/x86/isa/insts/general_purpose/semaphores.py
index 27a31dbd9..f23241863 100644
--- a/src/arch/x86/isa/insts/general_purpose/semaphores.py
+++ b/src/arch/x86/isa/insts/general_purpose/semaphores.py
@@ -78,10 +78,30 @@ def macroop CMPXCHG_P_R {
st t1, seg, riprel, disp
mov rax, rax, t1, flags=(nCZF,)
};
+
+def macroop XADD_M_R {
+ ldst t1, seg, sib, disp
+ add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF)
+ st t2, seg, sib, disp
+ mov reg, reg, t1
+};
+
+def macroop XADD_P_R {
+ rdip t7
+ ldst t1, seg, riprel, disp
+ add t2, t1, reg, flags=(OF,SF,ZF,AF,PF,CF)
+ st t2, seg, riprel, disp
+ mov reg, reg, t1
+};
+
+def macroop XADD_R_R {
+ add t2, regm, reg, flags=(OF,SF,ZF,AF,PF,CF)
+ mov regm, regm, reg
+ mov reg, reg, t2
+};
+
'''
#let {{
-# class XADD(Inst):
-# "GenFault ${new UnimpInstFault}"
# class XCHG(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py
index 71b8511b4..561b8a415 100644
--- a/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py
+++ b/src/arch/x86/isa/insts/general_purpose/string/compare_strings.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -75,12 +75,16 @@ def macroop CMPS_M_M {
#
def macroop CMPS_E_M_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
+
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
+topOfLoop:
ld t1, seg, [1, t0, rsi]
ld t2, es, [1, t0, rdi]
sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF)
@@ -88,17 +92,22 @@ def macroop CMPS_E_M_M {
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t3, dataSize=asz
add rsi, rsi, t3, dataSize=asz
- bri t0, 4, flags=(CSTRZnEZF,)
+ br label("topOfLoop"), flags=(CSTRZnEZF,)
+end:
fault "NoFault"
};
def macroop CMPS_N_M_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
+
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
+topOfLoop:
ld t1, seg, [1, t0, rsi]
ld t2, es, [1, t0, rdi]
sub t0, t1, t2, flags=(OF, SF, ZF, AF, PF, CF)
@@ -106,7 +115,8 @@ def macroop CMPS_N_M_M {
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t3, dataSize=asz
add rsi, rsi, t3, dataSize=asz
- bri t0, 4, flags=(CSTRnZnEZF,)
+ br label("topOfLoop"), flags=(CSTRnZnEZF,)
+end:
fault "NoFault"
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/string/load_string.py b/src/arch/x86/isa/insts/general_purpose/string/load_string.py
index 61525c2f2..14198701a 100644
--- a/src/arch/x86/isa/insts/general_purpose/string/load_string.py
+++ b/src/arch/x86/isa/insts/general_purpose/string/load_string.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -61,12 +61,14 @@ def macroop LODS_M {
subi t4, t0, dsz, dataSize=asz
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
- ld rax, seg, [1, t0, rdi]
+ ld rax, seg, [1, t0, rsi]
- add rdi, rdi, t3, dataSize=asz
+ add rsi, rsi, t3, dataSize=asz
};
def macroop LODS_E_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
@@ -74,11 +76,12 @@ def macroop LODS_E_M {
mov t3, t3, t4, flags=(nCEZF,), dataSize=asz
topOfLoop:
- ld rax, seg, [1, t0, rdi]
+ ld rax, seg, [1, t0, rsi]
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
- add rdi, rdi, t3, dataSize=asz
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ add rsi, rsi, t3, dataSize=asz
+ br label("topOfLoop"), flags=(nCEZF,)
+end:
fault "NoFault"
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/string/move_string.py b/src/arch/x86/isa/insts/general_purpose/string/move_string.py
index b64acfdc2..18faa38e2 100644
--- a/src/arch/x86/isa/insts/general_purpose/string/move_string.py
+++ b/src/arch/x86/isa/insts/general_purpose/string/move_string.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -69,6 +69,8 @@ def macroop MOVS_M_M {
};
def macroop MOVS_E_M_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
@@ -82,7 +84,8 @@ topOfLoop:
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t3, dataSize=asz
add rsi, rsi, t3, dataSize=asz
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ br label("topOfLoop"), flags=(nCEZF,)
+end:
fault "NoFault"
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py
index b038cc00a..5b0e74aad 100644
--- a/src/arch/x86/isa/insts/general_purpose/string/scan_string.py
+++ b/src/arch/x86/isa/insts/general_purpose/string/scan_string.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -73,34 +73,44 @@ def macroop SCAS_M {
#
def macroop SCAS_E_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
+
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t2, t2, dsz, flags=(CEZF,), dataSize=asz
subi t3, t0, dsz, dataSize=asz
mov t2, t2, t3, flags=(nCEZF,), dataSize=asz
+topOfLoop:
ld t1, es, [1, t0, rdi]
sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF)
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t2, dataSize=asz
- bri t0, 4, flags=(CSTRZnEZF,)
+ br label("topOfLoop"), flags=(CSTRZnEZF,)
+end:
fault "NoFault"
};
def macroop SCAS_N_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
+
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t2, t2, dsz, flags=(CEZF,), dataSize=asz
subi t3, t0, dsz, dataSize=asz
mov t2, t2, t3, flags=(nCEZF,), dataSize=asz
+topOfLoop:
ld t1, es, [1, t0, rdi]
sub t0, t1, rax, flags=(OF, SF, ZF, AF, PF, CF)
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t2, dataSize=asz
- bri t0, 4, flags=(CSTRnZnEZF,)
+ br label("topOfLoop"), flags=(CSTRnZnEZF,)
+end:
fault "NoFault"
};
diff --git a/src/arch/x86/isa/insts/general_purpose/string/store_string.py b/src/arch/x86/isa/insts/general_purpose/string/store_string.py
index a8d558929..fe9917ce6 100644
--- a/src/arch/x86/isa/insts/general_purpose/string/store_string.py
+++ b/src/arch/x86/isa/insts/general_purpose/string/store_string.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2007 The Hewlett-Packard Development Company
+# Copyright (c) 2007-2008 The Hewlett-Packard Development Company
# All rights reserved.
#
# Redistribution and use of this software in source and binary forms,
@@ -67,6 +67,8 @@ def macroop STOS_M {
};
def macroop STOS_E_M {
+ and t0, rcx, rcx, flags=(EZF,), dataSize=asz
+ br label("end"), flags=(CEZF,)
# Find the constant we need to either add or subtract from rdi
ruflag t0, 10
movi t3, t3, dsz, flags=(CEZF,), dataSize=asz
@@ -78,7 +80,8 @@ topOfLoop:
subi rcx, rcx, 1, flags=(EZF,), dataSize=asz
add rdi, rdi, t3, dataSize=asz
- bri t0, label("topOfLoop"), flags=(nCEZF,)
+ br label("topOfLoop"), flags=(nCEZF,)
+end:
fault "NoFault"
};
'''
diff --git a/src/arch/x86/isa/insts/general_purpose/system_calls.py b/src/arch/x86/isa/insts/general_purpose/system_calls.py
index e056bea84..67607d5f8 100644
--- a/src/arch/x86/isa/insts/general_purpose/system_calls.py
+++ b/src/arch/x86/isa/insts/general_purpose/system_calls.py
@@ -53,14 +53,183 @@
#
# Authors: Gabe Black
-microcode = ""
+microcode = '''
+def macroop SYSCALL_64
+{
+ # All 1s.
+ limm t1, "(uint64_t)(-1)"
+
+ # Save the next RIP.
+ rdip rcx
+
+ # Stick rflags with RF masked into r11.
+ rflags t2
+ limm t3, "~RFBit"
+ andi r11, t2, t3, dataSize=8
+
+ rdval t3, star
+ srli t3, t3, 32, dataSize=8
+ andi t3, t3, 0xFC, dataSize=1
+
+ # Set up CS.
+ wrsel cs, t3
+ wrbase cs, t0, dataSize=8
+ wrlimit cs, t1, dataSize=4
+ # Not writable, read/execute-able, not expandDown,
+ # dpl=0, defaultSize=0, long mode
+ limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+ (0 << 3) | (0 << 5) | (1 << 6))
+ wrattr cs, t4
+
+ # Set up SS.
+ addi t3, t3, 8
+ wrsel ss, t3
+ wrbase ss, t0, dataSize=8
+ wrlimit ss, t1, dataSize=4
+ # Writable, readable, not expandDown,
+ # dpl=0, defaultSize=0, not long mode
+ limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \
+ (0 << 3) | (0 << 5) | (0 << 6))
+ wrattr ss, t4
+
+ # Set the new rip.
+ rdval t7, lstar
+ wrip t0, t7
+
+ # Mask the flags against sf_mask and leave RF turned off.
+ rdval t3, sf_mask, dataSize=8
+ xor t3, t3, t1, dataSize=8
+ and t3, t3, r11, dataSize=8
+ wrflags t3, t0
+};
+
+def macroop SYSCALL_COMPAT
+{
+ # All 1s.
+ limm t1, "(uint64_t)(-1)"
+
+ # Save the next RIP.
+ rdip rcx
+
+ # Stick rflags with RF masked into r11.
+ rflags t2
+ limm t3, "~RFBit"
+ andi r11, t2, t3, dataSize=8
+
+ rdval t3, star
+ srli t3, t3, 32, dataSize=8
+ andi t3, t3, 0xFC, dataSize=1
+
+ # Set up CS.
+ wrsel cs, t3
+ wrbase cs, t0, dataSize=8
+ wrlimit cs, t1, dataSize=4
+ # Not writable, read/execute-able, not expandDown,
+ # dpl=0, defaultSize=0, long mode
+ limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+ (0 << 3) | (0 << 5) | (1 << 6))
+ wrattr cs, t4
+
+ # Set up SS.
+ addi t3, t3, 8
+ wrsel ss, t3
+ wrbase ss, t0, dataSize=8
+ wrlimit ss, t1, dataSize=4
+ # Writable, readable, not expandDown,
+ # dpl=0, defaultSize=0, not long mode
+ limm t4, ((1 << 0) | (1 << 1) | (0 << 2) | \
+ (0 << 3) | (0 << 5) | (0 << 6))
+ wrattr ss, t4
+
+ # Set the new rip.
+ rdval t7, cstar
+ wrip t0, t7
+
+ # Mask the flags against sf_mask and leave RF turned off.
+ rdval t3, sf_mask, dataSize=8
+ xor t3, t3, t1, dataSize=8
+ and t3, t3, r11, dataSize=8
+ wrflags t3, t0
+};
+
+def macroop SYSCALL_LEGACY
+{
+ panic "The syscall instruction isn't implemented in legacy mode."
+};
+
+def macroop SYSRET_TO_64
+{
+ # All 1s.
+ limm t1, "(uint64_t)(-1)"
+
+ rdval t3, star
+ srli t3, t3, 48, dataSize=8
+ ori t3, t3, 3, dataSize=1
+
+ # Set rflags to r11 with RF and VM cleared.
+ limm t4, "~(RFBit | VMBit)"
+ and t4, t4, r11, dataSize=8
+ wrflags t4, t0
+
+ # Set up CS.
+ addi t4, t3, 16, dataSize=8
+ wrsel cs, t4
+ wrbase cs, t0, dataSize=8
+ wrlimit cs, t1, dataSize=4
+ # Not writable, read/execute-able, not expandDown,
+ # dpl=3, defaultSize=0, long mode
+ limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+ (3 << 3) | (0 << 5) | (1 << 6))
+ wrattr cs, t4
+
+ # Only the selector is changed for SS.
+ addi t4, t3, 8, dataSize=8
+ wrsel ss, t4
+
+ # Set the RIP back.
+ wrip rcx, t0, dataSize=8
+};
+
+def macroop SYSRET_TO_COMPAT
+{
+ # All 1s.
+ limm t1, "(uint64_t)(-1)"
+
+ rdval t3, star
+ srli t3, t3, 48, dataSize=8
+ ori t3, t3, 3, dataSize=1
+
+ # Set rflags to r11 with RF and VM cleared.
+ limm t4, "~(RFBit | VMBit)"
+ and t4, t4, r11, dataSize=8
+ wrflags t4, t0
+
+ # Set up CS.
+ wrsel cs, t3
+ wrbase cs, t0, dataSize=8
+ wrlimit cs, t1, dataSize=4
+ # Not writable, read/execute-able, not expandDown,
+ # dpl=3, defaultSize=1, not long mode
+ limm t4, ((0 << 0) | (1 << 1) | (0 << 2) | \
+ (3 << 3) | (1 << 5) | (0 << 6))
+ wrattr cs, t4
+
+ # Only the selector is changed for SS.
+ addi t4, t3, 8, dataSize=8
+ wrsel ss, t4
+
+ # Set the RIP back.
+ wrip rcx, t0, dataSize=8
+};
+
+def macroop SYSRET_NON_64
+{
+ panic "The sysret instruction isn't implemented in legacy mode."
+};
+'''
#let {{
# class SYSENTER(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
# class SYSEXIT(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class SYSCALL(Inst):
-# "GenFault ${new UnimpInstFault}"
-# class SYSRET(Inst):
-# "GenFault ${new UnimpInstFault}"
+# "GenFault ${new UnimpInstFault}"
#}};
diff --git a/src/arch/x86/isa/insts/romutil.py b/src/arch/x86/isa/insts/romutil.py
new file mode 100644
index 000000000..e47259eb3
--- /dev/null
+++ b/src/arch/x86/isa/insts/romutil.py
@@ -0,0 +1,212 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+intCodeTemplate = '''
+def rom
+{
+ # This vectors the CPU into an interrupt handler in long mode.
+ # On entry, t1 is set to the vector of the interrupt and t7 is the current
+ # ip. We need that because rdip returns the next ip.
+ extern %(startLabel)s:
+
+ #
+ # Get the 64 bit interrupt or trap gate descriptor from the IDT
+ #
+
+ # Load the gate descriptor from the IDT
+ slli t4, t1, 4, dataSize=8
+ ld t2, idtr, [1, t0, t4], 8, dataSize=8, addressSize=8, atCPL0=True
+ ld t4, idtr, [1, t0, t4], dataSize=8, addressSize=8, atCPL0=True
+
+ # Make sure the descriptor is a legal gate.
+ chks t1, t4, %(gateCheckType)s
+
+ #
+ # Get the target CS descriptor using the selector in the gate
+ # descriptor.
+ #
+ srli t10, t4, 16, dataSize=8
+ andi t5, t10, 0xF8, dataSize=8
+ andi t0, t10, 0x4, flags=(EZF,), dataSize=2
+ br rom_local_label("%(startLabel)s_globalDescriptor"), flags=(CEZF,)
+ ld t3, tsl, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True
+ br rom_local_label("%(startLabel)s_processDescriptor")
+%(startLabel)s_globalDescriptor:
+ ld t3, tsg, [1, t0, t5], dataSize=8, addressSize=8, atCPL0=True
+%(startLabel)s_processDescriptor:
+ chks t10, t3, IntCSCheck, dataSize=8
+ wrdl hs, t3, t10, dataSize=8
+
+ # Stick the target offset in t9.
+ wrdh t9, t4, t2, dataSize=8
+
+
+ #
+ # Figure out where the stack should be
+ #
+
+ # Record what we might set the stack selector to.
+ rdsel t11, ss
+
+ # Check if we're changing privelege level. At this point we can assume
+ # we're going to a DPL that's less than or equal to the CPL.
+ rdattr t10, hs, dataSize=8
+ srli t10, t10, 3, dataSize=8
+ andi t10, t10, 3, dataSize=8
+ rdattr t5, cs, dataSize=8
+ srli t5, t5, 3, dataSize=8
+ andi t5, t5, 0x3, dataSize=8
+ sub t0, t5, t10, flags=(EZF,), dataSize=8
+ # We're going to change priviledge, so zero out the stack selector. We
+ # need to let the IST have priority so we don't branch yet.
+ wrsel t11, t0, flags=(nCEZF,)
+
+ # Check the IST field of the gate descriptor
+ srli t12, t4, 32, dataSize=8
+ andi t12, t12, 0x7, dataSize=8
+ subi t0, t12, 1, flags=(ECF,), dataSize=8
+ br rom_local_label("%(startLabel)s_istStackSwitch"), flags=(nCECF,)
+ br rom_local_label("%(startLabel)s_cplStackSwitch"), flags=(nCEZF,)
+
+ # If we're here, it's because the stack isn't being switched.
+ # Set t6 to the new aligned rsp.
+ mov t6, t6, rsp, dataSize=8
+ br rom_local_label("%(startLabel)s_stackSwitched")
+
+%(startLabel)s_istStackSwitch:
+ ld t6, tr, [8, t12, t0], 0x1c, dataSize=8, addressSize=8, atCPL0=True
+ br rom_local_label("%(startLabel)s_stackSwitched")
+
+%(startLabel)s_cplStackSwitch:
+ # Get the new rsp from the TSS
+ ld t6, tr, [8, t10, t0], 4, dataSize=8, addressSize=8, atCPL0=True
+
+%(startLabel)s_stackSwitched:
+
+ andi t6, t6, 0xF0, dataSize=1
+ subi t6, t6, 40 + %(errorCodeSize)d, dataSize=8
+
+ ##
+ ## Point of no return.
+ ## We're now going to irrevocably modify visible state.
+ ## Anything bad that's going to happen should have happened by now or will
+ ## happen right now.
+ ##
+ wrip t0, t9, dataSize=8
+
+ #
+ # Set up the target code segment. Do this now so we have the right
+ # permissions when setting up the stack frame.
+ #
+ srli t5, t4, 16, dataSize=8
+ andi t5, t5, 0xFF, dataSize=8
+ wrdl cs, t3, t5, dataSize=8
+ # Tuck away the old CS for use below
+ limm t10, 0, dataSize=8
+ rdsel t10, cs, dataSize=2
+ wrsel cs, t5, dataSize=2
+
+ # Check that we can access everything we need to on the stack
+ ldst t0, hs, [1, t0, t6], dataSize=8, addressSize=8
+ ldst t0, hs, [1, t0, t6], \
+ 32 + %(errorCodeSize)d, dataSize=8, addressSize=8
+
+
+ #
+ # Build up the interrupt stack frame
+ #
+
+
+ # Write out the contents of memory
+ %(errorCodeCode)s
+ st t7, hs, [1, t0, t6], %(errorCodeSize)d, dataSize=8, addressSize=8
+ st t10, hs, [1, t0, t6], 8 + %(errorCodeSize)d, dataSize=8, addressSize=8
+ rflags t10, dataSize=8
+ st t10, hs, [1, t0, t6], 16 + %(errorCodeSize)d, dataSize=8, addressSize=8
+ st rsp, hs, [1, t0, t6], 24 + %(errorCodeSize)d, dataSize=8, addressSize=8
+ rdsel t5, ss, dataSize=2
+ st t5, hs, [1, t0, t6], 32 + %(errorCodeSize)d, dataSize=8, addressSize=8
+
+ # Set the stack segment
+ mov rsp, rsp, t6, dataSize=8
+ wrsel ss, t11, dataSize=2
+
+ #
+ # Adjust rflags which is still in t10 from above
+ #
+
+ # Set IF to the lowest bit of the original gate type.
+ # The type field of the original gate starts at bit 40.
+
+ # Set the TF, NT, and RF bits. We'll flip them at the end.
+ limm t6, (1 << 8) | (1 << 14) | (1 << 16)
+ or t10, t10, t6
+ srli t5, t4, 40, dataSize=8
+ srli t7, t10, 9, dataSize=8
+ xor t5, t7, t5, dataSize=8
+ andi t5, t5, 1, dataSize=8
+ slli t5, t5, 9, dataSize=8
+ or t6, t5, t6, dataSize=8
+
+ # Put the results into rflags
+ wrflags t6, t10
+
+ eret
+};
+'''
+
+microcode = \
+intCodeTemplate % {\
+ "startLabel" : "longModeInterrupt",
+ "gateCheckType" : "IntGateCheck",
+ "errorCodeSize" : 0,
+ "errorCodeCode" : ""
+} + \
+intCodeTemplate % {\
+ "startLabel" : "longModeSoftInterrupt",
+ "gateCheckType" : "SoftIntGateCheck",
+ "errorCodeSize" : 0,
+ "errorCodeCode" : ""
+} + \
+intCodeTemplate % {\
+ "startLabel" : "longModeInterruptWithError",
+ "gateCheckType" : "IntGateCheck",
+ "errorCodeSize" : 8,
+ "errorCodeCode" : '''
+ st t15, hs, [1, t0, t6], dataSize=8, addressSize=8
+ '''
+} + \
+'''
+def rom
+{
+ # This vectors the CPU into an interrupt handler in legacy mode.
+ extern legacyModeInterrupt:
+ panic "Legacy mode interrupts not implemented (in microcode)"
+ eret
+};
+'''
diff --git a/src/arch/x86/isa/insts/system/__init__.py b/src/arch/x86/isa/insts/system/__init__.py
index 409a929f5..0dec9ebda 100644
--- a/src/arch/x86/isa/insts/system/__init__.py
+++ b/src/arch/x86/isa/insts/system/__init__.py
@@ -81,7 +81,8 @@
#
# Authors: Gabe Black
-categories = ["halt",
+categories = ["control_registers",
+ "halt",
"invlpg",
"undefined_operation",
"msrs",
diff --git a/src/arch/x86/isa/insts/system/control_registers.py b/src/arch/x86/isa/insts/system/control_registers.py
new file mode 100644
index 000000000..902c01abb
--- /dev/null
+++ b/src/arch/x86/isa/insts/system/control_registers.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2009 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+microcode = '''
+def macroop CLTS {
+ rdcr t1, 0, dataSize=8
+ andi t1, t1, 0xF7, dataSize=1
+ wrcr 0, t1, dataSize=8
+};
+'''
diff --git a/src/arch/x86/isa/insts/system/msrs.py b/src/arch/x86/isa/insts/system/msrs.py
index 1acb4c792..7f283c8c1 100644
--- a/src/arch/x86/isa/insts/system/msrs.py
+++ b/src/arch/x86/isa/insts/system/msrs.py
@@ -84,8 +84,8 @@
microcode = '''
def macroop RDMSR
{
- limm t1, "IntAddrPrefixMSR >> 3"
- ld t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4
+ ld t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \
+ dataSize=8, addressSize=8
mov rax, rax, t2, dataSize=4
srli t2, t2, 32, dataSize=8
mov rdx, rdx, t2, dataSize=4
@@ -93,10 +93,18 @@ def macroop RDMSR
def macroop WRMSR
{
- limm t1, "IntAddrPrefixMSR >> 3"
mov t2, t2, rax, dataSize=4
slli t3, rdx, 32, dataSize=8
or t2, t2, t3, dataSize=8
- st t2, intseg, [8, t1, rcx], dataSize=8, addressSize=4
+ st t2, intseg, [8, rcx, t0], "IntAddrPrefixMSR << 3", \
+ dataSize=8, addressSize=8
+};
+
+def macroop RDTSC
+{
+ rdtsc t1
+ mov rax, rax, t1, dataSize=4
+ srli t1, t1, 32, dataSize=8
+ mov rdx, rdx, t1, dataSize=4
};
'''
diff --git a/src/arch/x86/isa/insts/system/segmentation.py b/src/arch/x86/isa/insts/system/segmentation.py
index 97846f79c..acbca9f6e 100644
--- a/src/arch/x86/isa/insts/system/segmentation.py
+++ b/src/arch/x86/isa/insts/system/segmentation.py
@@ -56,7 +56,7 @@
microcode = '''
def macroop LGDT_M
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
# Get the limit
ld t1, seg, sib, disp, dataSize=2
@@ -68,7 +68,7 @@ def macroop LGDT_M
def macroop LGDT_P
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
rdip t7
# Get the limit
@@ -86,34 +86,34 @@ def macroop LGDT_P
def macroop LGDT_16_M
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
# Get the limit
ld t1, seg, sib, disp, dataSize=2
# Get the base
ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4
- zexti t2, t2, 23
+ zexti t2, t2, 23, dataSize=8
wrbase tsg, t2
wrlimit tsg, t1
};
def macroop LGDT_16_P
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
rdip t7
# Get the limit
ld t1, seg, riprel, disp, dataSize=2
# Get the base
ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4
- zexti t2, t2, 23
+ zexti t2, t2, 23, dataSize=8
wrbase tsg, t2
wrlimit tsg, t1
};
def macroop LIDT_M
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
# Get the limit
ld t1, seg, sib, disp, dataSize=2
@@ -125,7 +125,7 @@ def macroop LIDT_M
def macroop LIDT_P
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
rdip t7
# Get the limit
@@ -143,28 +143,135 @@ def macroop LIDT_P
def macroop LIDT_16_M
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
# Get the limit
ld t1, seg, sib, disp, dataSize=2
# Get the base
ld t2, seg, sib, 'adjustedDisp + 2', dataSize=4
- zexti t2, t2, 23
+ zexti t2, t2, 23, dataSize=8
wrbase idtr, t2
wrlimit idtr, t1
};
def macroop LIDT_16_P
{
- .adjust_env oszForPseudoDesc
+ .adjust_env maxOsz
rdip t7
# Get the limit
ld t1, seg, riprel, disp, dataSize=2
# Get the base
ld t2, seg, riprel, 'adjustedDisp + 2', dataSize=4
- zexti t2, t2, 23
+ zexti t2, t2, 23, dataSize=8
wrbase idtr, t2
wrlimit idtr, t1
};
+
+def macroop LTR_R
+{
+ chks reg, t0, TRCheck
+ limm t4, 0
+ srli t4, reg, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks reg, t1, TSSCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, reg
+ wrbase tr, t3, dataSize=8
+ ori t1, t1, (1 << 9)
+ st t1, tsg, [8, t4, t0], dataSize=8
+};
+
+def macroop LTR_M
+{
+ ld t5, seg, sib, disp, dataSize=2
+ chks t5, t0, TRCheck
+ limm t4, 0
+ srli t4, t5, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks t5, t1, TSSCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, t5
+ wrbase tr, t3, dataSize=8
+ ori t1, t1, (1 << 9)
+ st t1, tsg, [8, t4, t0], dataSize=8
+};
+
+def macroop LTR_P
+{
+ rdip t7
+ ld t5, seg, riprel, disp, dataSize=2
+ chks t5, t0, TRCheck
+ limm t4, 0
+ srli t4, t5, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks t5, t1, TSSCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, t5
+ wrbase tr, t3, dataSize=8
+ ori t1, t1, (1 << 9)
+ st t1, tsg, [8, t4, t0], dataSize=8
+};
+
+def macroop LLDT_R
+{
+ chks reg, t0, InGDTCheck, flags=(EZF,)
+ br label("end"), flags=(CEZF,)
+ limm t4, 0
+ srli t4, reg, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks reg, t1, LDTCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, reg
+ wrbase tr, t3, dataSize=8
+end:
+ fault "NoFault"
+};
+
+def macroop LLDT_M
+{
+ ld t5, seg, sib, disp, dataSize=2
+ chks t5, t0, InGDTCheck, flags=(EZF,)
+ br label("end"), flags=(CEZF,)
+ limm t4, 0
+ srli t4, t5, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks t5, t1, LDTCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, t5
+ wrbase tr, t3, dataSize=8
+end:
+ fault "NoFault"
+};
+
+def macroop LLDT_P
+{
+ rdip t7
+ ld t5, seg, riprel, disp, dataSize=2
+ chks t5, t0, InGDTCheck, flags=(EZF,)
+ br label("end"), flags=(CEZF,)
+ limm t4, 0
+ srli t4, t5, 3, dataSize=2
+ ldst t1, tsg, [8, t4, t0], dataSize=8
+ ld t2, tsg, [8, t4, t0], 8, dataSize=8
+ chks t5, t1, LDTCheck
+ wrdh t3, t1, t2
+ wrdl tr, t1, t5
+ wrbase tr, t3, dataSize=8
+end:
+ fault "NoFault"
+};
+
+def macroop SWAPGS
+{
+ rdval t1, kernel_gs_base, dataSize=8
+ rdbase t2, gs, dataSize=8
+ wrbase gs, t1, dataSize=8
+ wrval kernel_gs_base, t2, dataSize=8
+};
'''
diff --git a/src/arch/x86/isa/macroop.isa b/src/arch/x86/isa/macroop.isa
index 4818b926c..3a836ff68 100644
--- a/src/arch/x86/isa/macroop.isa
+++ b/src/arch/x86/isa/macroop.isa
@@ -72,41 +72,13 @@ def template MacroExecPanic {{
output header {{
// Base class for combinationally generated macroops
- class Macroop : public StaticInst
+ class Macroop : public X86ISA::MacroopBase
{
- protected:
- const uint32_t numMicroops;
-
- //Constructor.
+ public:
Macroop(const char *mnem, ExtMachInst _machInst,
- uint32_t _numMicroops)
- : StaticInst(mnem, _machInst, No_OpClass),
- numMicroops(_numMicroops)
- {
- assert(numMicroops);
- microops = new StaticInstPtr[numMicroops];
- flags[IsMacroop] = true;
- }
-
- ~Macroop()
- {
- delete [] microops;
- }
-
- StaticInstPtr * microops;
-
- StaticInstPtr fetchMicroop(MicroPC microPC)
- {
- assert(microPC < numMicroops);
- return microops[microPC];
- }
-
- std::string generateDisassembly(Addr pc,
- const SymbolTable *symtab) const
- {
- return mnemonic;
- }
-
+ uint32_t _numMicroops, X86ISA::EmulEnv _env)
+ : MacroopBase(mnem, _machInst, _numMicroops, _env)
+ {}
%(MacroExecPanic)s
};
}};
@@ -130,22 +102,42 @@ def template MacroDeclare {{
%(declareLabels)s
public:
// Constructor.
- %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv env);
+ %(class_name)s(ExtMachInst machInst, X86ISA::EmulEnv _env);
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
};
}};
+def template MacroDisassembly {{
+ std::string
+ X86Macroop::%(class_name)s::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream out;
+ out << mnemonic << "\t";
+
+ int regSize = %(regSize)s;
+ %(disassembly)s
+ // Shut up gcc.
+ regSize = regSize;
+ return out.str();
+ }
+}};
+
// Basic instruction class constructor template.
def template MacroConstructor {{
inline X86Macroop::%(class_name)s::%(class_name)s(
- ExtMachInst machInst, EmulEnv env)
- : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s)
+ ExtMachInst machInst, EmulEnv _env)
+ : %(base_class)s("%(mnemonic)s", machInst, %(num_microops)s, _env)
{
%(adjust_env)s;
%(adjust_imm)s;
%(adjust_disp)s;
- %(do_modrm)s;
+ %(init_env)s;
%(constructor)s;
+ const char *macrocodeBlock = "%(class_name)s";
//alloc_microops is the code that sets up the microops
//array in the parent class.
%(alloc_microops)s;
@@ -174,7 +166,7 @@ let {{
}
self.declared = False
self.adjust_env = ""
- self.doModRM = ""
+ self.init_env = ""
self.adjust_imm = '''
uint64_t adjustedImm = IMMEDIATE;
//This is to pacify gcc in case the immediate isn't used.
@@ -186,7 +178,12 @@ let {{
adjustedDisp = adjustedDisp;
'''
def getAllocator(self, env):
- return "new X86Macroop::%s(machInst, %s)" % (self.name, env.getAllocator())
+ return "new X86Macroop::%s(machInst, %s)" % \
+ (self.name, env.getAllocator())
+ def getMnemonic(self):
+ mnemonic = self.name.lower()
+ mnemonic = re.match(r'[^_]*', mnemonic).group(0)
+ return mnemonic
def getDeclaration(self):
#FIXME This first parameter should be the mnemonic. I need to
#write some code which pulls that out
@@ -194,32 +191,46 @@ let {{
for (label, microop) in self.labels.items():
declareLabels += "const static uint64_t label_%s = %d;\n" \
% (label, microop.micropc)
- iop = InstObjParams(self.name, self.name, "Macroop",
+ iop = InstObjParams(self.getMnemonic(), self.name, "Macroop",
{"code" : "",
"declareLabels" : declareLabels
})
return MacroDeclare.subst(iop);
- def getDefinition(self):
+ def getDefinition(self, env):
#FIXME This first parameter should be the mnemonic. I need to
#write some code which pulls that out
numMicroops = len(self.microops)
allocMicroops = ''
micropc = 0
for op in self.microops:
+ isLast = (micropc == numMicroops - 1)
allocMicroops += \
"microops[%d] = %s;\n" % \
- (micropc, op.getAllocator(True, False,
- micropc == 0,
- micropc == numMicroops - 1))
+ (micropc, op.getAllocator(True, not isLast,
+ micropc == 0, isLast))
micropc += 1
- iop = InstObjParams(self.name, self.name, "Macroop",
+ if env.useStackSize:
+ useStackSize = "true"
+ else:
+ useStackSize = "false"
+ if env.memoryInst:
+ memoryInst = "true"
+ else:
+ memoryInst = "false"
+ regSize = '''(%s || (env.base == INTREG_RSP && %s) ?
+ env.stackSize :
+ env.dataSize)''' % (useStackSize, memoryInst)
+ iop = InstObjParams(self.getMnemonic(), self.name, "Macroop",
{"code" : "", "num_microops" : numMicroops,
"alloc_microops" : allocMicroops,
"adjust_env" : self.adjust_env,
"adjust_imm" : self.adjust_imm,
"adjust_disp" : self.adjust_disp,
- "do_modrm" : self.doModRM})
- return MacroConstructor.subst(iop);
+ "disassembly" : env.disassembly,
+ "regSize" : regSize,
+ "init_env" : self.initEnv})
+ return MacroConstructor.subst(iop) + \
+ MacroDisassembly.subst(iop);
}};
let {{
@@ -235,6 +246,16 @@ let {{
self.dataSize = "OPSIZE"
self.stackSize = "STACKSIZE"
self.doModRM = False
+ self.disassembly = ""
+ self.firstArgument = True
+ self.useStackSize = False
+ self.memoryInst = False
+
+ def addToDisassembly(self, code):
+ if not self.firstArgument:
+ self.disassembly += "out << \", \";\n"
+ self.firstArgument = False
+ self.disassembly += code
def getAllocator(self):
if self.size == 'b':
@@ -283,6 +304,7 @@ let {{
let {{
doModRMString = "env.doModRM(machInst);\n"
+ noModRMString = "env.setSeg(machInst);\n"
def genMacroop(Name, env):
blocks = OutputBlocks()
if not macroopDict.has_key(Name):
@@ -290,9 +312,11 @@ let {{
macroop = macroopDict[Name]
if not macroop.declared:
if env.doModRM:
- macroop.doModRM = doModRMString
+ macroop.initEnv = doModRMString
+ else:
+ macroop.initEnv = noModRMString
blocks.header_output = macroop.getDeclaration()
- blocks.decoder_output = macroop.getDefinition()
+ blocks.decoder_output = macroop.getDefinition(env)
macroop.declared = True
blocks.decode_block = "return %s;\n" % macroop.getAllocator(env)
return blocks
diff --git a/src/arch/x86/isa/microasm.isa b/src/arch/x86/isa/microasm.isa
index 78ae34f52..c7c6dae2e 100644
--- a/src/arch/x86/isa/microasm.isa
+++ b/src/arch/x86/isa/microasm.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -64,23 +64,32 @@
//Include code to build macroops in both C++ and python.
##include "macroop.isa"
+//Include code to fill out the microcode ROM in both C++ and python.
+##include "rom.isa"
+
let {{
import sys
sys.path[0:0] = ["src/arch/x86/isa/"]
from insts import microcode
# print microcode
- from micro_asm import MicroAssembler, Rom_Macroop, Rom
- mainRom = Rom('main ROM')
+ from micro_asm import MicroAssembler, Rom_Macroop
+ mainRom = X86MicrocodeRom('main ROM')
assembler = MicroAssembler(X86Macroop, microopClasses, mainRom, Rom_Macroop)
# Add in symbols for the microcode registers
- for num in range(15):
+ for num in range(16):
assembler.symbols["t%d" % num] = "NUM_INTREGS+%d" % num
- for num in range(7):
+ for num in range(8):
assembler.symbols["ufp%d" % num] = "FLOATREG_MICROFP(%d)" % num
# Add in symbols for the segment descriptor registers
- for letter in ("C", "D", "E", "F", "G", "S"):
+ for letter in ("C", "D", "E", "F", "G", "H", "S"):
assembler.symbols["%ss" % letter.lower()] = "SEGMENT_REG_%sS" % letter
+ # Add in symbols for the various checks of segment selectors.
+ for check in ("NoCheck", "CSCheck", "CallGateCheck", "IntGateCheck",
+ "SoftIntGateCheck", "SSCheck", "IretCheck", "IntCSCheck",
+ "TRCheck", "TSSCheck", "InGDTCheck", "LDTCheck"):
+ assembler.symbols[check] = "Seg%s" % check
+
for reg in ("TR", "IDTR"):
assembler.symbols[reg.lower()] = "SYS_SEGMENT_REG_%s" % reg
@@ -129,13 +138,15 @@ let {{
# like the internal segment above
assembler.symbols["flatseg"] = "SEGMENT_REG_LS"
- for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di'):
+ for reg in ('ax', 'bx', 'cx', 'dx', 'sp', 'bp', 'si', 'di', \
+ '8', '9', '10', '11', '12', '13', '14', '15'):
assembler.symbols["r%s" % reg] = "INTREG_R%s" % reg.upper()
- for reg in range(15):
+ for reg in range(16):
assembler.symbols["cr%d" % reg] = "MISCREG_CR%d" % reg
- for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF'):
+ for flag in ('CF', 'PF', 'ECF', 'AF', 'EZF', 'ZF', 'SF', 'OF', \
+ 'TF', 'IF', 'NT', 'RF', 'VM', 'AC', 'VIF', 'VIP', 'ID'):
assembler.symbols[flag] = flag + "Bit"
for cond in ('True', 'False', 'ECF', 'EZF', 'SZnZF',
@@ -150,6 +161,11 @@ let {{
assembler.symbols["CTrue"] = "ConditionTests::True"
assembler.symbols["CFalse"] = "ConditionTests::False"
+ for reg in ('sysenter_cs', 'sysenter_esp', 'sysenter_eip',
+ 'star', 'lstar', 'cstar', 'sf_mask',
+ 'kernel_gs_base'):
+ assembler.symbols[reg] = "MISCREG_%s" % reg.upper()
+
# Code literal which forces a default 64 bit operand size in 64 bit mode.
assembler.symbols["oszIn64Override"] = '''
if (machInst.mode.submode == SixtyFourBitMode &&
@@ -157,7 +173,7 @@ let {{
env.dataSize = 8;
'''
- assembler.symbols["oszForPseudoDesc"] = '''
+ assembler.symbols["maxOsz"] = '''
if (machInst.mode.submode == SixtyFourBitMode)
env.dataSize = 8;
else
@@ -174,10 +190,23 @@ let {{
assembler.symbols["label"] = labeler
+ def rom_labeler(labelStr):
+ return "romMicroPC(RomLabels::extern_label_%s)" % labelStr
+
+ assembler.symbols["rom_label"] = rom_labeler
+
+ def rom_local_labeler(labelStr):
+ return "romMicroPC(RomLabels::label_%s)" % labelStr
+
+ assembler.symbols["rom_local_label"] = rom_local_labeler
+
def stack_index(index):
return "(NUM_FLOATREGS + (((%s) + 8) %% 8))" % index
assembler.symbols["st"] = stack_index
macroopDict = assembler.assemble(microcode)
+
+ decoder_output += mainRom.getDefinition()
+ header_output += mainRom.getDeclaration()
}};
diff --git a/src/arch/x86/isa/microops/base.isa b/src/arch/x86/isa/microops/base.isa
index 75658a26c..f1007bf71 100644
--- a/src/arch/x86/isa/microops/base.isa
+++ b/src/arch/x86/isa/microops/base.isa
@@ -69,6 +69,29 @@ let {{
let {{
class X86Microop(object):
+
+ generatorNameTemplate = "generate_%s_%d"
+
+ generatorTemplate = '''
+ StaticInstPtr
+ ''' + generatorNameTemplate + '''(StaticInstPtr curMacroop)
+ {
+ static const char *macrocodeBlock = romMnemonic;
+ static const ExtMachInst dummyExtMachInst;
+ static const EmulEnv dummyEmulEnv(0, 0, 1, 1, 1);
+
+ Macroop * macroop = dynamic_cast<Macroop *>(curMacroop.get());
+ const ExtMachInst &machInst =
+ macroop ? macroop->getExtMachInst() : dummyExtMachInst;
+ const EmulEnv &env =
+ macroop ? macroop->getEmulEnv() : dummyEmulEnv;
+ // env may not be used in the microop's constructor.
+ RegIndex reg = env.reg;
+ reg = reg;
+ using namespace RomLabels;
+ return %s;
+ }
+ '''
def __init__(self, name):
self.name = name
@@ -91,4 +114,12 @@ let {{
def getAllocator(self, mnemonic, *microFlags):
return 'new %s(machInst, %s)' % \
(self.className, mnemonic, self.microFlagsText(microFlags))
+
+ def getGeneratorDef(self, micropc):
+ return self.generatorTemplate % \
+ (self.className, micropc, \
+ self.getAllocator(True, True, False, False))
+
+ def getGenerator(self, micropc):
+ return self.generatorNameTemplate % (self.className, micropc)
}};
diff --git a/src/arch/x86/isa/microops/debug.isa b/src/arch/x86/isa/microops/debug.isa
new file mode 100644
index 000000000..38fee59bb
--- /dev/null
+++ b/src/arch/x86/isa/microops/debug.isa
@@ -0,0 +1,229 @@
+// Copyright (c) 2008 The Hewlett-Packard Development Company
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the
+// following conditions are met:
+//
+// The software must be used only for Non-Commercial Use which means any
+// use which is NOT directed to receiving any direct monetary
+// compensation for, or commercial advantage from such use. Illustrative
+// examples of non-commercial use are academic research, personal study,
+// teaching, education and corporate research & development.
+// Illustrative examples of commercial use are distributing products for
+// commercial advantage and providing services using the software for
+// commercial advantage.
+//
+// If you wish to use this software or functionality therein that may be
+// covered by patents for commercial use, please contact:
+// Director of Intellectual Property Licensing
+// Office of Strategy and Technology
+// Hewlett-Packard Company
+// 1501 Page Mill Road
+// Palo Alto, California 94304
+//
+// Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer. Redistributions
+// in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution. Neither the name of
+// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission. No right of
+// sublicense is granted herewith. Derivatives of the software and
+// output created using the software may be prepared, but only for
+// Non-Commercial Uses. Derivatives of the software may be shared with
+// others provided: (i) the others agree to abide by the list of
+// conditions herein which includes the Non-Commercial Use restrictions;
+// and (ii) such Derivatives of the software include the above copyright
+// notice to acknowledge the contribution from this software where
+// applicable, this list of conditions and the disclaimer below.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Debug Microops
+//
+//////////////////////////////////////////////////////////////////////////
+
+output header {{
+ class MicroDebugBase : public X86ISA::X86MicroopBase
+ {
+ protected:
+ std::string message;
+ uint8_t cc;
+
+ public:
+ MicroDebugBase(ExtMachInst _machInst, const char * mnem,
+ const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ std::string _message, uint8_t _cc);
+
+ MicroDebugBase(ExtMachInst _machInst, const char * mnem,
+ const char * instMnem, std::string _message, uint8_t _cc);
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+}};
+
+def template MicroDebugDeclare {{
+ class %(class_name)s : public %(base_class)s
+ {
+ private:
+ void buildMe();
+ public:
+ %(class_name)s(ExtMachInst _machInst, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ std::string _message, uint8_t _cc);
+
+ %(class_name)s(ExtMachInst _machInst, const char * instMnem,
+ std::string _message, uint8_t _cc);
+
+ %(BasicExecDeclare)s
+ };
+}};
+
+def template MicroDebugExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ %(op_decl)s
+ %(op_rd)s
+ if (%(cond_test)s) {
+ %(func)s("%s\n", message);
+ }
+ return NoFault;
+ }
+}};
+
+output decoder {{
+ inline MicroDebugBase::MicroDebugBase(
+ ExtMachInst machInst, const char * mnem, const char * instMnem,
+ std::string _message, uint8_t _cc) :
+ X86MicroopBase(machInst, mnem, instMnem,
+ false, false, false, false, No_OpClass),
+ message(_message), cc(_cc)
+ {
+ }
+
+ inline MicroDebugBase::MicroDebugBase(
+ ExtMachInst machInst, const char * mnem, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ std::string _message, uint8_t _cc) :
+ X86MicroopBase(machInst, mnem, instMnem,
+ isMicro, isDelayed, isFirst, isLast, No_OpClass),
+ message(_message), cc(_cc)
+ {
+ }
+}};
+
+def template MicroDebugConstructor {{
+
+ inline void %(class_name)s::buildMe()
+ {
+ %(constructor)s;
+ }
+
+ inline %(class_name)s::%(class_name)s(
+ ExtMachInst machInst, const char * instMnem,
+ std::string _message, uint8_t _cc) :
+ %(base_class)s(machInst, "%(func)s", instMnem, _message, _cc)
+ {
+ buildMe();
+ }
+
+ inline %(class_name)s::%(class_name)s(
+ ExtMachInst machInst, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ std::string _message, uint8_t _cc) :
+ %(base_class)s(machInst, "%(func)s", instMnem,
+ isMicro, isDelayed, isFirst, isLast, _message, _cc)
+ {
+ buildMe();
+ }
+}};
+
+output decoder {{
+ std::string MicroDebugBase::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, instMnem, mnemonic);
+ response << "\"" << message << "\"";
+
+ return response.str();
+ }
+}};
+
+let {{
+ class MicroDebug(X86Microop):
+ def __init__(self, message, flags=None):
+ self.message = message
+ if flags:
+ if not isinstance(flags, (list, tuple)):
+ raise Exception, "flags must be a list or tuple of flags"
+ self.cond = " | ".join(flags)
+ self.className += "Flags"
+ else:
+ self.cond = "0"
+
+ def getAllocator(self, *microFlags):
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
+ %(flags)s, "%(message)s", %(cc)s)''' % {
+ "class_name" : self.className,
+ "flags" : self.microFlagsText(microFlags),
+ "message" : self.message,
+ "cc" : self.cond}
+ return allocator
+
+ exec_output = ""
+ header_output = ""
+ decoder_output = ""
+
+ def buildDebugMicro(func):
+ global exec_output, header_output, decoder_output
+
+ iop = InstObjParams(func, "Micro%sFlags" % func.capitalize(),
+ "MicroDebugBase",
+ {"code": "",
+ "func": func,
+ "cond_test": "checkCondition(ccFlagBits, cc)"})
+ exec_output += MicroDebugExecute.subst(iop)
+ header_output += MicroDebugDeclare.subst(iop)
+ decoder_output += MicroDebugConstructor.subst(iop)
+
+ iop = InstObjParams(func, "Micro%s" % func.capitalize(),
+ "MicroDebugBase",
+ {"code": "",
+ "func": func,
+ "cond_test": "true"})
+ exec_output += MicroDebugExecute.subst(iop)
+ header_output += MicroDebugDeclare.subst(iop)
+ decoder_output += MicroDebugConstructor.subst(iop)
+
+ class MicroDebugChild(MicroDebug):
+ className = "Micro%s" % func.capitalize()
+
+ global microopClasses
+ microopClasses[func] = MicroDebugChild
+
+ buildDebugMicro("panic")
+ buildDebugMicro("fatal")
+ buildDebugMicro("warn")
+ buildDebugMicro("warn_once")
+}};
diff --git a/src/arch/x86/isa/microops/fpop.isa b/src/arch/x86/isa/microops/fpop.isa
index 2919aa277..d4acfdbf4 100644
--- a/src/arch/x86/isa/microops/fpop.isa
+++ b/src/arch/x86/isa/microops/fpop.isa
@@ -245,7 +245,7 @@ let {{
self.className += "Top"
def getAllocator(self, *microFlags):
- return '''new %(class_name)s(machInst, mnemonic
+ return '''new %(class_name)s(machInst, macrocodeBlock
%(flags)s, %(src1)s, %(src2)s, %(dest)s,
%(dataSize)s, %(spm)d)''' % {
"class_name" : self.className,
diff --git a/src/arch/x86/isa/microops/ldstop.isa b/src/arch/x86/isa/microops/ldstop.isa
index cb63e7cd9..af94cf31e 100644
--- a/src/arch/x86/isa/microops/ldstop.isa
+++ b/src/arch/x86/isa/microops/ldstop.isa
@@ -124,14 +124,16 @@ def template MicroLeaDeclare {{
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize);
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags);
%(class_name)s(ExtMachInst _machInst,
const char * instMnem,
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize);
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags);
%(BasicExecDeclare)s
};
@@ -151,11 +153,13 @@ def template MicroLoadExecute {{
%(ea_code)s;
DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);
- fault = read(xc, EA, Mem, (%(mem_flags)s) | segment);
+ fault = read(xc, EA, Mem, memFlags);
- if(fault == NoFault)
- {
+ if (fault == NoFault) {
%(code)s;
+ } else if (memFlags & Request::PF_EXCLUSIVE) {
+ // For prefetches, ignore any faults/exceptions.
+ return NoFault;
}
if(fault == NoFault)
{
@@ -178,7 +182,7 @@ def template MicroLoadInitiateAcc {{
%(ea_code)s;
DPRINTF(X86, "%s : %s: The address is %#x\n", instMnem, mnemonic, EA);
- fault = read(xc, EA, Mem, (%(mem_flags)s) | segment);
+ fault = read(xc, EA, Mem, memFlags);
return fault;
}
@@ -194,7 +198,7 @@ def template MicroLoadCompleteAcc {{
%(op_decl)s;
%(op_rd)s;
- Mem = pkt->get<typeof(Mem)>();
+ Mem = get(pkt);
%(code)s;
@@ -225,9 +229,10 @@ def template MicroStoreExecute {{
if(fault == NoFault)
{
- fault = write(xc, Mem, EA, (%(mem_flags)s) | segment);
+ fault = write(xc, Mem, EA, memFlags);
if(fault == NoFault)
{
+ %(post_code)s;
%(op_wb)s;
}
}
@@ -252,20 +257,20 @@ def template MicroStoreInitiateAcc {{
if(fault == NoFault)
{
- fault = write(xc, Mem, EA, (%(mem_flags)s) | segment);
- if(fault == NoFault)
- {
- %(op_wb)s;
- }
+ write(xc, Mem, EA, memFlags);
}
return fault;
}
}};
def template MicroStoreCompleteAcc {{
- Fault %(class_name)s::completeAcc(PacketPtr, %(CPU_exec_context)s * xc,
- Trace::InstRecord * traceData) const
+ Fault %(class_name)s::completeAcc(PacketPtr pkt,
+ %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const
{
+ %(op_decl)s;
+ %(op_rd)s;
+ %(complete_code)s;
+ %(op_wb)s;
return NoFault;
}
}};
@@ -295,14 +300,16 @@ def template MicroLdStOpDeclare {{
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize);
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags);
%(class_name)s(ExtMachInst _machInst,
const char * instMnem,
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize);
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags);
%(BasicExecDeclare)s
@@ -324,12 +331,13 @@ def template MicroLdStOpConstructor {{
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize) :
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags) :
%(base_class)s(machInst, "%(mnemonic)s", instMnem,
false, false, false, false,
_scale, _index, _base,
_disp, _segment, _data,
- _dataSize, _addressSize, %(op_class)s)
+ _dataSize, _addressSize, _memFlags, %(op_class)s)
{
buildMe();
}
@@ -340,12 +348,13 @@ def template MicroLdStOpConstructor {{
uint8_t _scale, RegIndex _index, RegIndex _base,
uint64_t _disp, uint8_t _segment,
RegIndex _data,
- uint8_t _dataSize, uint8_t _addressSize) :
+ uint8_t _dataSize, uint8_t _addressSize,
+ Request::FlagsType _memFlags) :
%(base_class)s(machInst, "%(mnemonic)s", instMnem,
isMicro, isDelayed, isFirst, isLast,
_scale, _index, _base,
_disp, _segment, _data,
- _dataSize, _addressSize, %(op_class)s)
+ _dataSize, _addressSize, _memFlags, %(op_class)s)
{
buildMe();
}
@@ -353,26 +362,35 @@ def template MicroLdStOpConstructor {{
let {{
class LdStOp(X86Microop):
- def __init__(self, data, segment, addr, disp, dataSize, addressSize):
+ def __init__(self, data, segment, addr, disp,
+ dataSize, addressSize, baseFlags, atCPL0, prefetch):
self.data = data
[self.scale, self.index, self.base] = addr
self.disp = disp
self.segment = segment
self.dataSize = dataSize
self.addressSize = addressSize
+ self.memFlags = baseFlags
+ if atCPL0:
+ self.memFlags += " | (CPL0FlagBit << FlagShift)"
+ if prefetch:
+ self.memFlags += " | Request::PF_EXCLUSIVE"
+ self.memFlags += " | (machInst.legacy.addr ? " + \
+ "(AddrSizeFlagBit << FlagShift) : 0)"
def getAllocator(self, *microFlags):
- allocator = '''new %(class_name)s(machInst, mnemonic
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
%(flags)s, %(scale)s, %(index)s, %(base)s,
%(disp)s, %(segment)s, %(data)s,
- %(dataSize)s, %(addressSize)s)''' % {
+ %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % {
"class_name" : self.className,
"flags" : self.microFlagsText(microFlags),
"scale" : self.scale, "index" : self.index,
"base" : self.base,
"disp" : self.disp,
"segment" : self.segment, "data" : self.data,
- "dataSize" : self.dataSize, "addressSize" : self.addressSize}
+ "dataSize" : self.dataSize, "addressSize" : self.addressSize,
+ "memFlags" : self.memFlags}
return allocator
}};
@@ -384,9 +402,11 @@ let {{
decoder_output = ""
exec_output = ""
- calculateEA = "EA = SegBase + scale * Index + Base + disp;"
+ calculateEA = '''
+ EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0);
+ '''
- def defineMicroLoadOp(mnemonic, code, mem_flags=0):
+ def defineMicroLoadOp(mnemonic, code, mem_flags="0"):
global header_output
global decoder_output
global exec_output
@@ -397,8 +417,7 @@ let {{
# Build up the all register version of this micro op
iop = InstObjParams(name, Name, 'X86ISA::LdStOp',
{"code": code,
- "ea_code": calculateEA,
- "mem_flags": mem_flags})
+ "ea_code": calculateEA})
header_output += MicroLdStOpDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroLoadExecute.subst(iop)
@@ -407,19 +426,24 @@ let {{
class LoadOp(LdStOp):
def __init__(self, data, segment, addr, disp = 0,
- dataSize="env.dataSize", addressSize="env.addressSize"):
- super(LoadOp, self).__init__(data, segment,
- addr, disp, dataSize, addressSize)
+ dataSize="env.dataSize",
+ addressSize="env.addressSize",
+ atCPL0=False, prefetch=False):
+ super(LoadOp, self).__init__(data, segment, addr,
+ disp, dataSize, addressSize, mem_flags,
+ atCPL0, prefetch)
self.className = Name
self.mnemonic = name
microopClasses[name] = LoadOp
defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);')
- defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', 'StoreCheck')
+ defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);',
+ 'X86ISA::StoreCheck')
defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;')
- def defineMicroStoreOp(mnemonic, code, mem_flags=0):
+ def defineMicroStoreOp(mnemonic, code, \
+ postCode="", completeCode="", mem_flags="0"):
global header_output
global decoder_output
global exec_output
@@ -430,8 +454,9 @@ let {{
# Build up the all register version of this micro op
iop = InstObjParams(name, Name, 'X86ISA::LdStOp',
{"code": code,
- "ea_code": calculateEA,
- "mem_flags": mem_flags})
+ "post_code": postCode,
+ "complete_code": completeCode,
+ "ea_code": calculateEA})
header_output += MicroLdStOpDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroStoreExecute.subst(iop)
@@ -440,26 +465,26 @@ let {{
class StoreOp(LdStOp):
def __init__(self, data, segment, addr, disp = 0,
- dataSize="env.dataSize", addressSize="env.addressSize"):
- super(StoreOp, self).__init__(data, segment,
- addr, disp, dataSize, addressSize)
+ dataSize="env.dataSize",
+ addressSize="env.addressSize",
+ atCPL0=False):
+ super(StoreOp, self).__init__(data, segment, addr,
+ disp, dataSize, addressSize, mem_flags, atCPL0, False)
self.className = Name
self.mnemonic = name
microopClasses[name] = StoreOp
- defineMicroStoreOp('St', 'Mem = Data;')
+ defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);')
defineMicroStoreOp('Stfp', 'Mem = FpData.uqw;')
- defineMicroStoreOp('Stupd', '''
- Mem = Data;
- Base = merge(Base, EA - SegBase, addressSize);
- ''');
-
+ defineMicroStoreOp('Stupd', 'Mem = pick(Data, 2, dataSize);',
+ 'Base = merge(Base, EA - SegBase, addressSize);',
+ 'Base = merge(Base, pkt->req->getVaddr() - SegBase, addressSize);');
+ defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS")
iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp',
{"code": "Data = merge(Data, EA, dataSize);",
- "ea_code": calculateEA,
- "mem_flags": 0})
+ "ea_code": calculateEA})
header_output += MicroLeaDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroLeaExecute.subst(iop)
@@ -468,7 +493,7 @@ let {{
def __init__(self, data, segment, addr, disp = 0,
dataSize="env.dataSize", addressSize="env.addressSize"):
super(LeaOp, self).__init__(data, segment,
- addr, disp, dataSize, addressSize)
+ addr, disp, dataSize, addressSize, "0", False, False)
self.className = "Lea"
self.mnemonic = "lea"
@@ -477,38 +502,28 @@ let {{
iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp',
{"code": "xc->demapPage(EA, 0);",
- "ea_code": calculateEA,
- "mem_flags": 0})
+ "ea_code": calculateEA})
header_output += MicroLeaDeclare.subst(iop)
decoder_output += MicroLdStOpConstructor.subst(iop)
exec_output += MicroLeaExecute.subst(iop)
class TiaOp(LdStOp):
def __init__(self, segment, addr, disp = 0,
- dataSize="env.dataSize", addressSize="env.addressSize"):
+ dataSize="env.dataSize",
+ addressSize="env.addressSize"):
super(TiaOp, self).__init__("NUM_INTREGS", segment,
- addr, disp, dataSize, addressSize)
+ addr, disp, dataSize, addressSize, "0", False, False)
self.className = "Tia"
self.mnemonic = "tia"
microopClasses["tia"] = TiaOp
- iop = InstObjParams("cda", "Cda", 'X86ISA::LdStOp',
- {"code": '''
- Addr paddr;
- fault = xc->translateDataWriteAddr(EA, paddr,
- dataSize, (1 << segment));
- ''',
- "ea_code": calculateEA})
- header_output += MicroLeaDeclare.subst(iop)
- decoder_output += MicroLdStOpConstructor.subst(iop)
- exec_output += MicroLeaExecute.subst(iop)
-
class CdaOp(LdStOp):
def __init__(self, segment, addr, disp = 0,
- dataSize="env.dataSize", addressSize="env.addressSize"):
+ dataSize="env.dataSize",
+ addressSize="env.addressSize", atCPL0=False):
super(CdaOp, self).__init__("NUM_INTREGS", segment,
- addr, disp, dataSize, addressSize)
+ addr, disp, dataSize, addressSize, "0", atCPL0, False)
self.className = "Cda"
self.mnemonic = "cda"
diff --git a/src/arch/x86/isa/microops/limmop.isa b/src/arch/x86/isa/microops/limmop.isa
index 6686444fd..4e75ab8b0 100644
--- a/src/arch/x86/isa/microops/limmop.isa
+++ b/src/arch/x86/isa/microops/limmop.isa
@@ -154,7 +154,7 @@ let {{
self.dataSize = dataSize
def getAllocator(self, *microFlags):
- allocator = '''new %(class_name)s(machInst, mnemonic
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
%(flags)s, %(dest)s, %(imm)s, %(dataSize)s)''' % {
"class_name" : self.className,
"mnemonic" : self.mnemonic,
diff --git a/src/arch/x86/isa/microops/microops.isa b/src/arch/x86/isa/microops/microops.isa
index 53f34d3f2..19266f6d6 100644
--- a/src/arch/x86/isa/microops/microops.isa
+++ b/src/arch/x86/isa/microops/microops.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -68,5 +68,11 @@
//Load/store microop definitions
##include "ldstop.isa"
+//Control flow microop definitions
+##include "seqop.isa"
+
//Miscellaneous microop definitions
##include "specop.isa"
+
+//Microops for printing out debug messages through M5
+##include "debug.isa"
diff --git a/src/arch/x86/isa/microops/regop.isa b/src/arch/x86/isa/microops/regop.isa
index e761f0034..f9bc82119 100644
--- a/src/arch/x86/isa/microops/regop.isa
+++ b/src/arch/x86/isa/microops/regop.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -231,6 +231,21 @@ output header {{
void
divide(uint64_t dividend, uint64_t divisor,
uint64_t &quotient, uint64_t &remainder);
+
+ enum SegmentSelectorCheck {
+ SegNoCheck, SegCSCheck, SegCallGateCheck, SegIntGateCheck,
+ SegSoftIntGateCheck, SegSSCheck, SegIretCheck, SegIntCSCheck,
+ SegTRCheck, SegTSSCheck, SegInGDTCheck, SegLDTCheck
+ };
+
+ enum LongModeDescriptorType {
+ LDT64 = 2,
+ AvailableTSS64 = 9,
+ BusyTSS64 = 0xb,
+ CallGate64 = 0xc,
+ IntGate64 = 0xe,
+ TrapGate64 = 0xf
+ };
}};
output decoder {{
@@ -424,7 +439,7 @@ let {{
className = self.className
if self.mnemonic == self.base_mnemonic + 'i':
className += "Imm"
- allocator = '''new %(class_name)s(machInst, mnemonic
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
%(flags)s, %(src1)s, %(op2)s, %(dest)s,
%(dataSize)s, %(ext)s)''' % {
"class_name" : className,
@@ -838,19 +853,28 @@ let {{
code = 'RIP = psrc1 + sop2 + CSBase'
else_code="RIP = RIP;"
- class Br(WrRegOp, CondRegOp):
- code = 'nuIP = psrc1 + op2;'
- else_code='nuIP = nuIP;'
-
class Wruflags(WrRegOp):
code = 'ccFlagBits = psrc1 ^ op2'
+ class Wrflags(WrRegOp):
+ code = '''
+ MiscReg newFlags = psrc1 ^ op2;
+ MiscReg userFlagMask = 0xDD5;
+ // Get only the user flags
+ ccFlagBits = newFlags & userFlagMask;
+ // Get everything else
+ nccFlagBits = newFlags & ~userFlagMask;
+ '''
+
class Rdip(RdRegOp):
code = 'DestReg = RIP - CSBase'
class Ruflags(RdRegOp):
code = 'DestReg = ccFlagBits'
+ class Rflags(RdRegOp):
+ code = 'DestReg = ccFlagBits | nccFlagBits'
+
class Ruflag(RegOp):
code = '''
int flag = bits(ccFlagBits, imm8);
@@ -863,6 +887,20 @@ let {{
super(Ruflag, self).__init__(dest, \
"NUM_INTREGS", imm, flags, dataSize)
+ class Rflag(RegOp):
+ code = '''
+ MiscReg flagMask = 0x3F7FDD5;
+ MiscReg flags = (nccFlagBits | ccFlagBits) & flagMask;
+ int flag = bits(flags, imm8);
+ DestReg = merge(DestReg, flag, dataSize);
+ ccFlagBits = (flag == 0) ? (ccFlagBits | EZFBit) :
+ (ccFlagBits & ~EZFBit);
+ '''
+ def __init__(self, dest, imm, flags=None, \
+ dataSize="env.dataSize"):
+ super(Rflag, self).__init__(dest, \
+ "NUM_INTREGS", imm, flags, dataSize)
+
class Sext(RegOp):
code = '''
IntReg val = psrc1;
@@ -883,17 +921,53 @@ let {{
'''
class Zext(RegOp):
- code = 'DestReg = bits(psrc1, op2, 0);'
+ code = 'DestReg = merge(DestReg, bits(psrc1, op2, 0), dataSize);'
+
+ class Rddr(RegOp):
+ def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
+ super(Rddr, self).__init__(dest, \
+ src1, "NUM_INTREGS", flags, dataSize)
+ code = '''
+ CR4 cr4 = CR4Op;
+ DR7 dr7 = DR7Op;
+ if ((cr4.de == 1 && (src1 == 4 || src1 == 5)) || src1 >= 8) {
+ fault = new InvalidOpcode();
+ } else if (dr7.gd) {
+ fault = new DebugException();
+ } else {
+ DestReg = merge(DestReg, DebugSrc1, dataSize);
+ }
+ '''
+
+ class Wrdr(RegOp):
+ def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
+ super(Wrdr, self).__init__(dest, \
+ src1, "NUM_INTREGS", flags, dataSize)
+ code = '''
+ CR4 cr4 = CR4Op;
+ DR7 dr7 = DR7Op;
+ if ((cr4.de == 1 && (dest == 4 || dest == 5)) || dest >= 8) {
+ fault = new InvalidOpcode();
+ } else if ((dest == 6 || dest == 7) &&
+ bits(psrc1, 63, 32) &&
+ machInst.mode.mode == LongMode) {
+ fault = new GeneralProtection(0);
+ } else if (dr7.gd) {
+ fault = new DebugException();
+ } else {
+ DebugDest = psrc1;
+ }
+ '''
class Rdcr(RegOp):
def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
super(Rdcr, self).__init__(dest, \
src1, "NUM_INTREGS", flags, dataSize)
code = '''
- if (dest == 1 || (dest > 4 && dest < 8) || (dest > 8)) {
+ if (src1 == 1 || (src1 > 4 && src1 < 8) || (src1 > 8)) {
fault = new InvalidOpcode();
} else {
- DestReg = ControlSrc1;
+ DestReg = merge(DestReg, ControlSrc1, dataSize);
}
'''
@@ -950,7 +1024,7 @@ let {{
'''
# Microops for manipulating segmentation registers
- class SegOp(RegOp):
+ class SegOp(CondRegOp):
abstract = True
def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
super(SegOp, self).__init__(dest, \
@@ -971,74 +1045,223 @@ let {{
SegSelDest = psrc1;
'''
+ class WrAttr(SegOp):
+ code = '''
+ SegAttrDest = psrc1;
+ '''
+
class Rdbase(SegOp):
code = '''
- DestReg = SegBaseDest;
+ DestReg = merge(DestReg, SegBaseSrc1, dataSize);
'''
class Rdlimit(SegOp):
code = '''
- DestReg = SegLimitSrc1;
+ DestReg = merge(DestReg, SegLimitSrc1, dataSize);
+ '''
+
+ class RdAttr(SegOp):
+ code = '''
+ DestReg = merge(DestReg, SegAttrSrc1, dataSize);
'''
class Rdsel(SegOp):
code = '''
- DestReg = SegSelSrc1;
+ DestReg = merge(DestReg, SegSelSrc1, dataSize);
'''
- class Chks(SegOp):
+ class Rdval(RegOp):
+ def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
+ super(Rdval, self).__init__(dest, \
+ src1, "NUM_INTREGS", flags, dataSize)
code = '''
- // The selector is in source 1.
- SegSelector selector = psrc1;
-
- // Compute the address of the descriptor and set DestReg to it.
- if (selector.ti) {
- // A descriptor in the LDT
- Addr target = (selector.esi << 3) + LDTRBase;
- if (!LDTRSel || (selector.esi << 3) + dataSize > LDTRLimit)
- fault = new GeneralProtection(selector & mask(16));
- DestReg = target;
- } else {
- // A descriptor in the GDT
- Addr target = (selector.esi << 3) + GDTRBase;
- if ((selector.esi << 3) + dataSize > GDTRLimit)
- fault = new GeneralProtection(selector & mask(16));
- DestReg = target;
+ DestReg = MiscRegSrc1;
+ '''
+
+ class Wrval(RegOp):
+ def __init__(self, dest, src1, flags=None, dataSize="env.dataSize"):
+ super(Wrval, self).__init__(dest, \
+ src1, "NUM_INTREGS", flags, dataSize)
+ code = '''
+ MiscRegDest = SrcReg1;
+ '''
+
+ class Chks(RegOp):
+ def __init__(self, dest, src1, src2=0,
+ flags=None, dataSize="env.dataSize"):
+ super(Chks, self).__init__(dest,
+ src1, src2, flags, dataSize)
+ code = '''
+ // The selector is in source 1 and can be at most 16 bits.
+ SegSelector selector = DestReg;
+ SegDescriptor desc = SrcReg1;
+ HandyM5Reg m5reg = M5Reg;
+
+ switch (imm8)
+ {
+ case SegNoCheck:
+ break;
+ case SegCSCheck:
+ panic("CS checks for far calls/jumps not implemented.\\n");
+ break;
+ case SegCallGateCheck:
+ panic("CS checks for far calls/jumps through call gates"
+ "not implemented.\\n");
+ break;
+ case SegSoftIntGateCheck:
+ // Check permissions.
+ if (desc.dpl < m5reg.cpl) {
+ fault = new GeneralProtection(selector);
+ }
+ // Fall through on purpose
+ case SegIntGateCheck:
+ // Make sure the gate's the right type.
+ if ((m5reg.mode == LongMode && (desc.type & 0xe) != 0xe) ||
+ ((desc.type & 0x6) != 0x6)) {
+ fault = new GeneralProtection(0);
+ }
+ break;
+ case SegSSCheck:
+ if (selector.si || selector.ti) {
+ if (!desc.p) {
+ fault = new StackFault(selector);
+ }
+ } else {
+ if ((m5reg.submode != SixtyFourBitMode ||
+ m5reg.cpl == 3) ||
+ !(desc.s == 1 &&
+ desc.type.codeOrData == 0 && desc.type.w) ||
+ (desc.dpl != m5reg.cpl) ||
+ (selector.rpl != m5reg.cpl)) {
+ fault = new GeneralProtection(selector);
+ }
+ }
+ break;
+ case SegIretCheck:
+ {
+ if ((!selector.si && !selector.ti) ||
+ (selector.rpl < m5reg.cpl) ||
+ !(desc.s == 1 && desc.type.codeOrData == 1) ||
+ (!desc.type.c && desc.dpl != selector.rpl) ||
+ (desc.type.c && desc.dpl > selector.rpl)) {
+ fault = new GeneralProtection(selector);
+ } else if (!desc.p) {
+ fault = new SegmentNotPresent(selector);
+ }
+ break;
+ }
+ case SegIntCSCheck:
+ if (m5reg.mode == LongMode) {
+ if (desc.l != 1 || desc.d != 0) {
+ fault = new GeneralProtection(selector);
+ }
+ } else {
+ panic("Interrupt CS checks not implemented "
+ "in legacy mode.\\n");
+ }
+ break;
+ case SegTRCheck:
+ if (!selector.si || selector.ti) {
+ fault = new GeneralProtection(selector);
+ }
+ break;
+ case SegTSSCheck:
+ if (!desc.p) {
+ fault = new SegmentNotPresent(selector);
+ } else if (!(desc.type == 0x9 ||
+ (desc.type == 1 &&
+ m5reg.mode != LongMode))) {
+ fault = new GeneralProtection(selector);
+ }
+ break;
+ case SegInGDTCheck:
+ if (selector.ti) {
+ fault = new GeneralProtection(selector);
+ }
+ break;
+ case SegLDTCheck:
+ if (!desc.p) {
+ fault = new SegmentNotPresent(selector);
+ } else if (desc.type != 0x2) {
+ fault = new GeneralProtection(selector);
+ }
+ break;
+ default:
+ panic("Undefined segment check type.\\n");
}
'''
flag_code = '''
// Check for a NULL selector and set ZF,EZF appropriately.
ccFlagBits = ccFlagBits & ~(ext & (ZFBit | EZFBit));
- if (!selector.esi && !selector.ti)
+ if (!selector.si && !selector.ti)
ccFlagBits = ccFlagBits | (ext & (ZFBit | EZFBit));
'''
class Wrdh(RegOp):
code = '''
+ SegDescriptor desc = SrcReg1;
+
+ uint64_t target = bits(SrcReg2, 31, 0) << 32;
+ switch(desc.type) {
+ case LDT64:
+ case AvailableTSS64:
+ case BusyTSS64:
+ replaceBits(target, 23, 0, desc.baseLow);
+ replaceBits(target, 31, 24, desc.baseHigh);
+ break;
+ case CallGate64:
+ case IntGate64:
+ case TrapGate64:
+ replaceBits(target, 15, 0, bits(desc, 15, 0));
+ replaceBits(target, 31, 16, bits(desc, 63, 48));
+ break;
+ default:
+ panic("Wrdh used with wrong descriptor type!\\n");
+ }
+ DestReg = target;
+ '''
+
+ class Wrtsc(WrRegOp):
+ code = '''
+ TscOp = psrc1;
+ '''
+
+ class Rdtsc(RdRegOp):
+ code = '''
+ DestReg = TscOp;
+ '''
+ class Rdm5reg(RdRegOp):
+ code = '''
+ DestReg = M5Reg;
'''
class Wrdl(RegOp):
code = '''
SegDescriptor desc = SrcReg1;
- SegAttr attr = 0;
- attr.dpl = desc.dpl;
- attr.defaultSize = desc.d;
- if (!desc.s) {
- SegBaseDest = SegBaseDest;
- SegLimitDest = SegLimitDest;
- SegAttrDest = SegAttrDest;
- panic("System segment encountered.\\n");
- } else {
- if (!desc.p)
- panic("Segment not present.\\n");
- if (desc.type.codeOrData) {
- attr.readable = desc.type.r;
- attr.longMode = desc.l;
- } else {
- attr.expandDown = desc.type.e;
+ SegSelector selector = SrcReg2;
+ if (selector.si || selector.ti) {
+ SegAttr attr = 0;
+ attr.dpl = desc.dpl;
+ attr.defaultSize = desc.d;
+ if (!desc.s) {
+ // The expand down bit happens to be set for gates.
+ if (desc.type.e) {
+ panic("Gate descriptor encountered.\\n");
+ }
attr.readable = 1;
- attr.writable = desc.type.w;
+ attr.writable = 1;
+ } else {
+ if (!desc.p)
+ panic("Segment not present.\\n");
+ if (desc.type.codeOrData) {
+ attr.readable = desc.type.r;
+ attr.longMode = desc.l;
+ } else {
+ attr.expandDown = desc.type.e;
+ attr.readable = 1;
+ attr.writable = desc.type.w;
+ }
}
Addr base = desc.baseLow | (desc.baseHigh << 24);
Addr limit = desc.limitLow | (desc.limitHigh << 16);
@@ -1047,6 +1270,10 @@ let {{
SegBaseDest = base;
SegLimitDest = limit;
SegAttrDest = attr;
+ } else {
+ SegBaseDest = SegBaseDest;
+ SegLimitDest = SegLimitDest;
+ SegAttrDest = SegAttrDest;
}
'''
}};
diff --git a/src/arch/x86/isa/microops/seqop.isa b/src/arch/x86/isa/microops/seqop.isa
new file mode 100644
index 000000000..332519b87
--- /dev/null
+++ b/src/arch/x86/isa/microops/seqop.isa
@@ -0,0 +1,251 @@
+// Copyright (c) 2008 The Hewlett-Packard Development Company
+// All rights reserved.
+//
+// Redistribution and use of this software in source and binary forms,
+// with or without modification, are permitted provided that the
+// following conditions are met:
+//
+// The software must be used only for Non-Commercial Use which means any
+// use which is NOT directed to receiving any direct monetary
+// compensation for, or commercial advantage from such use. Illustrative
+// examples of non-commercial use are academic research, personal study,
+// teaching, education and corporate research & development.
+// Illustrative examples of commercial use are distributing products for
+// commercial advantage and providing services using the software for
+// commercial advantage.
+//
+// If you wish to use this software or functionality therein that may be
+// covered by patents for commercial use, please contact:
+// Director of Intellectual Property Licensing
+// Office of Strategy and Technology
+// Hewlett-Packard Company
+// 1501 Page Mill Road
+// Palo Alto, California 94304
+//
+// Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer. Redistributions
+// in binary form must reproduce the above copyright notice, this list of
+// conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution. Neither the name of
+// the COPYRIGHT HOLDER(s), HEWLETT-PACKARD COMPANY, nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission. No right of
+// sublicense is granted herewith. Derivatives of the software and
+// output created using the software may be prepared, but only for
+// Non-Commercial Uses. Derivatives of the software may be shared with
+// others provided: (i) the others agree to abide by the list of
+// conditions herein which includes the Non-Commercial Use restrictions;
+// and (ii) such Derivatives of the software include the above copyright
+// notice to acknowledge the contribution from this software where
+// applicable, this list of conditions and the disclaimer below.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+output header {{
+ class SeqOpBase : public X86ISA::X86MicroopBase
+ {
+ protected:
+ uint16_t target;
+ uint8_t cc;
+
+ public:
+ SeqOpBase(ExtMachInst _machInst, const char * instMnem,
+ const char * mnemonic,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ uint16_t _target, uint8_t _cc);
+
+ SeqOpBase(ExtMachInst _machInst, const char * instMnem,
+ const char * mnemonic,
+ uint16_t _target, uint8_t _cc);
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
+ };
+}};
+
+def template SeqOpDeclare {{
+ class %(class_name)s : public %(base_class)s
+ {
+ private:
+ void buildMe();
+ public:
+ %(class_name)s(ExtMachInst _machInst, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ uint16_t _target, uint8_t _cc);
+
+ %(class_name)s(ExtMachInst _machInst, const char * instMnem,
+ uint16_t _target, uint8_t _cc);
+
+ %(BasicExecDeclare)s
+ };
+}};
+
+def template SeqOpExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ %(op_decl)s;
+ %(op_rd)s;
+ if (%(cond_test)s) {
+ %(code)s;
+ } else {
+ %(else_code)s;
+ }
+ %(op_wb)s;
+ return NoFault;
+ }
+}};
+
+output decoder {{
+ inline SeqOpBase::SeqOpBase(
+ ExtMachInst machInst, const char * mnemonic, const char * instMnem,
+ uint16_t _target, uint8_t _cc) :
+ X86MicroopBase(machInst, mnemonic, instMnem,
+ false, false, false, false, No_OpClass),
+ target(_target), cc(_cc)
+ {
+ }
+
+ inline SeqOpBase::SeqOpBase(
+ ExtMachInst machInst, const char * mnemonic, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ uint16_t _target, uint8_t _cc) :
+ X86MicroopBase(machInst, mnemonic, instMnem,
+ isMicro, isDelayed, isFirst, isLast, No_OpClass),
+ target(_target), cc(_cc)
+ {
+ }
+}};
+
+def template SeqOpConstructor {{
+
+ inline void %(class_name)s::buildMe()
+ {
+ %(constructor)s;
+ }
+
+ inline %(class_name)s::%(class_name)s(
+ ExtMachInst machInst, const char * instMnem,
+ uint16_t _target, uint8_t _cc) :
+ %(base_class)s(machInst, "%(mnemonic)s", instMnem, _target, _cc)
+ {
+ buildMe();
+ }
+
+ inline %(class_name)s::%(class_name)s(
+ ExtMachInst machInst, const char * instMnem,
+ bool isMicro, bool isDelayed, bool isFirst, bool isLast,
+ uint16_t _target, uint8_t _cc) :
+ %(base_class)s(machInst, "%(mnemonic)s", instMnem,
+ isMicro, isDelayed, isFirst, isLast, _target, _cc)
+ {
+ buildMe();
+ }
+}};
+
+output decoder {{
+ std::string SeqOpBase::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, instMnem, mnemonic);
+ ccprintf(response, "%#x", target);
+
+ return response.str();
+ }
+}};
+
+let {{
+ class SeqOp(X86Microop):
+ def __init__(self, target, flags=None):
+ self.target = target
+ if flags:
+ if not isinstance(flags, (list, tuple)):
+ raise Exception, "flags must be a list or tuple of flags"
+ self.cond = " | ".join(flags)
+ self.className += "Flags"
+ else:
+ self.cond = "0"
+
+ def getAllocator(self, *microFlags):
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
+ %(flags)s, %(target)s, %(cc)s)''' % {
+ "class_name" : self.className,
+ "flags" : self.microFlagsText(microFlags),
+ "target" : self.target,
+ "cc" : self.cond}
+ return allocator
+
+ class Br(SeqOp):
+ className = "MicroBranch"
+
+ def getAllocator(self, *microFlags):
+ (is_micro, is_delayed, is_first, is_last) = microFlags
+ is_last = False
+ is_delayed = True
+ microFlags = (is_micro, is_delayed, is_first, is_last)
+ return super(Br, self).getAllocator(*microFlags)
+
+ class Eret(SeqOp):
+ target = "normalMicroPC(0)"
+ className = "Eret"
+
+ def __init__(self, flags=None):
+ if flags:
+ if not isinstance(flags, (list, tuple)):
+ raise Exception, "flags must be a list or tuple of flags"
+ self.cond = " | ".join(flags)
+ self.className += "Flags"
+ else:
+ self.cond = "0"
+
+ def getAllocator(self, *microFlags):
+ (is_micro, is_delayed, is_first, is_last) = microFlags
+ is_last = True
+ is_delayed = False
+ microFlags = (is_micro, is_delayed, is_first, is_last)
+ return super(Eret, self).getAllocator(*microFlags)
+
+ iop = InstObjParams("br", "MicroBranchFlags", "SeqOpBase",
+ {"code": "nuIP = target",
+ "else_code": "nuIP = nuIP",
+ "cond_test": "checkCondition(ccFlagBits, cc)"})
+ exec_output += SeqOpExecute.subst(iop)
+ header_output += SeqOpDeclare.subst(iop)
+ decoder_output += SeqOpConstructor.subst(iop)
+ iop = InstObjParams("br", "MicroBranch", "SeqOpBase",
+ {"code": "nuIP = target",
+ "else_code": "nuIP = nuIP",
+ "cond_test": "true"})
+ exec_output += SeqOpExecute.subst(iop)
+ header_output += SeqOpDeclare.subst(iop)
+ decoder_output += SeqOpConstructor.subst(iop)
+ microopClasses["br"] = Br
+
+ iop = InstObjParams("eret", "EretFlags", "SeqOpBase",
+ {"code": "", "else_code": "",
+ "cond_test": "checkCondition(ccFlagBits, cc)"})
+ exec_output += SeqOpExecute.subst(iop)
+ header_output += SeqOpDeclare.subst(iop)
+ decoder_output += SeqOpConstructor.subst(iop)
+ iop = InstObjParams("eret", "Eret", "SeqOpBase",
+ {"code": "", "else_code": "",
+ "cond_test": "true"})
+ exec_output += SeqOpExecute.subst(iop)
+ header_output += SeqOpDeclare.subst(iop)
+ decoder_output += SeqOpConstructor.subst(iop)
+ microopClasses["eret"] = Eret
+}};
diff --git a/src/arch/x86/isa/microops/specop.isa b/src/arch/x86/isa/microops/specop.isa
index 6bcc7ff91..c6e172ef1 100644
--- a/src/arch/x86/isa/microops/specop.isa
+++ b/src/arch/x86/isa/microops/specop.isa
@@ -1,4 +1,4 @@
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -95,6 +95,9 @@ output header {{
}
%(BasicExecDeclare)s
+
+ std::string generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const;
};
}};
@@ -201,6 +204,16 @@ output decoder {{
return response.str();
}
+
+ std::string MicroHalt::generateDisassembly(Addr pc,
+ const SymbolTable *symtab) const
+ {
+ std::stringstream response;
+
+ printMnemonic(response, instMnem, mnemonic);
+
+ return response.str();
+ }
}};
let {{
@@ -217,7 +230,7 @@ let {{
self.cond = "0"
def getAllocator(self, *microFlags):
- allocator = '''new %(class_name)s(machInst, mnemonic
+ allocator = '''new %(class_name)s(machInst, macrocodeBlock
%(flags)s, %(fault)s, %(cc)s)''' % {
"class_name" : self.className,
"flags" : self.microFlagsText(microFlags),
@@ -244,7 +257,7 @@ let {{
pass
def getAllocator(self, *microFlags):
- return "new MicroHalt(machInst, mnemonic %s)" % \
+ return "new MicroHalt(machInst, macrocodeBlock %s)" % \
self.microFlagsText(microFlags)
microopClasses["halt"] = Halt
diff --git a/src/arch/x86/isa/operands.isa b/src/arch/x86/isa/operands.isa
index 9345158e9..ab1e9a851 100644
--- a/src/arch/x86/isa/operands.isa
+++ b/src/arch/x86/isa/operands.isa
@@ -26,7 +26,7 @@
//
// Authors: Gabe Black
-// Copyright (c) 2007 The Hewlett-Packard Development Company
+// Copyright (c) 2007-2008 The Hewlett-Packard Development Company
// All rights reserved.
//
// Redistribution and use of this software in source and binary forms,
@@ -109,7 +109,14 @@ def operands {{
'Quotient': ('IntReg', 'uqw', 'INTREG_IMPLICIT(2)', 'IsInteger', 9),
'Remainder': ('IntReg', 'uqw', 'INTREG_IMPLICIT(3)', 'IsInteger', 10),
'Divisor': ('IntReg', 'uqw', 'INTREG_IMPLICIT(4)', 'IsInteger', 11),
- 'rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12),
+ 'Rax': ('IntReg', 'uqw', '(INTREG_RAX)', 'IsInteger', 12),
+ 'Rbx': ('IntReg', 'uqw', '(INTREG_RBX)', 'IsInteger', 13),
+ 'Rcx': ('IntReg', 'uqw', '(INTREG_RCX)', 'IsInteger', 14),
+ 'Rdx': ('IntReg', 'uqw', '(INTREG_RDX)', 'IsInteger', 15),
+ 'Rsp': ('IntReg', 'uqw', '(INTREG_RSP)', 'IsInteger', 16),
+ 'Rbp': ('IntReg', 'uqw', '(INTREG_RBP)', 'IsInteger', 17),
+ 'Rsi': ('IntReg', 'uqw', '(INTREG_RSI)', 'IsInteger', 18),
+ 'Rdi': ('IntReg', 'uqw', '(INTREG_RDI)', 'IsInteger', 19),
'FpSrcReg1': ('FloatReg', 'df', 'src1', 'IsFloating', 20),
'FpSrcReg2': ('FloatReg', 'df', 'src2', 'IsFloating', 21),
'FpDestReg': ('FloatReg', 'df', 'dest', 'IsFloating', 22),
@@ -117,10 +124,13 @@ def operands {{
'RIP': ('NPC', 'uqw', None, (None, None, 'IsControl'), 50),
'uIP': ('UPC', 'uqw', None, (None, None, 'IsControl'), 51),
'nuIP': ('NUPC', 'uqw', None, (None, None, 'IsControl'), 52),
+ # This holds the condition code portion of the flag register. The
+ # nccFlagBits version holds the rest.
'ccFlagBits': ('IntReg', 'uqw', 'INTREG_PSEUDO(0)', None, 60),
- # The TOP register should needs to be more protected so that later
+ # These register should needs to be more protected so that later
# instructions don't map their indexes with an old value.
- 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 61),
+ 'nccFlagBits': ('ControlReg', 'uqw', 'MISCREG_RFLAGS', None, 61),
+ 'TOP': ('ControlReg', 'ub', 'MISCREG_X87_TOP', None, 62),
# The segment base as used by memory instructions.
'SegBase': ('ControlReg', 'uqw', 'MISCREG_SEG_EFF_BASE(segment)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 70),
@@ -128,23 +138,31 @@ def operands {{
# original instruction.
'ControlDest': ('ControlReg', 'uqw', 'MISCREG_CR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 100),
'ControlSrc1': ('ControlReg', 'uqw', 'MISCREG_CR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 101),
- 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102),
- 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103),
- 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104),
- 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105),
- 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106),
- 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107),
- 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108),
- 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109),
+ 'DebugDest': ('ControlReg', 'uqw', 'MISCREG_DR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 102),
+ 'DebugSrc1': ('ControlReg', 'uqw', 'MISCREG_DR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 103),
+ 'SegBaseDest': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 104),
+ 'SegBaseSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_BASE(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 105),
+ 'SegLimitDest': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 106),
+ 'SegLimitSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_LIMIT(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 107),
+ 'SegSelDest': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 108),
+ 'SegSelSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_SEL(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 109),
+ 'SegAttrDest': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(dest)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 110),
+ 'SegAttrSrc1': ('ControlReg', 'uqw', 'MISCREG_SEG_ATTR(src1)', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 111),
# Operands to access specific control registers directly.
'EferOp': ('ControlReg', 'uqw', 'MISCREG_EFER', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 200),
'CR4Op': ('ControlReg', 'uqw', 'MISCREG_CR4', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 201),
- 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202),
- 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203),
- 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204),
- 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205),
- 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206),
- 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207),
+ 'DR7Op': ('ControlReg', 'uqw', 'MISCREG_DR7', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 202),
+ 'LDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSL_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 203),
+ 'LDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSL_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 204),
+ 'LDTRSel': ('ControlReg', 'uqw', 'MISCREG_TSL', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 205),
+ 'GDTRBase': ('ControlReg', 'uqw', 'MISCREG_TSG_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 206),
+ 'GDTRLimit': ('ControlReg', 'uqw', 'MISCREG_TSG_LIMIT', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 207),
+ 'CSBase': ('ControlReg', 'udw', 'MISCREG_CS_EFF_BASE', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 208),
+ 'CSAttr': ('ControlReg', 'udw', 'MISCREG_CS_ATTR', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 209),
+ 'MiscRegDest': ('ControlReg', 'uqw', 'dest', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 210),
+ 'MiscRegSrc1': ('ControlReg', 'uqw', 'src1', (None, None, ['IsSerializeAfter','IsSerializing','IsNonSpeculative']), 211),
+ 'TscOp': ('ControlReg', 'uqw', 'MISCREG_TSC', (None, None, ['IsSerializeAfter', 'IsSerializing', 'IsNonSpeculative']), 212),
+ 'M5Reg': ('ControlReg', 'uqw', 'MISCREG_M5_REG', (None, None, None), 213),
'Mem': ('Mem', 'uqw', None, ('IsMemRef', 'IsLoad', 'IsStore'), 300)
}};
diff --git a/src/arch/x86/isa/rom.isa b/src/arch/x86/isa/rom.isa
new file mode 100644
index 000000000..7d3eb8670
--- /dev/null
+++ b/src/arch/x86/isa/rom.isa
@@ -0,0 +1,90 @@
+// Copyright (c) 2008 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (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
+
+def template MicroRomConstructor {{
+
+ %(define_generators)s
+ const MicroPC X86ISA::MicrocodeRom::numMicroops = %(num_microops)s;
+
+ X86ISA::MicrocodeRom::MicrocodeRom()
+ {
+ using namespace RomLabels;
+ genFuncs = new GenFunc[numMicroops];
+ %(alloc_generators)s;
+ }
+}};
+
+let {{
+ from micro_asm import Rom
+
+ class X86MicrocodeRom(Rom):
+ def __init__(self, name):
+ super(X86MicrocodeRom, self).__init__(name)
+ self.directives = {}
+
+ def add_microop(self, mnemonic, microop):
+ microop.mnemonic = mnemonic
+ microop.micropc = len(self.microops)
+ self.microops.append(microop)
+
+
+ def getDeclaration(self):
+ declareLabels = "namespace RomLabels {\n"
+ for (label, microop) in self.labels.items():
+ declareLabels += "const static uint64_t label_%s = %d;\n" \
+ % (label, microop.micropc)
+ for (label, microop) in self.externs.items():
+ declareLabels += \
+ "const static MicroPC extern_label_%s = %d;\n" \
+ % (label, microop.micropc)
+ declareLabels += "}\n"
+ return declareLabels;
+
+ def getDefinition(self):
+ numMicroops = len(self.microops)
+ allocGenerators = ''
+ micropc = 0
+ define_generators = '''
+ namespace
+ {
+ static const char romMnemonic[] = "Microcode_ROM";
+ '''
+ for op in self.microops:
+ define_generators += op.getGeneratorDef(micropc)
+ allocGenerators += "genFuncs[%d] = %s;\n" % \
+ (micropc, op.getGenerator(micropc))
+ micropc += 1
+ define_generators += "}\n"
+ iop = InstObjParams(self.name, self.name, "MicrocodeRom",
+ {"code" : "",
+ "define_generators" : define_generators,
+ "num_microops" : numMicroops,
+ "alloc_generators" : allocGenerators
+ })
+ return MicroRomConstructor.subst(iop);
+}};
diff --git a/src/arch/x86/isa/specialize.isa b/src/arch/x86/isa/specialize.isa
index abf734307..b74363470 100644
--- a/src/arch/x86/isa/specialize.isa
+++ b/src/arch/x86/isa/specialize.isa
@@ -86,8 +86,17 @@ let {{
let {{
def doRipRelativeDecode(Name, opTypes, env):
# print "RIPing %s with opTypes %s" % (Name, opTypes)
- normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), copy.copy(env))
- ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), copy.copy(env))
+ env.memoryInst = True
+ normEnv = copy.copy(env)
+ normEnv.addToDisassembly(
+ '''printMem(out, env.seg, env.scale, env.index, env.base,
+ machInst.displacement, env.addressSize, false);''')
+ normBlocks = specializeInst(Name + "_M", copy.copy(opTypes), normEnv)
+ ripEnv = copy.copy(env)
+ ripEnv.addToDisassembly(
+ '''printMem(out, env.seg, 1, 0, 0,
+ machInst.displacement, env.addressSize, true);''')
+ ripBlocks = specializeInst(Name + "_P", copy.copy(opTypes), ripEnv)
blocks = OutputBlocks()
blocks.append(normBlocks)
@@ -138,12 +147,17 @@ let {{
#Figure out what to do with fixed register operands
#This is the index to use, so we should stick it some place.
if opType.reg in ("A", "B", "C", "D"):
- env.addReg("INTREG_R%sX" % opType.reg)
+ regString = "INTREG_R%sX" % opType.reg
else:
- env.addReg("INTREG_R%s" % opType.reg)
+ regString = "INTREG_R%s" % opType.reg
+ env.addReg(regString)
+ env.addToDisassembly(
+ "printReg(out, %s, regSize);\n" % regString)
Name += "_R"
elif opType.tag == "B":
# This refers to registers whose index is encoded as part of the opcode
+ env.addToDisassembly(
+ "printReg(out, %s, regSize);\n" % InstRegIndex)
Name += "_R"
env.addReg(InstRegIndex)
elif opType.tag == "M":
@@ -156,24 +170,34 @@ let {{
elif opType.tag == "C":
# A control register indexed by the "reg" field
env.addReg(ModRMRegIndex)
+ env.addToDisassembly(
+ "ccprintf(out, \"CR%%d\", %s);\n" % ModRMRegIndex)
Name += "_C"
elif opType.tag == "D":
# A debug register indexed by the "reg" field
env.addReg(ModRMRegIndex)
+ env.addToDisassembly(
+ "ccprintf(out, \"DR%%d\", %s);\n" % ModRMRegIndex)
Name += "_D"
elif opType.tag == "S":
# A segment selector register indexed by the "reg" field
env.addReg(ModRMRegIndex)
+ env.addToDisassembly(
+ "printSegment(out, %s);\n" % ModRMRegIndex)
Name += "_S"
elif opType.tag in ("G", "P", "T", "V"):
# Use the "reg" field of the ModRM byte to select the register
env.addReg(ModRMRegIndex)
+ env.addToDisassembly(
+ "printReg(out, %s, regSize);\n" % ModRMRegIndex)
Name += "_R"
elif opType.tag in ("E", "Q", "W"):
# This might refer to memory or to a register. We need to
# divide it up farther.
regEnv = copy.copy(env)
regEnv.addReg(ModRMRMIndex)
+ regEnv.addToDisassembly(
+ "printReg(out, %s, regSize);\n" % ModRMRMIndex)
# This refers to memory. The macroop constructor should set up
# modrm addressing.
memEnv = copy.copy(env)
@@ -183,6 +207,8 @@ let {{
(doRipRelativeDecode, Name, copy.copy(opTypes), memEnv))
elif opType.tag in ("I", "J"):
# Immediates
+ env.addToDisassembly(
+ "ccprintf(out, \"%#x\", machInst.immediate);\n")
Name += "_I"
elif opType.tag == "O":
# Immediate containing a memory offset
@@ -190,10 +216,22 @@ let {{
elif opType.tag in ("PR", "R", "VR"):
# Non register modrm settings should cause an error
env.addReg(ModRMRMIndex)
+ env.addToDisassembly(
+ "printReg(out, %s, regSize);\n" % ModRMRMIndex)
Name += "_R"
elif opType.tag in ("X", "Y"):
# This type of memory addressing is for string instructions.
# They'll use the right index and segment internally.
+ if opType.tag == "X":
+ env.addToDisassembly(
+ '''printMem(out, env.seg,
+ 1, X86ISA::ZeroReg, X86ISA::INTREG_RSI, 0,
+ env.addressSize, false);''')
+ else:
+ env.addToDisassembly(
+ '''printMem(out, SEGMENT_REG_ES,
+ 1, X86ISA::ZeroReg, X86ISA::INTREG_RDI, 0,
+ env.addressSize, false);''')
Name += "_M"
else:
raise Exception, "Unrecognized tag %s." % opType.tag
diff --git a/src/arch/x86/isa_traits.hh b/src/arch/x86/isa_traits.hh
index abb7694ed..d25e0eb70 100644
--- a/src/arch/x86/isa_traits.hh
+++ b/src/arch/x86/isa_traits.hh
@@ -106,19 +106,7 @@ namespace X86ISA
const int StackPointerReg = INTREG_RSP;
//X86 doesn't seem to have a link register
const int ReturnAddressReg = 0;
- const int ReturnValueReg = INTREG_RAX;
const int FramePointerReg = INTREG_RBP;
- const int ArgumentReg[] = {
- INTREG_RDI,
- INTREG_RSI,
- INTREG_RDX,
- //This argument register is r10 for syscalls and rcx for C.
- INTREG_R10W,
- //INTREG_RCX,
- INTREG_R8W,
- INTREG_R9W
- };
- const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
// Some OS syscalls use a second register (rdx) to return a second
// value
diff --git a/src/arch/x86/linux/linux.cc b/src/arch/x86/linux/linux.cc
index 5e8d2de16..41855da59 100644
--- a/src/arch/x86/linux/linux.cc
+++ b/src/arch/x86/linux/linux.cc
@@ -97,3 +97,42 @@ const int X86Linux64::NUM_OPEN_FLAGS =
sizeof(X86Linux64::openFlagTable) /
sizeof(X86Linux64::openFlagTable[0]);
+// open(2) flags translation table
+OpenFlagTransTable X86Linux32::openFlagTable[] = {
+#ifdef _MSC_VER
+ { TGT_O_RDONLY, _O_RDONLY },
+ { TGT_O_WRONLY, _O_WRONLY },
+ { TGT_O_RDWR, _O_RDWR },
+ { TGT_O_APPEND, _O_APPEND },
+ { TGT_O_CREAT, _O_CREAT },
+ { TGT_O_TRUNC, _O_TRUNC },
+ { TGT_O_EXCL, _O_EXCL },
+#ifdef _O_NONBLOCK
+ { TGT_O_NONBLOCK, _O_NONBLOCK },
+#endif
+#ifdef _O_NOCTTY
+ { TGT_O_NOCTTY, _O_NOCTTY },
+#endif
+#ifdef _O_SYNC
+ { TGT_O_SYNC, _O_SYNC },
+#endif
+#else /* !_MSC_VER */
+ { TGT_O_RDONLY, O_RDONLY },
+ { TGT_O_WRONLY, O_WRONLY },
+ { TGT_O_RDWR, O_RDWR },
+ { TGT_O_APPEND, O_APPEND },
+ { TGT_O_CREAT, O_CREAT },
+ { TGT_O_TRUNC, O_TRUNC },
+ { TGT_O_EXCL, O_EXCL },
+ { TGT_O_NONBLOCK, O_NONBLOCK },
+ { TGT_O_NOCTTY, O_NOCTTY },
+#ifdef O_SYNC
+ { TGT_O_SYNC, O_SYNC },
+#endif
+#endif /* _MSC_VER */
+};
+
+const int X86Linux32::NUM_OPEN_FLAGS =
+ sizeof(X86Linux32::openFlagTable) /
+ sizeof(X86Linux32::openFlagTable[0]);
+
diff --git a/src/arch/x86/linux/linux.hh b/src/arch/x86/linux/linux.hh
index 8a78d5320..c2941c769 100644
--- a/src/arch/x86/linux/linux.hh
+++ b/src/arch/x86/linux/linux.hh
@@ -82,26 +82,26 @@ class X86Linux64 : public Linux
uint64_t st_mtime_nsec;
uint64_t st_ctimeX;
uint64_t st_ctime_nsec;
- int64_t __unused[3];
+ int64_t unused0[3];
} tgt_stat64;
static OpenFlagTransTable openFlagTable[];
- 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 = 00004000; //!< O_NONBLOCK
- static const int TGT_O_APPEND = 00002000; //!< O_APPEND
- static const int TGT_O_CREAT = 00000100; //!< O_CREAT
- static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC
- static const int TGT_O_EXCL = 00000200; //!< O_EXCL
- static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY
- static const int TGT_O_SYNC = 00010000; //!< 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 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 = 00004000; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 00002000; //!< O_APPEND
+ static const int TGT_O_CREAT = 00000100; //!< O_CREAT
+ static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC
+ static const int TGT_O_EXCL = 00000200; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 00010000; //!< 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;
@@ -113,4 +113,53 @@ class X86Linux64 : public Linux
} tgt_iovec;
};
+class X86Linux32 : public Linux
+{
+ public:
+
+ typedef struct {
+ uint64_t st_dev;
+ uint8_t __pad0[4];
+ uint32_t __st_ino;
+ uint32_t st_mode;
+ uint32_t st_nlink;
+ uint32_t st_uid;
+ uint32_t st_gid;
+ uint64_t st_rdev;
+ int64_t st_size;
+ uint8_t __pad3[4];
+ uint32_t st_blksize;
+ uint64_t st_blocks;
+ uint32_t st_atimeX;
+ uint32_t st_atime_nsec;
+ uint32_t st_mtimeX;
+ uint32_t st_mtime_nsec;
+ uint32_t st_ctimeX;
+ uint32_t st_ctime_nsec;
+ uint64_t st_ino;
+ } tgt_stat64;
+
+ static OpenFlagTransTable openFlagTable[];
+
+ 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 = 00004000; //!< O_NONBLOCK
+ static const int TGT_O_APPEND = 00002000; //!< O_APPEND
+ static const int TGT_O_CREAT = 00000100; //!< O_CREAT
+ static const int TGT_O_TRUNC = 00001000; //!< O_TRUNC
+ static const int TGT_O_EXCL = 00000200; //!< O_EXCL
+ static const int TGT_O_NOCTTY = 00000400; //!< O_NOCTTY
+ static const int TGT_O_SYNC = 00010000; //!< 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/x86/linux/process.cc b/src/arch/x86/linux/process.cc
index 8beaf150b..da22d9851 100644
--- a/src/arch/x86/linux/process.cc
+++ b/src/arch/x86/linux/process.cc
@@ -64,34 +64,16 @@
#include "kern/linux/linux.hh"
#include "sim/process.hh"
-#include "sim/syscall_emul.hh"
using namespace std;
using namespace X86ISA;
-SyscallDesc*
-X86LinuxProcess::getDesc(int callnum)
-{
- if (callnum < 0 || callnum > Num_Syscall_Descs)
- return NULL;
- return &syscallDescs[callnum];
-}
-
-X86LinuxProcess::X86LinuxProcess(LiveProcessParams * params,
+X86_64LinuxProcess::X86_64LinuxProcess(LiveProcessParams * params,
ObjectFile *objFile)
- : X86LiveProcess(params, objFile),
- Num_Syscall_Descs(273)
+ : X86_64LiveProcess(params, objFile, syscallDescs, 273)
{}
-void X86LinuxProcess::handleTrap(int trapNum, ThreadContext *tc)
-{
- switch(trapNum)
- {
- //This implementation is from SPARC
- case 0x10: //Linux 32 bit syscall trap
- tc->syscall(tc->readIntReg(1));
- break;
- default:
- X86LiveProcess::handleTrap(trapNum, tc);
- }
-}
+I386LinuxProcess::I386LinuxProcess(LiveProcessParams * params,
+ ObjectFile *objFile)
+ : I386LiveProcess(params, objFile, syscallDescs, 324)
+{}
diff --git a/src/arch/x86/linux/process.hh b/src/arch/x86/linux/process.hh
index e224374d4..ca3606ef0 100644
--- a/src/arch/x86/linux/process.hh
+++ b/src/arch/x86/linux/process.hh
@@ -60,26 +60,30 @@
#include "sim/process.hh"
#include "arch/x86/linux/linux.hh"
-#include "arch/x86/syscallreturn.hh"
#include "arch/x86/process.hh"
namespace X86ISA {
-/// A process with emulated x86/Linux syscalls.
-class X86LinuxProcess : public X86LiveProcess
+class X86_64LinuxProcess : public X86_64LiveProcess
{
+ protected:
+ /// Array of syscall descriptors, indexed by call number.
+ static SyscallDesc syscallDescs[];
+
public:
/// Constructor.
- X86LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
+ X86_64LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
+};
+class I386LinuxProcess : public I386LiveProcess
+{
+ protected:
/// Array of syscall descriptors, indexed by call number.
static SyscallDesc syscallDescs[];
- SyscallDesc* getDesc(int callnum);
-
- const int Num_Syscall_Descs;
-
- void handleTrap(int trapNum, ThreadContext *tc);
+ public:
+ /// Constructor.
+ I386LinuxProcess(LiveProcessParams * params, ObjectFile *objFile);
};
} // namespace X86ISA
diff --git a/src/arch/x86/linux/syscalls.cc b/src/arch/x86/linux/syscalls.cc
index ae2ac243b..09235ec94 100644
--- a/src/arch/x86/linux/syscalls.cc
+++ b/src/arch/x86/linux/syscalls.cc
@@ -68,7 +68,7 @@ static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(process->getSyscallArg(tc, 0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -94,8 +94,8 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
};
//First argument is the code, second is the address
- int code = tc->getSyscallArg(0);
- uint64_t addr = tc->getSyscallArg(1);
+ int code = process->getSyscallArg(tc, 0);
+ uint64_t addr = process->getSyscallArg(tc, 1);
uint64_t fsBase, gsBase;
TranslatingPort *p = tc->getMemPort();
switch(code)
@@ -122,7 +122,112 @@ archPrctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
}
}
-SyscallDesc X86LinuxProcess::syscallDescs[] = {
+BitUnion32(UserDescFlags)
+ Bitfield<0> seg_32bit;
+ Bitfield<2, 1> contents;
+ Bitfield<3> read_exec_only;
+ Bitfield<4> limit_in_pages;
+ Bitfield<5> seg_not_present;
+ Bitfield<6> useable;
+EndBitUnion(UserDescFlags)
+
+struct UserDesc32 {
+ uint32_t entry_number;
+ uint32_t base_addr;
+ uint32_t limit;
+ uint32_t flags;
+};
+
+struct UserDesc64 {
+ uint32_t entry_number;
+ uint32_t __padding1;
+ uint64_t base_addr;
+ uint32_t limit;
+ uint32_t flags;
+};
+
+static SyscallReturn
+setThreadArea32Func(SyscallDesc *desc, int callnum,
+ LiveProcess *process, ThreadContext *tc)
+{
+ const int minTLSEntry = 6;
+ const int numTLSEntries = 3;
+ const int maxTLSEntry = minTLSEntry + numTLSEntries - 1;
+
+ X86LiveProcess *x86lp = dynamic_cast<X86LiveProcess *>(process);
+ assert(x86lp);
+
+ assert((maxTLSEntry + 1) * sizeof(uint64_t) <= x86lp->gdtSize());
+
+ TypedBufferArg<UserDesc32> userDesc(process->getSyscallArg(tc, 0));
+ TypedBufferArg<uint64_t>
+ gdt(x86lp->gdtStart() + minTLSEntry * sizeof(uint64_t),
+ numTLSEntries * sizeof(uint64_t));
+
+ if (!userDesc.copyIn(tc->getMemPort()))
+ return -EFAULT;
+
+ if (!gdt.copyIn(tc->getMemPort()))
+ panic("Failed to copy in GDT for %s.\n", desc->name);
+
+ if (userDesc->entry_number == (uint32_t)(-1)) {
+ // Find a free TLS entry.
+ for (int i = 0; i < numTLSEntries; i++) {
+ if (gdt[i] == 0) {
+ userDesc->entry_number = i + minTLSEntry;
+ break;
+ }
+ }
+ // We failed to find one.
+ if (userDesc->entry_number == (uint32_t)(-1))
+ return -ESRCH;
+ }
+
+ int index = userDesc->entry_number;
+
+ if (index < minTLSEntry || index > maxTLSEntry)
+ return -EINVAL;
+
+ index -= minTLSEntry;
+
+ // Build the entry we're going to add.
+ SegDescriptor segDesc = 0;
+ UserDescFlags flags = userDesc->flags;
+
+ segDesc.limitLow = bits(userDesc->limit, 15, 0);
+ segDesc.baseLow = bits(userDesc->base_addr, 23, 0);
+ segDesc.type.a = 1;
+ if (!flags.read_exec_only)
+ segDesc.type.w = 1;
+ if (bits((uint8_t)flags.contents, 0))
+ segDesc.type.e = 1;
+ if (bits((uint8_t)flags.contents, 1))
+ segDesc.type.codeOrData = 1;
+ segDesc.s = 1;
+ segDesc.dpl = 3;
+ if (!flags.seg_not_present)
+ segDesc.p = 1;
+ segDesc.limitHigh = bits(userDesc->limit, 19, 16);
+ if (flags.useable)
+ segDesc.avl = 1;
+ segDesc.l = 0;
+ if (flags.seg_32bit)
+ segDesc.d = 1;
+ if (flags.limit_in_pages)
+ segDesc.g = 1;
+ segDesc.baseHigh = bits(userDesc->base_addr, 31, 24);
+
+ gdt[index] = (uint64_t)segDesc;
+
+ if (!userDesc.copyOut(tc->getMemPort()))
+ return -EFAULT;
+ if (!gdt.copyOut(tc->getMemPort()))
+ panic("Failed to copy out GDT for %s.\n", desc->name);
+
+ return 0;
+}
+
+SyscallDesc X86_64LinuxProcess::syscallDescs[] = {
/* 0 */ SyscallDesc("read", readFunc),
/* 1 */ SyscallDesc("write", writeFunc),
/* 2 */ SyscallDesc("open", openFunc<X86Linux64>),
@@ -135,7 +240,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = {
/* 9 */ SyscallDesc("mmap", mmapFunc<X86Linux64>),
/* 10 */ SyscallDesc("mprotect", unimplementedFunc),
/* 11 */ SyscallDesc("munmap", munmapFunc),
- /* 12 */ SyscallDesc("brk", obreakFunc),
+ /* 12 */ SyscallDesc("brk", brkFunc),
/* 13 */ SyscallDesc("rt_sigaction", unimplementedFunc),
/* 14 */ SyscallDesc("rt_sigprocmask", unimplementedFunc),
/* 15 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
@@ -148,7 +253,7 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = {
/* 22 */ SyscallDesc("pipe", unimplementedFunc),
/* 23 */ SyscallDesc("select", unimplementedFunc),
/* 24 */ SyscallDesc("sched_yield", unimplementedFunc),
- /* 25 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 25 */ SyscallDesc("mremap", mremapFunc<X86Linux64>),
/* 26 */ SyscallDesc("msync", unimplementedFunc),
/* 27 */ SyscallDesc("mincore", unimplementedFunc),
/* 28 */ SyscallDesc("madvise", unimplementedFunc),
@@ -397,3 +502,330 @@ SyscallDesc X86LinuxProcess::syscallDescs[] = {
/* 271 */ SyscallDesc("ppoll", unimplementedFunc),
/* 272 */ SyscallDesc("unshare", unimplementedFunc)
};
+
+SyscallDesc I386LinuxProcess::syscallDescs[] = {
+ /* 0 */ SyscallDesc("restart_syscall", unimplementedFunc),
+ /* 1 */ SyscallDesc("exit", unimplementedFunc),
+ /* 2 */ SyscallDesc("fork", unimplementedFunc),
+ /* 3 */ SyscallDesc("read", unimplementedFunc),
+ /* 4 */ SyscallDesc("write", writeFunc),
+ /* 5 */ SyscallDesc("open", openFunc<X86Linux64>),
+ /* 6 */ SyscallDesc("close", unimplementedFunc),
+ /* 7 */ SyscallDesc("waitpid", unimplementedFunc),
+ /* 8 */ SyscallDesc("creat", unimplementedFunc),
+ /* 9 */ SyscallDesc("link", unimplementedFunc),
+ /* 10 */ SyscallDesc("unlink", unimplementedFunc),
+ /* 11 */ SyscallDesc("execve", unimplementedFunc),
+ /* 12 */ SyscallDesc("chdir", unimplementedFunc),
+ /* 13 */ SyscallDesc("time", unimplementedFunc),
+ /* 14 */ SyscallDesc("mknod", unimplementedFunc),
+ /* 15 */ SyscallDesc("chmod", unimplementedFunc),
+ /* 16 */ SyscallDesc("lchown", unimplementedFunc),
+ /* 17 */ SyscallDesc("break", unimplementedFunc),
+ /* 18 */ SyscallDesc("oldstat", unimplementedFunc),
+ /* 19 */ SyscallDesc("lseek", unimplementedFunc),
+ /* 20 */ SyscallDesc("getpid", unimplementedFunc),
+ /* 21 */ SyscallDesc("mount", unimplementedFunc),
+ /* 22 */ SyscallDesc("umount", unimplementedFunc),
+ /* 23 */ SyscallDesc("setuid", unimplementedFunc),
+ /* 24 */ SyscallDesc("getuid", unimplementedFunc),
+ /* 25 */ SyscallDesc("stime", unimplementedFunc),
+ /* 26 */ SyscallDesc("ptrace", unimplementedFunc),
+ /* 27 */ SyscallDesc("alarm", unimplementedFunc),
+ /* 28 */ SyscallDesc("oldfstat", 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", unimplementedFunc),
+ /* 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", brkFunc),
+ /* 46 */ SyscallDesc("setgid", unimplementedFunc),
+ /* 47 */ SyscallDesc("getgid", unimplementedFunc),
+ /* 48 */ SyscallDesc("signal", unimplementedFunc),
+ /* 49 */ SyscallDesc("geteuid", unimplementedFunc),
+ /* 50 */ SyscallDesc("getegid", unimplementedFunc),
+ /* 51 */ SyscallDesc("acct", unimplementedFunc),
+ /* 52 */ SyscallDesc("umount2", unimplementedFunc),
+ /* 53 */ SyscallDesc("lock", unimplementedFunc),
+ /* 54 */ SyscallDesc("ioctl", unimplementedFunc),
+ /* 55 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 56 */ SyscallDesc("mpx", unimplementedFunc),
+ /* 57 */ SyscallDesc("setpgid", unimplementedFunc),
+ /* 58 */ SyscallDesc("ulimit", unimplementedFunc),
+ /* 59 */ SyscallDesc("oldolduname", unimplementedFunc),
+ /* 60 */ SyscallDesc("umask", unimplementedFunc),
+ /* 61 */ SyscallDesc("chroot", unimplementedFunc),
+ /* 62 */ SyscallDesc("ustat", unimplementedFunc),
+ /* 63 */ SyscallDesc("dup2", unimplementedFunc),
+ /* 64 */ SyscallDesc("getppid", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 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("select", unimplementedFunc),
+ /* 83 */ SyscallDesc("symlink", unimplementedFunc),
+ /* 84 */ SyscallDesc("oldlstat", unimplementedFunc),
+ /* 85 */ SyscallDesc("readlink", unimplementedFunc),
+ /* 86 */ SyscallDesc("uselib", unimplementedFunc),
+ /* 87 */ SyscallDesc("swapon", unimplementedFunc),
+ /* 88 */ SyscallDesc("reboot", unimplementedFunc),
+ /* 89 */ SyscallDesc("readdir", unimplementedFunc),
+ /* 90 */ SyscallDesc("mmap", unimplementedFunc),
+ /* 91 */ SyscallDesc("munmap", unimplementedFunc),
+ /* 92 */ SyscallDesc("truncate", unimplementedFunc),
+ /* 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", unimplementedFunc),
+ /* 107 */ SyscallDesc("lstat", unimplementedFunc),
+ /* 108 */ SyscallDesc("fstat", unimplementedFunc),
+ /* 109 */ SyscallDesc("olduname", unimplementedFunc),
+ /* 110 */ SyscallDesc("iopl", unimplementedFunc),
+ /* 111 */ SyscallDesc("vhangup", unimplementedFunc),
+ /* 112 */ SyscallDesc("idle", unimplementedFunc),
+ /* 113 */ SyscallDesc("vm86old", 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", unimplementedFunc),
+ /* 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),
+ /* 145 */ SyscallDesc("readv", unimplementedFunc),
+ /* 146 */ SyscallDesc("writev", writevFunc<X86Linux32>),
+ /* 147 */ SyscallDesc("getsid", unimplementedFunc),
+ /* 148 */ SyscallDesc("fdatasync", unimplementedFunc),
+ /* 149 */ SyscallDesc("_sysctl", unimplementedFunc),
+ /* 150 */ SyscallDesc("mlock", unimplementedFunc),
+ /* 151 */ SyscallDesc("munlock", unimplementedFunc),
+ /* 152 */ SyscallDesc("mlockall", unimplementedFunc),
+ /* 153 */ SyscallDesc("munlockall", unimplementedFunc),
+ /* 154 */ SyscallDesc("sched_setparam", unimplementedFunc),
+ /* 155 */ SyscallDesc("sched_getparam", unimplementedFunc),
+ /* 156 */ SyscallDesc("sched_setscheduler", unimplementedFunc),
+ /* 157 */ SyscallDesc("sched_getscheduler", unimplementedFunc),
+ /* 158 */ SyscallDesc("sched_yield", unimplementedFunc),
+ /* 159 */ SyscallDesc("sched_get_priority_max", unimplementedFunc),
+ /* 160 */ SyscallDesc("sched_get_priority_min", unimplementedFunc),
+ /* 161 */ SyscallDesc("sched_rr_get_interval", unimplementedFunc),
+ /* 162 */ SyscallDesc("nanosleep", unimplementedFunc),
+ /* 163 */ SyscallDesc("mremap", unimplementedFunc),
+ /* 164 */ SyscallDesc("setresuid", unimplementedFunc),
+ /* 165 */ SyscallDesc("getresuid", unimplementedFunc),
+ /* 166 */ SyscallDesc("vm86", unimplementedFunc),
+ /* 167 */ SyscallDesc("query_module", unimplementedFunc),
+ /* 168 */ SyscallDesc("poll", unimplementedFunc),
+ /* 169 */ SyscallDesc("nfsservctl", unimplementedFunc),
+ /* 170 */ SyscallDesc("setresgid", unimplementedFunc),
+ /* 171 */ SyscallDesc("getresgid", unimplementedFunc),
+ /* 172 */ SyscallDesc("prctl", unimplementedFunc),
+ /* 173 */ SyscallDesc("rt_sigreturn", unimplementedFunc),
+ /* 174 */ SyscallDesc("rt_sigaction", unimplementedFunc),
+ /* 175 */ SyscallDesc("rt_sigprocmask", unimplementedFunc),
+ /* 176 */ SyscallDesc("rt_sigpending", unimplementedFunc),
+ /* 177 */ SyscallDesc("rt_sigtimedwait", unimplementedFunc),
+ /* 178 */ SyscallDesc("rt_sigqueueinfo", unimplementedFunc),
+ /* 179 */ SyscallDesc("rt_sigsuspend", unimplementedFunc),
+ /* 180 */ SyscallDesc("pread64", unimplementedFunc),
+ /* 181 */ SyscallDesc("pwrite64", unimplementedFunc),
+ /* 182 */ SyscallDesc("chown", unimplementedFunc),
+ /* 183 */ SyscallDesc("getcwd", unimplementedFunc),
+ /* 184 */ SyscallDesc("capget", unimplementedFunc),
+ /* 185 */ SyscallDesc("capset", unimplementedFunc),
+ /* 186 */ SyscallDesc("sigaltstack", unimplementedFunc),
+ /* 187 */ SyscallDesc("sendfile", unimplementedFunc),
+ /* 188 */ SyscallDesc("getpmsg", unimplementedFunc),
+ /* 189 */ SyscallDesc("putpmsg", unimplementedFunc),
+ /* 190 */ SyscallDesc("vfork", unimplementedFunc),
+ /* 191 */ SyscallDesc("ugetrlimit", unimplementedFunc),
+ /* 192 */ SyscallDesc("mmap2", mmapFunc<X86Linux32>),
+ /* 193 */ SyscallDesc("truncate64", unimplementedFunc),
+ /* 194 */ SyscallDesc("ftruncate64", unimplementedFunc),
+ /* 195 */ SyscallDesc("stat64", unimplementedFunc),
+ /* 196 */ SyscallDesc("lstat64", unimplementedFunc),
+ /* 197 */ SyscallDesc("fstat64", fstat64Func<X86Linux32>),
+ /* 198 */ SyscallDesc("lchown32", unimplementedFunc),
+ /* 199 */ SyscallDesc("getuid32", unimplementedFunc),
+ /* 200 */ SyscallDesc("getgid32", unimplementedFunc),
+ /* 201 */ SyscallDesc("geteuid32", unimplementedFunc),
+ /* 202 */ SyscallDesc("getegid32", unimplementedFunc),
+ /* 203 */ SyscallDesc("setreuid32", unimplementedFunc),
+ /* 204 */ SyscallDesc("setregid32", unimplementedFunc),
+ /* 205 */ SyscallDesc("getgroups32", unimplementedFunc),
+ /* 206 */ SyscallDesc("setgroups32", unimplementedFunc),
+ /* 207 */ SyscallDesc("fchown32", unimplementedFunc),
+ /* 208 */ SyscallDesc("setresuid32", unimplementedFunc),
+ /* 209 */ SyscallDesc("getresuid32", unimplementedFunc),
+ /* 210 */ SyscallDesc("setresgid32", unimplementedFunc),
+ /* 211 */ SyscallDesc("getresgid32", unimplementedFunc),
+ /* 212 */ SyscallDesc("chown32", unimplementedFunc),
+ /* 213 */ SyscallDesc("setuid32", unimplementedFunc),
+ /* 214 */ SyscallDesc("setgid32", unimplementedFunc),
+ /* 215 */ SyscallDesc("setfsuid32", unimplementedFunc),
+ /* 216 */ SyscallDesc("setfsgid32", unimplementedFunc),
+ /* 217 */ SyscallDesc("pivot_root", unimplementedFunc),
+ /* 218 */ SyscallDesc("mincore", unimplementedFunc),
+ /* 219 */ SyscallDesc("madvise", unimplementedFunc),
+ /* 220 */ SyscallDesc("madvise1", unimplementedFunc),
+ /* 221 */ SyscallDesc("getdents64", unimplementedFunc),
+ /* 222 */ SyscallDesc("fcntl64", unimplementedFunc),
+ /* 223 */ SyscallDesc("unused", unimplementedFunc),
+ /* 224 */ SyscallDesc("gettid", unimplementedFunc),
+ /* 225 */ SyscallDesc("readahead", unimplementedFunc),
+ /* 226 */ SyscallDesc("setxattr", unimplementedFunc),
+ /* 227 */ SyscallDesc("lsetxattr", unimplementedFunc),
+ /* 228 */ SyscallDesc("fsetxattr", unimplementedFunc),
+ /* 229 */ SyscallDesc("getxattr", unimplementedFunc),
+ /* 230 */ SyscallDesc("lgetxattr", unimplementedFunc),
+ /* 231 */ SyscallDesc("fgetxattr", unimplementedFunc),
+ /* 232 */ SyscallDesc("listxattr", unimplementedFunc),
+ /* 233 */ SyscallDesc("llistxattr", unimplementedFunc),
+ /* 234 */ SyscallDesc("flistxattr", unimplementedFunc),
+ /* 235 */ SyscallDesc("removexattr", unimplementedFunc),
+ /* 236 */ SyscallDesc("lremovexattr", unimplementedFunc),
+ /* 237 */ SyscallDesc("fremovexattr", unimplementedFunc),
+ /* 238 */ SyscallDesc("tkill", unimplementedFunc),
+ /* 239 */ SyscallDesc("sendfile64", unimplementedFunc),
+ /* 240 */ SyscallDesc("futex", unimplementedFunc),
+ /* 241 */ SyscallDesc("sched_setaffinity", unimplementedFunc),
+ /* 242 */ SyscallDesc("sched_getaffinity", unimplementedFunc),
+ /* 243 */ SyscallDesc("set_thread_area", setThreadArea32Func),
+ /* 244 */ SyscallDesc("get_thread_area", unimplementedFunc),
+ /* 245 */ SyscallDesc("io_setup", unimplementedFunc),
+ /* 246 */ SyscallDesc("io_destroy", unimplementedFunc),
+ /* 247 */ SyscallDesc("io_getevents", unimplementedFunc),
+ /* 248 */ SyscallDesc("io_submit", unimplementedFunc),
+ /* 249 */ SyscallDesc("io_cancel", unimplementedFunc),
+ /* 250 */ SyscallDesc("fadvise64", unimplementedFunc),
+ /* 251 */ SyscallDesc("unused", unimplementedFunc),
+ /* 252 */ SyscallDesc("exit_group", exitFunc),
+ /* 253 */ SyscallDesc("lookup_dcookie", unimplementedFunc),
+ /* 254 */ SyscallDesc("epoll_create", unimplementedFunc),
+ /* 255 */ SyscallDesc("epoll_ctl", unimplementedFunc),
+ /* 256 */ SyscallDesc("epoll_wait", unimplementedFunc),
+ /* 257 */ SyscallDesc("remap_file_pages", unimplementedFunc),
+ /* 258 */ SyscallDesc("set_tid_address", unimplementedFunc),
+ /* 259 */ SyscallDesc("timer_create", unimplementedFunc),
+ /* 260 */ SyscallDesc("timer_settime", unimplementedFunc),
+ /* 261 */ SyscallDesc("timer_gettime", unimplementedFunc),
+ /* 262 */ SyscallDesc("timer_getoverrun", unimplementedFunc),
+ /* 263 */ SyscallDesc("timer_delete", unimplementedFunc),
+ /* 264 */ SyscallDesc("clock_settime", unimplementedFunc),
+ /* 265 */ SyscallDesc("clock_gettime", unimplementedFunc),
+ /* 266 */ SyscallDesc("clock_getres", unimplementedFunc),
+ /* 267 */ SyscallDesc("clock_nanosleep", unimplementedFunc),
+ /* 268 */ SyscallDesc("statfs64", unimplementedFunc),
+ /* 269 */ SyscallDesc("fstatfs64", unimplementedFunc),
+ /* 270 */ SyscallDesc("tgkill", unimplementedFunc),
+ /* 271 */ SyscallDesc("utimes", unimplementedFunc),
+ /* 272 */ SyscallDesc("fadvise64_64", unimplementedFunc),
+ /* 273 */ SyscallDesc("vserver", unimplementedFunc),
+ /* 274 */ SyscallDesc("mbind", unimplementedFunc),
+ /* 275 */ SyscallDesc("get_mempolicy", unimplementedFunc),
+ /* 276 */ SyscallDesc("set_mempolicy", unimplementedFunc),
+ /* 277 */ SyscallDesc("mq_open", unimplementedFunc),
+ /* 278 */ SyscallDesc("mq_unlink", unimplementedFunc),
+ /* 279 */ SyscallDesc("mq_timedsend", unimplementedFunc),
+ /* 280 */ SyscallDesc("mq_timedreceive", unimplementedFunc),
+ /* 281 */ SyscallDesc("mq_notify", unimplementedFunc),
+ /* 282 */ SyscallDesc("mq_getsetattr", unimplementedFunc),
+ /* 283 */ SyscallDesc("kexec_load", unimplementedFunc),
+ /* 284 */ SyscallDesc("waitid", unimplementedFunc),
+ /* 285 */ SyscallDesc("sys_setaltroot", unimplementedFunc),
+ /* 286 */ SyscallDesc("add_key", unimplementedFunc),
+ /* 287 */ SyscallDesc("request_key", unimplementedFunc),
+ /* 288 */ SyscallDesc("keyctl", unimplementedFunc),
+ /* 289 */ SyscallDesc("ioprio_set", unimplementedFunc),
+ /* 290 */ SyscallDesc("ioprio_get", unimplementedFunc),
+ /* 291 */ SyscallDesc("inotify_init", unimplementedFunc),
+ /* 292 */ SyscallDesc("inotify_add_watch", unimplementedFunc),
+ /* 293 */ SyscallDesc("inotify_rm_watch", unimplementedFunc),
+ /* 294 */ SyscallDesc("migrate_pages", unimplementedFunc),
+ /* 295 */ SyscallDesc("openat", unimplementedFunc),
+ /* 296 */ SyscallDesc("mkdirat", unimplementedFunc),
+ /* 297 */ SyscallDesc("mknodat", unimplementedFunc),
+ /* 298 */ SyscallDesc("fchownat", unimplementedFunc),
+ /* 299 */ SyscallDesc("futimesat", unimplementedFunc),
+ /* 300 */ SyscallDesc("fstatat64", unimplementedFunc),
+ /* 301 */ SyscallDesc("unlinkat", unimplementedFunc),
+ /* 302 */ SyscallDesc("renameat", unimplementedFunc),
+ /* 303 */ SyscallDesc("linkat", unimplementedFunc),
+ /* 304 */ SyscallDesc("symlinkat", unimplementedFunc),
+ /* 305 */ SyscallDesc("readlinkat", unimplementedFunc),
+ /* 306 */ SyscallDesc("fchmodat", unimplementedFunc),
+ /* 307 */ SyscallDesc("faccessat", unimplementedFunc),
+ /* 308 */ SyscallDesc("pselect6", unimplementedFunc),
+ /* 309 */ SyscallDesc("ppoll", unimplementedFunc),
+ /* 310 */ SyscallDesc("unshare", unimplementedFunc),
+ /* 311 */ SyscallDesc("set_robust_list", unimplementedFunc),
+ /* 312 */ SyscallDesc("get_robust_list", unimplementedFunc),
+ /* 313 */ SyscallDesc("splice", unimplementedFunc),
+ /* 314 */ SyscallDesc("sync_file_range", unimplementedFunc),
+ /* 315 */ SyscallDesc("tee", unimplementedFunc),
+ /* 316 */ SyscallDesc("vmsplice", unimplementedFunc),
+ /* 317 */ SyscallDesc("move_pages", unimplementedFunc),
+ /* 318 */ SyscallDesc("getcpu", unimplementedFunc),
+ /* 319 */ SyscallDesc("epoll_pwait", unimplementedFunc),
+ /* 320 */ SyscallDesc("utimensat", unimplementedFunc),
+ /* 321 */ SyscallDesc("signalfd", unimplementedFunc),
+ /* 322 */ SyscallDesc("timerfd", unimplementedFunc),
+ /* 323 */ SyscallDesc("eventfd", unimplementedFunc)
+};
diff --git a/src/arch/x86/linux/system.cc b/src/arch/x86/linux/system.cc
index 944bb2930..c2d9cb35c 100644
--- a/src/arch/x86/linux/system.cc
+++ b/src/arch/x86/linux/system.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -68,7 +68,7 @@ using namespace LittleEndianGuest;
using namespace X86ISA;
LinuxX86System::LinuxX86System(Params *p)
- : X86System(p), commandLine(p->boot_osflags)
+ : X86System(p), commandLine(p->boot_osflags), e820Table(p->e820_table)
{
}
@@ -144,62 +144,7 @@ LinuxX86System::startup()
// A pointer to the buffer for E820 entries.
const Addr e820MapPointer = realModeData + 0x2d0;
- struct e820Entry
- {
- Addr addr;
- Addr size;
- uint32_t type;
- };
-
- // The size is computed this way to ensure no padding sneaks in.
- int e820EntrySize =
- sizeof(e820Entry().addr) +
- sizeof(e820Entry().size) +
- sizeof(e820Entry().type);
-
- // I'm not sure what these should actually be. On a real machine they
- // would be generated by the BIOS, and they need to reflect the regions
- // which are actually available/reserved. These values are copied from
- // my development machine.
- e820Entry e820Map[] = {
- {ULL(0x0), ULL(0x9d400), 1},
- {ULL(0x9d400), ULL(0xa0000) - ULL(0x9d400), 2},
- {ULL(0xe8000), ULL(0x100000) - ULL(0xe8000), 2},
- {ULL(0x100000), ULL(0xcfff9300) - ULL(0x100000), 1},
- {ULL(0xcfff9300), ULL(0xd0000000) - ULL(0xcfff9300), 2},
- {ULL(0xfec00000), ULL(0x100000000) - ULL(0xfec00000), 2}
- };
-
- uint8_t e820Nr = sizeof(e820Map) / sizeof(e820Entry);
-
- // Make sure the number of entries isn't bigger than what the kernel
- // would be capable of providing.
- assert(e820Nr <= 128);
-
- uint8_t guestE820Nr = X86ISA::htog(e820Nr);
- physPort->writeBlob(e820MapNrPointer,
- (uint8_t *)&guestE820Nr, sizeof(guestE820Nr));
-
- for (int i = 0; i < e820Nr; i++) {
- e820Entry guestE820Entry;
- guestE820Entry.addr = X86ISA::htog(e820Map[i].addr);
- guestE820Entry.size = X86ISA::htog(e820Map[i].size);
- guestE820Entry.type = X86ISA::htog(e820Map[i].type);
- physPort->writeBlob(e820MapPointer + e820EntrySize * i,
- (uint8_t *)&guestE820Entry.addr,
- sizeof(guestE820Entry.addr));
- physPort->writeBlob(
- e820MapPointer + e820EntrySize * i +
- sizeof(guestE820Entry.addr),
- (uint8_t *)&guestE820Entry.size,
- sizeof(guestE820Entry.size));
- physPort->writeBlob(
- e820MapPointer + e820EntrySize * i +
- sizeof(guestE820Entry.addr) +
- sizeof(guestE820Entry.size),
- (uint8_t *)&guestE820Entry.type,
- sizeof(guestE820Entry.type));
- }
+ e820Table->writeTo(physPort, e820MapNrPointer, e820MapPointer);
/*
* Pass the location of the real mode data structure to the kernel
diff --git a/src/arch/x86/linux/system.hh b/src/arch/x86/linux/system.hh
index fc725ad45..a9c5f4ca9 100644
--- a/src/arch/x86/linux/system.hh
+++ b/src/arch/x86/linux/system.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -62,12 +62,14 @@
#include <vector>
#include "params/LinuxX86System.hh"
+#include "arch/x86/bios/e820.hh"
#include "arch/x86/system.hh"
class LinuxX86System : public X86System
{
protected:
std::string commandLine;
+ X86ISA::E820Table * e820Table;
public:
typedef LinuxX86SystemParams Params;
diff --git a/src/arch/x86/microcode_rom.hh b/src/arch/x86/microcode_rom.hh
new file mode 100644
index 000000000..f8ad410ce
--- /dev/null
+++ b/src/arch/x86/microcode_rom.hh
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __ARCH_X86_MICROCODE_ROM_HH__
+#define __ARCH_X86_MICROCODE_ROM_HH__
+
+#include "arch/x86/emulenv.hh"
+#include "cpu/static_inst.hh"
+
+namespace X86ISAInst
+{
+ class MicrocodeRom
+ {
+ protected:
+
+ typedef StaticInstPtr (*GenFunc)(StaticInstPtr);
+
+ static const MicroPC numMicroops;
+
+ GenFunc * genFuncs;
+
+ public:
+ //Constructor.
+ MicrocodeRom();
+
+ //Destructor.
+ ~MicrocodeRom()
+ {
+ delete [] genFuncs;
+ }
+
+ StaticInstPtr
+ fetchMicroop(MicroPC microPC, StaticInstPtr curMacroop)
+ {
+ microPC = normalMicroPC(microPC);
+ assert(microPC < numMicroops);
+ return genFuncs[microPC](curMacroop);
+ }
+ };
+}
+
+namespace X86ISA
+{
+ using X86ISAInst::MicrocodeRom;
+}
+
+#endif // __ARCH_X86_MICROCODE_ROM_HH__
diff --git a/src/arch/x86/miscregfile.cc b/src/arch/x86/miscregfile.cc
index 3b4dc3407..0316603e5 100644
--- a/src/arch/x86/miscregfile.cc
+++ b/src/arch/x86/miscregfile.cc
@@ -87,6 +87,7 @@
#include "arch/x86/miscregfile.hh"
#include "arch/x86/tlb.hh"
+#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "sim/serialize.hh"
@@ -95,19 +96,16 @@ using namespace std;
class Checkpoint;
-//These functions map register indices to names
-string X86ISA::getMiscRegName(RegIndex index)
-{
- panic("No misc registers in x86 yet!\n");
-}
-
void MiscRegFile::clear()
{
- // Blank everything. 0 might not be an appropriate value for some things.
+ // Blank everything. 0 might not be an appropriate value for some things,
+ // but it is for most.
memset(regVal, 0, NumMiscRegs * sizeof(MiscReg));
+ regVal[MISCREG_DR6] = (mask(8) << 4) | (mask(16) << 16);
+ regVal[MISCREG_DR7] = 1 << 10;
}
-MiscReg MiscRegFile::readRegNoEffect(int miscReg)
+MiscReg MiscRegFile::readRegNoEffect(MiscRegIndex miscReg)
{
// Make sure we're not dealing with an illegal control register.
// Instructions should filter out these indexes, and nothing else should
@@ -121,90 +119,15 @@ MiscReg MiscRegFile::readRegNoEffect(int miscReg)
return regVal[miscReg];
}
-MiscReg MiscRegFile::readReg(int miscReg, ThreadContext * tc)
+MiscReg MiscRegFile::readReg(MiscRegIndex miscReg, ThreadContext * tc)
{
- if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) {
- if (miscReg >= MISCREG_APIC_IN_SERVICE(0) &&
- miscReg <= MISCREG_APIC_IN_SERVICE(15)) {
- panic("Local APIC In-Service registers are unimplemented.\n");
- }
- if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) &&
- miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) {
- panic("Local APIC Trigger Mode registers are unimplemented.\n");
- }
- if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) &&
- miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) {
- panic("Local APIC Interrupt Request registers "
- "are unimplemented.\n");
- }
- switch (miscReg) {
- case MISCREG_APIC_TASK_PRIORITY:
- panic("Local APIC Task Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_ARBITRATION_PRIORITY:
- panic("Local APIC Arbitration Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_PROCESSOR_PRIORITY:
- panic("Local APIC Processor Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_EOI:
- panic("Local APIC EOI register unimplemented.\n");
- break;
- case MISCREG_APIC_LOGICAL_DESTINATION:
- panic("Local APIC Logical Destination register unimplemented.\n");
- break;
- case MISCREG_APIC_DESTINATION_FORMAT:
- panic("Local APIC Destination Format register unimplemented.\n");
- break;
- case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR:
- panic("Local APIC Spurious Interrupt Vector"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_ERROR_STATUS:
- panic("Local APIC Error Status register unimplemented.\n");
- break;
- case MISCREG_APIC_INTERRUPT_COMMAND_LOW:
- panic("Local APIC Interrupt Command low"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_INTERRUPT_COMMAND_HIGH:
- panic("Local APIC Interrupt Command high"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_TIMER:
- panic("Local APIC LVT Timer register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_THERMAL_SENSOR:
- panic("Local APIC LVT Thermal Sensor register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
- panic("Local APIC LVT Performance Monitoring Counters"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_LINT0:
- panic("Local APIC LVT LINT0 register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_LINT1:
- panic("Local APIC LVT LINT1 register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_ERROR:
- panic("Local APIC LVT Error register unimplemented.\n");
- break;
- case MISCREG_APIC_INITIAL_COUNT:
- panic("Local APIC Initial Count register unimplemented.\n");
- break;
- case MISCREG_APIC_CURRENT_COUNT:
- panic("Local APIC Current Count register unimplemented.\n");
- break;
- case MISCREG_APIC_DIVIDE_COUNT:
- panic("Local APIC Divide Count register unimplemented.\n");
- break;
- }
+ if (miscReg == MISCREG_TSC) {
+ return regVal[MISCREG_TSC] + tc->getCpuPtr()->curCycle();
}
return readRegNoEffect(miscReg);
}
-void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val)
+void MiscRegFile::setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val)
{
// Make sure we're not dealing with an illegal control register.
// Instructions should filter out these indexes, and nothing else should
@@ -217,96 +140,10 @@ void MiscRegFile::setRegNoEffect(int miscReg, const MiscReg &val)
regVal[miscReg] = val;
}
-void MiscRegFile::setReg(int miscReg,
+void MiscRegFile::setReg(MiscRegIndex miscReg,
const MiscReg &val, ThreadContext * tc)
{
MiscReg newVal = val;
- if (miscReg >= MISCREG_APIC_START && miscReg <= MISCREG_APIC_END) {
- if (miscReg >= MISCREG_APIC_IN_SERVICE(0) &&
- miscReg <= MISCREG_APIC_IN_SERVICE(15)) {
- panic("Local APIC In-Service registers are unimplemented.\n");
- }
- if (miscReg >= MISCREG_APIC_TRIGGER_MODE(0) &&
- miscReg <= MISCREG_APIC_TRIGGER_MODE(15)) {
- panic("Local APIC Trigger Mode registers are unimplemented.\n");
- }
- if (miscReg >= MISCREG_APIC_INTERRUPT_REQUEST(0) &&
- miscReg <= MISCREG_APIC_INTERRUPT_REQUEST(15)) {
- panic("Local APIC Interrupt Request registers "
- "are unimplemented.\n");
- }
- switch (miscReg) {
- case MISCREG_APIC_ID:
- panic("Local APIC ID register unimplemented.\n");
- break;
- case MISCREG_APIC_VERSION:
- panic("Local APIC Version register is read only.\n");
- break;
- case MISCREG_APIC_TASK_PRIORITY:
- panic("Local APIC Task Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_ARBITRATION_PRIORITY:
- panic("Local APIC Arbitration Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_PROCESSOR_PRIORITY:
- panic("Local APIC Processor Priority register unimplemented.\n");
- break;
- case MISCREG_APIC_EOI:
- panic("Local APIC EOI register unimplemented.\n");
- break;
- case MISCREG_APIC_LOGICAL_DESTINATION:
- panic("Local APIC Logical Destination register unimplemented.\n");
- break;
- case MISCREG_APIC_DESTINATION_FORMAT:
- panic("Local APIC Destination Format register unimplemented.\n");
- break;
- case MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR:
- panic("Local APIC Spurious Interrupt Vector"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_ERROR_STATUS:
- panic("Local APIC Error Status register unimplemented.\n");
- break;
- case MISCREG_APIC_INTERRUPT_COMMAND_LOW:
- panic("Local APIC Interrupt Command low"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_INTERRUPT_COMMAND_HIGH:
- panic("Local APIC Interrupt Command high"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_TIMER:
- panic("Local APIC LVT Timer register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_THERMAL_SENSOR:
- panic("Local APIC LVT Thermal Sensor register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS:
- panic("Local APIC LVT Performance Monitoring Counters"
- " register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_LINT0:
- panic("Local APIC LVT LINT0 register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_LINT1:
- panic("Local APIC LVT LINT1 register unimplemented.\n");
- break;
- case MISCREG_APIC_LVT_ERROR:
- panic("Local APIC LVT Error register unimplemented.\n");
- break;
- case MISCREG_APIC_INITIAL_COUNT:
- panic("Local APIC Initial Count register unimplemented.\n");
- break;
- case MISCREG_APIC_CURRENT_COUNT:
- panic("Local APIC Current Count register unimplemented.\n");
- break;
- case MISCREG_APIC_DIVIDE_COUNT:
- panic("Local APIC Divide Count register unimplemented.\n");
- break;
- }
- setRegNoEffect(miscReg, newVal);
- return;
- }
switch(miscReg)
{
case MISCREG_CR0:
@@ -314,17 +151,39 @@ void MiscRegFile::setReg(int miscReg,
CR0 toggled = regVal[miscReg] ^ val;
CR0 newCR0 = val;
Efer efer = regVal[MISCREG_EFER];
+ HandyM5Reg m5reg = regVal[MISCREG_M5_REG];
if (toggled.pg && efer.lme) {
if (newCR0.pg) {
//Turning on long mode
efer.lma = 1;
+ m5reg.mode = LongMode;
regVal[MISCREG_EFER] = efer;
} else {
//Turning off long mode
efer.lma = 0;
+ m5reg.mode = LegacyMode;
regVal[MISCREG_EFER] = efer;
}
}
+ // Figure out what submode we're in.
+ if (m5reg.mode == LongMode) {
+ SegAttr csAttr = regVal[MISCREG_CS_ATTR];
+ if (csAttr.longMode)
+ m5reg.submode = SixtyFourBitMode;
+ else
+ m5reg.submode = CompatabilityMode;
+ } else {
+ if (newCR0.pe) {
+ RFLAGS rflags = regVal[MISCREG_RFLAGS];
+ if (rflags.vm)
+ m5reg.submode = Virtual8086Mode;
+ else
+ m5reg.submode = ProtectedMode;
+ } else {
+ m5reg.submode = RealMode;
+ }
+ }
+ regVal[MISCREG_M5_REG] = m5reg;
if (toggled.pg) {
tc->getITBPtr()->invalidateAll();
tc->getDTBPtr()->invalidateAll();
@@ -355,20 +214,26 @@ void MiscRegFile::setReg(int miscReg,
{
SegAttr toggled = regVal[miscReg] ^ val;
SegAttr newCSAttr = val;
+ HandyM5Reg m5reg = regVal[MISCREG_M5_REG];
if (toggled.longMode) {
- SegAttr newCSAttr = val;
if (newCSAttr.longMode) {
+ if (m5reg.mode == LongMode)
+ m5reg.submode = SixtyFourBitMode;
regVal[MISCREG_ES_EFF_BASE] = 0;
regVal[MISCREG_CS_EFF_BASE] = 0;
regVal[MISCREG_SS_EFF_BASE] = 0;
regVal[MISCREG_DS_EFF_BASE] = 0;
} else {
+ if (m5reg.mode == LongMode)
+ m5reg.submode = CompatabilityMode;
regVal[MISCREG_ES_EFF_BASE] = regVal[MISCREG_ES_BASE];
regVal[MISCREG_CS_EFF_BASE] = regVal[MISCREG_CS_BASE];
regVal[MISCREG_SS_EFF_BASE] = regVal[MISCREG_SS_BASE];
regVal[MISCREG_DS_EFF_BASE] = regVal[MISCREG_DS_BASE];
}
}
+ m5reg.cpl = newCSAttr.dpl;
+ regVal[MISCREG_M5_REG] = m5reg;
}
break;
// These segments always actually use their bases, or in other words
@@ -396,6 +261,80 @@ void MiscRegFile::setReg(int miscReg,
MISCREG_SEG_BASE_BASE)] = val;
}
break;
+ case MISCREG_TSC:
+ regVal[MISCREG_TSC] = val - tc->getCpuPtr()->curCycle();
+ return;
+ case MISCREG_DR0:
+ case MISCREG_DR1:
+ case MISCREG_DR2:
+ case MISCREG_DR3:
+ /* These should eventually set up breakpoints. */
+ break;
+ case MISCREG_DR4:
+ miscReg = MISCREG_DR6;
+ /* Fall through to have the same effects as DR6. */
+ case MISCREG_DR6:
+ {
+ DR6 dr6 = regVal[MISCREG_DR6];
+ DR6 newDR6 = val;
+ dr6.b0 = newDR6.b0;
+ dr6.b1 = newDR6.b1;
+ dr6.b2 = newDR6.b2;
+ dr6.b3 = newDR6.b3;
+ dr6.bd = newDR6.bd;
+ dr6.bs = newDR6.bs;
+ dr6.bt = newDR6.bt;
+ newVal = dr6;
+ }
+ break;
+ case MISCREG_DR5:
+ miscReg = MISCREG_DR7;
+ /* Fall through to have the same effects as DR7. */
+ case MISCREG_DR7:
+ {
+ DR7 dr7 = regVal[MISCREG_DR7];
+ DR7 newDR7 = val;
+ dr7.l0 = newDR7.l0;
+ dr7.g0 = newDR7.g0;
+ if (dr7.l0 || dr7.g0) {
+ panic("Debug register breakpoints not implemented.\n");
+ } else {
+ /* Disable breakpoint 0. */
+ }
+ dr7.l1 = newDR7.l1;
+ dr7.g1 = newDR7.g1;
+ if (dr7.l1 || dr7.g1) {
+ panic("Debug register breakpoints not implemented.\n");
+ } else {
+ /* Disable breakpoint 1. */
+ }
+ dr7.l2 = newDR7.l2;
+ dr7.g2 = newDR7.g2;
+ if (dr7.l2 || dr7.g2) {
+ panic("Debug register breakpoints not implemented.\n");
+ } else {
+ /* Disable breakpoint 2. */
+ }
+ dr7.l3 = newDR7.l3;
+ dr7.g3 = newDR7.g3;
+ if (dr7.l3 || dr7.g3) {
+ panic("Debug register breakpoints not implemented.\n");
+ } else {
+ /* Disable breakpoint 3. */
+ }
+ dr7.gd = newDR7.gd;
+ dr7.rw0 = newDR7.rw0;
+ dr7.len0 = newDR7.len0;
+ dr7.rw1 = newDR7.rw1;
+ dr7.len1 = newDR7.len1;
+ dr7.rw2 = newDR7.rw2;
+ dr7.len2 = newDR7.len2;
+ dr7.rw3 = newDR7.rw3;
+ dr7.len3 = newDR7.len3;
+ }
+ break;
+ default:
+ break;
}
setRegNoEffect(miscReg, newVal);
}
diff --git a/src/arch/x86/miscregfile.hh b/src/arch/x86/miscregfile.hh
index e095e06e9..6d3ae4e92 100644
--- a/src/arch/x86/miscregfile.hh
+++ b/src/arch/x86/miscregfile.hh
@@ -29,7 +29,7 @@
*/
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -91,6 +91,7 @@
#include "arch/x86/faults.hh"
#include "arch/x86/miscregs.hh"
#include "arch/x86/types.hh"
+#include "sim/host.hh"
#include <string>
@@ -98,8 +99,6 @@ class Checkpoint;
namespace X86ISA
{
- std::string getMiscRegName(RegIndex);
-
//These will have to be updated in the future.
const int NumMiscArchRegs = NUM_MISCREGS;
const int NumMiscRegs = NUM_MISCREGS;
@@ -117,13 +116,13 @@ namespace X86ISA
clear();
}
- MiscReg readRegNoEffect(int miscReg);
+ MiscReg readRegNoEffect(MiscRegIndex miscReg);
- MiscReg readReg(int miscReg, ThreadContext *tc);
+ MiscReg readReg(MiscRegIndex miscReg, ThreadContext *tc);
- void setRegNoEffect(int miscReg, const MiscReg &val);
+ void setRegNoEffect(MiscRegIndex miscReg, const MiscReg &val);
- void setReg(int miscReg,
+ void setReg(MiscRegIndex miscReg,
const MiscReg &val, ThreadContext *tc);
void serialize(std::ostream & os);
diff --git a/src/arch/x86/miscregs.hh b/src/arch/x86/miscregs.hh
index d1016d2a9..af02e9422 100644
--- a/src/arch/x86/miscregs.hh
+++ b/src/arch/x86/miscregs.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -82,6 +82,18 @@ namespace X86ISA
OFBit = 1 << 11
};
+ enum RFLAGBit {
+ TFBit = 1 << 8,
+ IFBit = 1 << 9,
+ NTBit = 1 << 14,
+ RFBit = 1 << 16,
+ VMBit = 1 << 17,
+ ACBit = 1 << 18,
+ VIFBit = 1 << 19,
+ VIPBit = 1 << 20,
+ IDBit = 1 << 21
+ };
+
enum MiscRegIndex
{
// Control registers
@@ -118,6 +130,9 @@ namespace X86ISA
// Flags register
MISCREG_RFLAGS = MISCREG_DR_BASE + NumDRegs,
+ //Register to keep handy values like the CPU mode in.
+ MISCREG_M5_REG,
+
/*
* Model Specific Registers
*/
@@ -183,6 +198,9 @@ namespace X86ISA
MISCREG_MC2_CTL,
MISCREG_MC3_CTL,
MISCREG_MC4_CTL,
+ MISCREG_MC5_CTL,
+ MISCREG_MC6_CTL,
+ MISCREG_MC7_CTL,
MISCREG_MC_STATUS_BASE,
MISCREG_MC0_STATUS = MISCREG_MC_STATUS_BASE,
@@ -190,6 +208,9 @@ namespace X86ISA
MISCREG_MC2_STATUS,
MISCREG_MC3_STATUS,
MISCREG_MC4_STATUS,
+ MISCREG_MC5_STATUS,
+ MISCREG_MC6_STATUS,
+ MISCREG_MC7_STATUS,
MISCREG_MC_ADDR_BASE,
MISCREG_MC0_ADDR = MISCREG_MC_ADDR_BASE,
@@ -197,6 +218,9 @@ namespace X86ISA
MISCREG_MC2_ADDR,
MISCREG_MC3_ADDR,
MISCREG_MC4_ADDR,
+ MISCREG_MC5_ADDR,
+ MISCREG_MC6_ADDR,
+ MISCREG_MC7_ADDR,
MISCREG_MC_MISC_BASE,
MISCREG_MC0_MISC = MISCREG_MC_MISC_BASE,
@@ -204,6 +228,9 @@ namespace X86ISA
MISCREG_MC2_MISC,
MISCREG_MC3_MISC,
MISCREG_MC4_MISC,
+ MISCREG_MC5_MISC,
+ MISCREG_MC6_MISC,
+ MISCREG_MC7_MISC,
// Extended feature enable register
MISCREG_EFER,
@@ -341,38 +368,6 @@ namespace X86ISA
MISCREG_APIC_BASE,
- MISCREG_APIC_START,
- MISCREG_APIC_ID = MISCREG_APIC_START,
- MISCREG_APIC_VERSION,
- MISCREG_APIC_TASK_PRIORITY,
- MISCREG_APIC_ARBITRATION_PRIORITY,
- MISCREG_APIC_PROCESSOR_PRIORITY,
- MISCREG_APIC_EOI,
- MISCREG_APIC_LOGICAL_DESTINATION,
- MISCREG_APIC_DESTINATION_FORMAT,
- MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR,
-
- MISCREG_APIC_IN_SERVICE_BASE,
-
- MISCREG_APIC_TRIGGER_MODE_BASE = MISCREG_APIC_IN_SERVICE_BASE + 16,
-
- MISCREG_APIC_INTERRUPT_REQUEST_BASE =
- MISCREG_APIC_TRIGGER_MODE_BASE + 16,
-
- MISCREG_APIC_ERROR_STATUS = MISCREG_APIC_INTERRUPT_REQUEST_BASE + 16,
- MISCREG_APIC_INTERRUPT_COMMAND_LOW,
- MISCREG_APIC_INTERRUPT_COMMAND_HIGH,
- MISCREG_APIC_LVT_TIMER,
- MISCREG_APIC_LVT_THERMAL_SENSOR,
- MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS,
- MISCREG_APIC_LVT_LINT0,
- MISCREG_APIC_LVT_LINT1,
- MISCREG_APIC_LVT_ERROR,
- MISCREG_APIC_INITIAL_COUNT,
- MISCREG_APIC_CURRENT_COUNT,
- MISCREG_APIC_DIVIDE_COUNT,
- MISCREG_APIC_END = MISCREG_APIC_DIVIDE_COUNT,
-
// "Fake" MSRs for internally implemented devices
MISCREG_PCI_CONFIG_ADDRESS,
@@ -481,24 +476,6 @@ namespace X86ISA
return (MiscRegIndex)(MISCREG_SEG_ATTR_BASE + index);
}
- static inline MiscRegIndex
- MISCREG_APIC_IN_SERVICE(int index)
- {
- return (MiscRegIndex)(MISCREG_APIC_IN_SERVICE_BASE + index);
- }
-
- static inline MiscRegIndex
- MISCREG_APIC_TRIGGER_MODE(int index)
- {
- return (MiscRegIndex)(MISCREG_APIC_TRIGGER_MODE_BASE + index);
- }
-
- static inline MiscRegIndex
- MISCREG_APIC_INTERRUPT_REQUEST(int index)
- {
- return (MiscRegIndex)(MISCREG_APIC_INTERRUPT_REQUEST_BASE + index);
- }
-
/**
* A type to describe the condition code bits of the RFLAGS register,
* plus two flags, EZF and ECF, which are only visible to microcode.
@@ -537,6 +514,12 @@ namespace X86ISA
Bitfield<0> cf; // Carry Flag
EndBitUnion(RFLAGS)
+ BitUnion64(HandyM5Reg)
+ Bitfield<0> mode;
+ Bitfield<3, 1> submode;
+ Bitfield<5, 4> cpl;
+ EndBitUnion(HandyM5Reg)
+
/**
* Control registers
*/
@@ -589,6 +572,38 @@ namespace X86ISA
Bitfield<3, 0> tpr; // Task Priority Register
EndBitUnion(CR8)
+ BitUnion64(DR6)
+ Bitfield<0> b0;
+ Bitfield<1> b1;
+ Bitfield<2> b2;
+ Bitfield<3> b3;
+ Bitfield<13> bd;
+ Bitfield<14> bs;
+ Bitfield<15> bt;
+ EndBitUnion(DR6)
+
+ BitUnion64(DR7)
+ Bitfield<0> l0;
+ Bitfield<1> g0;
+ Bitfield<2> l1;
+ Bitfield<3> g1;
+ Bitfield<4> l2;
+ Bitfield<5> g2;
+ Bitfield<6> l3;
+ Bitfield<7> g3;
+ Bitfield<8> le;
+ Bitfield<9> ge;
+ Bitfield<13> gd;
+ Bitfield<17, 16> rw0;
+ Bitfield<19, 18> len0;
+ Bitfield<21, 20> rw1;
+ Bitfield<23, 22> len1;
+ Bitfield<25, 24> rw2;
+ Bitfield<27, 26> len2;
+ Bitfield<29, 28> rw3;
+ Bitfield<31, 30> len3;
+ EndBitUnion(DR7)
+
// MTRR capabilities
BitUnion64(MTRRcap)
Bitfield<7, 0> vcnt; // Variable-Range Register Count
diff --git a/src/arch/x86/mmaped_ipr.hh b/src/arch/x86/mmaped_ipr.hh
index eda85c084..7056c0902 100644
--- a/src/arch/x86/mmaped_ipr.hh
+++ b/src/arch/x86/mmaped_ipr.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -78,15 +78,12 @@ namespace X86ISA
#if !FULL_SYSTEM
panic("Shouldn't have a memory mapped register in SE\n");
#else
+ Addr offset = pkt->getAddr() & mask(3);
MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg));
- if (index == MISCREG_PCI_CONFIG_ADDRESS ||
- (index >= MISCREG_APIC_START &&
- index <= MISCREG_APIC_END)) {
- pkt->set((uint32_t)(xc->readMiscReg(pkt->getAddr() /
- sizeof(MiscReg))));
- } else {
- pkt->set(xc->readMiscReg(pkt->getAddr() / sizeof(MiscReg)));
- }
+ MiscReg data = htog(xc->readMiscReg(index));
+ // Make sure we don't trot off the end of data.
+ assert(offset + pkt->getSize() <= sizeof(MiscReg));
+ pkt->setData(((uint8_t *)&data) + offset);
#endif
return xc->getCpuPtr()->ticks(1);
}
@@ -97,15 +94,14 @@ namespace X86ISA
#if !FULL_SYSTEM
panic("Shouldn't have a memory mapped register in SE\n");
#else
+ Addr offset = pkt->getAddr() & mask(3);
MiscRegIndex index = (MiscRegIndex)(pkt->getAddr() / sizeof(MiscReg));
- if (index == MISCREG_PCI_CONFIG_ADDRESS ||
- (index >= MISCREG_APIC_START &&
- index <= MISCREG_APIC_END)) {
- xc->setMiscReg(index, gtoh(pkt->get<uint32_t>()));
- } else {
- xc->setMiscReg(pkt->getAddr() / sizeof(MiscReg),
- gtoh(pkt->get<uint64_t>()));
- }
+ MiscReg data;
+ data = htog(xc->readMiscRegNoEffect(index));
+ // Make sure we don't trot off the end of data.
+ assert(offset + pkt->getSize() <= sizeof(MiscReg));
+ pkt->writeData(((uint8_t *)&data) + offset);
+ xc->setMiscReg(index, gtoh(data));
#endif
return xc->getCpuPtr()->ticks(1);
}
diff --git a/src/arch/x86/pagetable.hh b/src/arch/x86/pagetable.hh
index e42693c03..1a7a945e4 100644
--- a/src/arch/x86/pagetable.hh
+++ b/src/arch/x86/pagetable.hh
@@ -113,6 +113,12 @@ namespace X86ISA
TlbEntry(Addr asn, Addr _vaddr, Addr _paddr);
TlbEntry() {}
+ void
+ updateVaddr(Addr new_vaddr)
+ {
+ vaddr = new_vaddr;
+ }
+
Addr pageStart()
{
return paddr;
diff --git a/src/arch/x86/pagetable_walker.cc b/src/arch/x86/pagetable_walker.cc
index e70c16b1d..f625cf4bd 100644
--- a/src/arch/x86/pagetable_walker.cc
+++ b/src/arch/x86/pagetable_walker.cc
@@ -84,8 +84,8 @@ BitUnion64(PageTableEntry)
Bitfield<0> p;
EndBitUnion(PageTableEntry)
-void
-Walker::doNext(PacketPtr &read, PacketPtr &write)
+Fault
+Walker::doNext(PacketPtr &write)
{
assert(state != Ready && state != Waiting);
write = NULL;
@@ -101,39 +101,45 @@ Walker::doNext(PacketPtr &read, PacketPtr &write)
bool badNX = pte.nx && (!tlb->allowNX() || !enableNX);
switch(state) {
case LongPML4:
+ DPRINTF(PageTableWalker,
+ "Got long mode PML4 entry %#016x.\n", (uint64_t)pte);
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl3 * size;
doWrite = !pte.a;
pte.a = 1;
entry.writable = pte.w;
entry.user = pte.u;
- if (badNX)
- panic("NX violation!\n");
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
entry.noExec = pte.nx;
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
nextState = LongPDP;
break;
case LongPDP:
+ DPRINTF(PageTableWalker,
+ "Got long mode PDP entry %#016x.\n", (uint64_t)pte);
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.longl2 * size;
doWrite = !pte.a;
pte.a = 1;
entry.writable = entry.writable && pte.w;
entry.user = entry.user && pte.u;
- if (badNX)
- panic("NX violation!\n");
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
nextState = LongPD;
break;
case LongPD:
+ DPRINTF(PageTableWalker,
+ "Got long mode PD entry %#016x.\n", (uint64_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = entry.writable && pte.w;
entry.user = entry.user && pte.u;
- if (badNX)
- panic("NX violation!\n");
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
if (!pte.ps) {
// 4 KB page
entry.size = 4 * (1 << 10);
@@ -150,47 +156,49 @@ Walker::doNext(PacketPtr &read, PacketPtr &write)
entry.patBit = bits(pte, 12);
entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
}
case LongPTE:
+ DPRINTF(PageTableWalker,
+ "Got long mode PTE entry %#016x.\n", (uint64_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = entry.writable && pte.w;
entry.user = entry.user && pte.u;
- if (badNX)
- panic("NX violation!\n");
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
entry.paddr = (uint64_t)pte & (mask(40) << 12);
entry.uncacheable = uncacheable;
entry.global = pte.g;
entry.patBit = bits(pte, 12);
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
case PAEPDP:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PAE PDP entry %#08x.\n", (uint32_t)pte);
nextRead = ((uint64_t)pte & (mask(40) << 12)) + vaddr.pael2 * size;
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (!pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
nextState = PAEPD;
break;
case PAEPD:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PAE PD entry %#08x.\n", (uint32_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = pte.w;
entry.user = pte.u;
- if (badNX)
- panic("NX violation!\n");
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
if (!pte.ps) {
// 4 KB page
entry.size = 4 * (1 << 10);
@@ -206,39 +214,39 @@ Walker::doNext(PacketPtr &read, PacketPtr &write)
entry.patBit = bits(pte, 12);
entry.vaddr = entry.vaddr & ~((2 * (1 << 20)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
}
case PAEPTE:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PAE PTE entry %#08x.\n", (uint32_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = entry.writable && pte.w;
entry.user = entry.user && pte.u;
- if (badNX)
- panic("NX violation!\n");
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (badNX || !pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
entry.paddr = (uint64_t)pte & (mask(40) << 12);
entry.uncacheable = uncacheable;
entry.global = pte.g;
entry.patBit = bits(pte, 7);
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
case PSEPD:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PSE PD entry %#08x.\n", (uint32_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = pte.w;
entry.user = pte.u;
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (!pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
if (!pte.ps) {
// 4 KB page
entry.size = 4 * (1 << 10);
@@ -255,54 +263,51 @@ Walker::doNext(PacketPtr &read, PacketPtr &write)
entry.patBit = bits(pte, 12);
entry.vaddr = entry.vaddr & ~((4 * (1 << 20)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
}
case PD:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PD entry %#08x.\n", (uint32_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = pte.w;
entry.user = pte.u;
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (!pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
// 4 KB page
entry.size = 4 * (1 << 10);
nextRead = ((uint64_t)pte & (mask(20) << 12)) + vaddr.norml2 * size;
nextState = PTE;
break;
- nextState = PTE;
- break;
case PTE:
+ DPRINTF(PageTableWalker,
+ "Got legacy mode PTE entry %#08x.\n", (uint32_t)pte);
doWrite = !pte.a;
pte.a = 1;
entry.writable = pte.w;
entry.user = pte.u;
- if (!pte.p)
- panic("Page at %#x not present!\n", entry.vaddr);
+ if (!pte.p) {
+ stop();
+ return pageFault(pte.p);
+ }
entry.paddr = (uint64_t)pte & (mask(20) << 12);
entry.uncacheable = uncacheable;
entry.global = pte.g;
entry.patBit = bits(pte, 7);
entry.vaddr = entry.vaddr & ~((4 * (1 << 10)) - 1);
tlb->insert(entry.vaddr, entry);
- nextState = Ready;
- delete read->req;
- delete read;
- read = NULL;
- return;
+ stop();
+ return NoFault;
default:
panic("Unknown page table walker state %d!\n");
}
PacketPtr oldRead = read;
//If we didn't return, we're setting up another read.
- uint32_t flags = oldRead->req->getFlags();
- if (uncacheable)
- flags |= UNCACHEABLE;
- else
- flags &= ~UNCACHEABLE;
+ Request::Flags flags = oldRead->req->getFlags();
+ flags.set(Request::UNCACHEABLE, uncacheable);
RequestPtr request =
new Request(nextRead, oldRead->getSize(), flags);
read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
@@ -319,14 +324,20 @@ Walker::doNext(PacketPtr &read, PacketPtr &write)
delete oldRead->req;
delete oldRead;
}
+ return NoFault;
}
-void
-Walker::start(ThreadContext * _tc, Addr vaddr)
+Fault
+Walker::start(ThreadContext * _tc, BaseTLB::Translation *_translation,
+ RequestPtr _req, bool _write, bool _execute)
{
assert(state == Ready);
- assert(!tc);
tc = _tc;
+ req = _req;
+ Addr vaddr = req->getVaddr();
+ execute = _execute;
+ write = _write;
+ translation = _translation;
VAddr addr = vaddr;
@@ -340,6 +351,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr)
// Do long mode.
state = LongPML4;
top = (cr3.longPdtb << 12) + addr.longl4 * size;
+ enableNX = efer.nxe;
} else {
// We're in some flavor of legacy mode.
CR4 cr4 = tc->readMiscRegNoEffect(MISCREG_CR4);
@@ -347,6 +359,7 @@ Walker::start(ThreadContext * _tc, Addr vaddr)
// Do legacy PAE.
state = PAEPDP;
top = (cr3.paePdtb << 5) + addr.pael3 * size;
+ enableNX = efer.nxe;
} else {
size = 4;
top = (cr3.pdtb << 12) + addr.norml2 * size;
@@ -357,38 +370,44 @@ Walker::start(ThreadContext * _tc, Addr vaddr)
// Do legacy non PSE.
state = PD;
}
+ enableNX = false;
}
}
nextState = Ready;
entry.vaddr = vaddr;
- enableNX = efer.nxe;
-
- RequestPtr request =
- new Request(top, size, PHYSICAL | cr3.pcd ? UNCACHEABLE : 0);
+ Request::Flags flags = Request::PHYSICAL;
+ if (cr3.pcd)
+ flags.set(Request::UNCACHEABLE);
+ RequestPtr request = new Request(top, size, flags);
read = new Packet(request, MemCmd::ReadExReq, Packet::Broadcast);
read->allocate();
Enums::MemoryMode memMode = sys->getMemoryMode();
if (memMode == Enums::timing) {
- tc->suspend();
- port.sendTiming(read);
+ nextState = state;
+ state = Waiting;
+ timingFault = NoFault;
+ sendPackets();
} else if (memMode == Enums::atomic) {
+ Fault fault;
do {
port.sendAtomic(read);
PacketPtr write = NULL;
- doNext(read, write);
+ fault = doNext(write);
+ assert(fault == NoFault || read == NULL);
state = nextState;
nextState = Ready;
if (write)
port.sendAtomic(write);
} while(read);
- tc = NULL;
state = Ready;
nextState = Waiting;
+ return fault;
} else {
panic("Unrecognized memory system mode.\n");
}
+ return NoFault;
}
bool
@@ -400,18 +419,19 @@ Walker::WalkerPort::recvTiming(PacketPtr pkt)
bool
Walker::recvTiming(PacketPtr pkt)
{
- inflight--;
if (pkt->isResponse() && !pkt->wasNacked()) {
+ assert(inflight);
+ assert(state == Waiting);
+ assert(!read);
+ inflight--;
if (pkt->isRead()) {
- assert(inflight);
- assert(state == Waiting);
- assert(!read);
state = nextState;
nextState = Ready;
PacketPtr write = NULL;
- doNext(pkt, write);
- state = Waiting;
read = pkt;
+ timingFault = doNext(write);
+ state = Waiting;
+ assert(timingFault == NoFault || read == NULL);
if (write) {
writes.push_back(write);
}
@@ -420,14 +440,31 @@ Walker::recvTiming(PacketPtr pkt)
sendPackets();
}
if (inflight == 0 && read == NULL && writes.size() == 0) {
- tc->activate(0);
- tc = NULL;
state = Ready;
nextState = Waiting;
+ if (timingFault == NoFault) {
+ /*
+ * Finish the translation. Now that we now the right entry is
+ * in the TLB, this should work with no memory accesses.
+ * There could be new faults unrelated to the table walk like
+ * permissions violations, so we'll need the return value as
+ * well.
+ */
+ bool delayedResponse;
+ Fault fault = tlb->translate(req, tc, NULL, write, execute,
+ delayedResponse, true);
+ assert(!delayedResponse);
+ // Let the CPU continue.
+ translation->finish(fault, req, tc, write);
+ } else {
+ // There was a fault during the walk. Let the CPU know.
+ translation->finish(timingFault, req, tc, write);
+ }
}
} else if (pkt->wasNacked()) {
pkt->reinitNacked();
if (!port.sendTiming(pkt)) {
+ inflight--;
retrying = true;
if (pkt->isWrite()) {
writes.push_back(pkt);
@@ -435,8 +472,6 @@ Walker::recvTiming(PacketPtr pkt)
assert(!read);
read = pkt;
}
- } else {
- inflight++;
}
}
return true;
@@ -490,27 +525,26 @@ Walker::sendPackets()
//Reads always have priority
if (read) {
- if (!port.sendTiming(read)) {
+ PacketPtr pkt = read;
+ read = NULL;
+ inflight++;
+ if (!port.sendTiming(pkt)) {
retrying = true;
+ read = pkt;
+ inflight--;
return;
- } else {
- inflight++;
- delete read->req;
- delete read;
- read = NULL;
}
}
//Send off as many of the writes as we can.
while (writes.size()) {
PacketPtr write = writes.back();
+ writes.pop_back();
+ inflight++;
if (!port.sendTiming(write)) {
retrying = true;
+ writes.push_back(write);
+ inflight--;
return;
- } else {
- inflight++;
- delete write->req;
- delete write;
- writes.pop_back();
}
}
}
@@ -524,6 +558,15 @@ Walker::getPort(const std::string &if_name, int idx)
panic("No page table walker port named %s!\n", if_name);
}
+Fault
+Walker::pageFault(bool present)
+{
+ DPRINTF(PageTableWalker, "Raising page fault.\n");
+ HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ return new PageFault(entry.vaddr, present, write,
+ m5reg.cpl == 3, false, execute && enableNX);
+}
+
}
X86ISA::Walker *
diff --git a/src/arch/x86/pagetable_walker.hh b/src/arch/x86/pagetable_walker.hh
index 324f16f3c..f73774a45 100644
--- a/src/arch/x86/pagetable_walker.hh
+++ b/src/arch/x86/pagetable_walker.hh
@@ -85,17 +85,28 @@ namespace X86ISA
PSEPD, PD, PTE
};
- // Act on the current state and determine what to do next. read
- // should be the packet that just came back from a read and write
+ // Act on the current state and determine what to do next. The global
+ // read should be the packet that just came back from a read and write
// should be NULL. When the function returns, read is either NULL
// if the machine is finished, or points to a packet to initiate
// the next read. If any write is required to update an "accessed"
// bit, write will point to a packet to do the write. Otherwise it
- // will be NULL.
- void doNext(PacketPtr &read, PacketPtr &write);
+ // will be NULL. The return value is whatever fault was incurred
+ // during this stage of the lookup.
+ Fault doNext(PacketPtr &write);
// Kick off the state machine.
- void start(ThreadContext * _tc, Addr vaddr);
+ Fault start(ThreadContext * _tc, BaseTLB::Translation *translation,
+ RequestPtr req, bool write, bool execute);
+ // Clean up after the state machine.
+ void
+ stop()
+ {
+ nextState = Ready;
+ delete read->req;
+ delete read;
+ read = NULL;
+ }
protected:
@@ -111,6 +122,11 @@ namespace X86ISA
bool retrying;
/*
+ * The fault, if any, that's waiting to be delivered in timing mode.
+ */
+ Fault timingFault;
+
+ /*
* Functions for dealing with packets.
*/
bool recvTiming(PacketPtr pkt);
@@ -156,16 +172,21 @@ namespace X86ISA
// The TLB we're supposed to load.
TLB * tlb;
System * sys;
+ BaseTLB::Translation * translation;
/*
* State machine state.
*/
ThreadContext * tc;
+ RequestPtr req;
State state;
State nextState;
int size;
bool enableNX;
+ bool write, execute, user;
TlbEntry entry;
+
+ Fault pageFault(bool present);
public:
diff --git a/src/arch/x86/predecoder.cc b/src/arch/x86/predecoder.cc
index 407a09ec0..620ab89ea 100644
--- a/src/arch/x86/predecoder.cc
+++ b/src/arch/x86/predecoder.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -55,9 +55,11 @@
* Authors: Gabe Black
*/
+#include "arch/x86/miscregs.hh"
#include "arch/x86/predecoder.hh"
#include "base/misc.hh"
#include "base/trace.hh"
+#include "cpu/thread_context.hh"
#include "sim/host.hh"
namespace X86ISA
@@ -78,7 +80,9 @@ namespace X86ISA
emi.modRM = 0;
emi.sib = 0;
- emi.mode = 0;
+ HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ emi.mode.mode = m5reg.mode;
+ emi.mode.submode = m5reg.submode;
}
void Predecoder::process()
@@ -132,7 +136,10 @@ namespace X86ISA
{
uint8_t prefix = Prefixes[nextByte];
State nextState = PrefixState;
- if(prefix)
+ // REX prefixes are only recognized in 64 bit mode.
+ if (prefix == RexPrefix && emi.mode.submode != SixtyFourBitMode)
+ prefix = 0;
+ if (prefix)
consumeByte();
switch(prefix)
{
@@ -209,10 +216,12 @@ namespace X86ISA
DPRINTF(Predecoder, "Found opcode %#x.\n", nextByte);
emi.opcode.op = nextByte;
+ SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
+
//Figure out the effective operand size. This can be overriden to
//a fixed value at the decoder level.
int logOpSize;
- if(/*FIXME long mode*/1)
+ if (emi.mode.submode == SixtyFourBitMode)
{
if(emi.rex.w)
logOpSize = 3; // 64 bit operand size
@@ -221,7 +230,7 @@ namespace X86ISA
else
logOpSize = 2; // 32 bit operand size
}
- else if(/*FIXME default 32*/1)
+ else if(csAttr.defaultSize)
{
if(emi.legacy.op)
logOpSize = 1; // 16 bit operand size
@@ -242,14 +251,14 @@ namespace X86ISA
//Figure out the effective address size. This can be overriden to
//a fixed value at the decoder level.
int logAddrSize;
- if(/*FIXME 64-bit mode*/1)
+ if(emi.mode.submode == SixtyFourBitMode)
{
if(emi.legacy.addr)
logAddrSize = 2; // 32 bit address size
else
logAddrSize = 3; // 64 bit address size
}
- else if(/*FIXME default 32*/1)
+ else if(csAttr.defaultSize)
{
if(emi.legacy.addr)
logAddrSize = 1; // 16 bit address size
@@ -264,6 +273,16 @@ namespace X86ISA
logAddrSize = 1; // 16 bit address size
}
+ SegAttr ssAttr = tc->readMiscRegNoEffect(MISCREG_SS_ATTR);
+ //Figure out the effective stack width. This can be overriden to
+ //a fixed value at the decoder level.
+ if(emi.mode.submode == SixtyFourBitMode)
+ emi.stackSize = 8; // 64 bit stack width
+ else if(ssAttr.defaultSize)
+ emi.stackSize = 4; // 32 bit stack width
+ else
+ emi.stackSize = 2; // 16 bit stack width
+
//Set the actual address size
emi.addrSize = 1 << logAddrSize;
@@ -299,19 +318,21 @@ namespace X86ISA
ModRM modRM;
modRM = nextByte;
DPRINTF(Predecoder, "Found modrm byte %#x.\n", nextByte);
- if (0) {//FIXME in 16 bit mode
+ SegAttr csAttr = tc->readMiscRegNoEffect(MISCREG_CS_ATTR);
+ if (emi.mode.submode != SixtyFourBitMode &&
+ !csAttr.defaultSize) {
//figure out 16 bit displacement size
- if(modRM.mod == 0 && modRM.rm == 6 || modRM.mod == 2)
+ if ((modRM.mod == 0 && modRM.rm == 6) || modRM.mod == 2)
displacementSize = 2;
- else if(modRM.mod == 1)
+ else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
} else {
//figure out 32/64 bit displacement size
- if(modRM.mod == 0 && modRM.rm == 5 || modRM.mod == 2)
+ if ((modRM.mod == 0 && modRM.rm == 5) || modRM.mod == 2)
displacementSize = 4;
- else if(modRM.mod == 1)
+ else if (modRM.mod == 1)
displacementSize = 1;
else
displacementSize = 0;
diff --git a/src/arch/x86/predecoder.hh b/src/arch/x86/predecoder.hh
index 6e41e8134..a16ce6fb8 100644
--- a/src/arch/x86/predecoder.hh
+++ b/src/arch/x86/predecoder.hh
@@ -58,6 +58,8 @@
#ifndef __ARCH_X86_PREDECODER_HH__
#define __ARCH_X86_PREDECODER_HH__
+#include <cassert>
+
#include "arch/x86/types.hh"
#include "base/bitfield.hh"
#include "base/misc.hh"
diff --git a/src/arch/x86/predecoder_tables.cc b/src/arch/x86/predecoder_tables.cc
index a8c719054..5f2b5c421 100644
--- a/src/arch/x86/predecoder_tables.cc
+++ b/src/arch/x86/predecoder_tables.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -123,7 +123,7 @@ namespace X86ISA
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F
/* 0 */ 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 0 , 1,
-/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
+/* 1 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 2 */ 1 , 1 , 1 , 1 , 1 , 0 , 1 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
/* 4 */ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1,
@@ -201,7 +201,7 @@ namespace X86ISA
//For two byte instructions
{ //LSB
// MSB 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F
-/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
+/* 0 */ 0 , 0 , 0 , 0 , WO, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , BY ,
/* 0 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
/* 2 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
/* 3 */ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
diff --git a/src/arch/x86/process.cc b/src/arch/x86/process.cc
index 76f0b5d04..4a61ed168 100644
--- a/src/arch/x86/process.cc
+++ b/src/arch/x86/process.cc
@@ -98,56 +98,115 @@
#include "mem/page_table.hh"
#include "mem/translating_port.hh"
#include "sim/process_impl.hh"
+#include "sim/syscall_emul.hh"
#include "sim/system.hh"
using namespace std;
using namespace X86ISA;
-M5_64_auxv_t::M5_64_auxv_t(int64_t type, int64_t val)
-{
- a_type = TheISA::htog(type);
- a_val = TheISA::htog(val);
-}
-
-X86LiveProcess::X86LiveProcess(LiveProcessParams * params,
- ObjectFile *objFile)
- : LiveProcess(params, objFile)
+static const int ReturnValueReg = INTREG_RAX;
+static const int ArgumentReg[] = {
+ INTREG_RDI,
+ INTREG_RSI,
+ INTREG_RDX,
+ //This argument register is r10 for syscalls and rcx for C.
+ INTREG_R10W,
+ //INTREG_RCX,
+ INTREG_R8W,
+ INTREG_R9W
+};
+static const int NumArgumentRegs = sizeof(ArgumentReg) / sizeof(const int);
+static const int ArgumentReg32[] = {
+ INTREG_EBX,
+ INTREG_ECX,
+ INTREG_EDX,
+ INTREG_ESI,
+ INTREG_EDI,
+};
+static const int NumArgumentRegs32 = sizeof(ArgumentReg) / sizeof(const int);
+
+X86LiveProcess::X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
+ SyscallDesc *_syscallDescs, int _numSyscallDescs) :
+ LiveProcess(params, objFile), syscallDescs(_syscallDescs),
+ numSyscallDescs(_numSyscallDescs)
{
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
brk_point = roundUp(brk_point, VMPageSize);
+}
- // Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
-
+X86_64LiveProcess::X86_64LiveProcess(LiveProcessParams *params,
+ ObjectFile *objFile, SyscallDesc *_syscallDescs,
+ int _numSyscallDescs) :
+ X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
+{
// Set up stack. On X86_64 Linux, stack goes from the top of memory
// downward, less the hole for the kernel address space plus one page
// for undertermined purposes.
stack_base = (Addr)0x7FFFFFFFF000ULL;
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+
// Set up region for mmaps. This was determined empirically and may not
// always be correct.
mmap_start = mmap_end = (Addr)0x2aaaaaaab000ULL;
}
-void X86LiveProcess::handleTrap(int trapNum, ThreadContext *tc)
+void
+I386LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
{
- switch(trapNum)
- {
- default:
- panic("Unimplemented trap to operating system: trap number %#x.\n", trapNum);
+ Addr eip = tc->readPC();
+ if (eip >= vsyscallPage.base &&
+ eip < vsyscallPage.base + vsyscallPage.size) {
+ tc->setNextPC(vsyscallPage.base + vsyscallPage.vsysexitOffset);
}
+ X86LiveProcess::syscall(callnum, tc);
+}
+
+
+I386LiveProcess::I386LiveProcess(LiveProcessParams *params,
+ ObjectFile *objFile, SyscallDesc *_syscallDescs,
+ int _numSyscallDescs) :
+ X86LiveProcess(params, objFile, _syscallDescs, _numSyscallDescs)
+{
+ _gdtStart = 0x100000000;
+ _gdtSize = VMPageSize;
+
+ vsyscallPage.base = 0xffffe000ULL;
+ vsyscallPage.size = VMPageSize;
+ vsyscallPage.vsyscallOffset = 0x400;
+ vsyscallPage.vsysexitOffset = 0x410;
+
+ stack_base = vsyscallPage.base;
+
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
+
+ // Set up region for mmaps. This was determined empirically and may not
+ // always be correct.
+ mmap_start = mmap_end = (Addr)0xf7ffd000ULL;
+}
+
+SyscallDesc*
+X86LiveProcess::getDesc(int callnum)
+{
+ if (callnum < 0 || callnum >= numSyscallDescs)
+ return NULL;
+ return &syscallDescs[callnum];
}
void
-X86LiveProcess::startup()
+X86_64LiveProcess::startup()
{
+ LiveProcess::startup();
+
if (checkpointRestored)
return;
- argsInit(sizeof(IntReg), VMPageSize);
+ argsInit(sizeof(uint64_t), VMPageSize);
- for (int i = 0; i < threadContexts.size(); i++) {
- ThreadContext * tc = threadContexts[i];
+ for (int i = 0; i < contextIds.size(); i++) {
+ ThreadContext * tc = system->getThreadContext(contextIds[i]);
SegAttr dataAttr = 0;
dataAttr.writable = 1;
@@ -203,10 +262,122 @@ X86LiveProcess::startup()
}
void
-X86LiveProcess::argsInit(int intSize, int pageSize)
+I386LiveProcess::startup()
+{
+ LiveProcess::startup();
+
+ if (checkpointRestored)
+ return;
+
+ argsInit(sizeof(uint32_t), VMPageSize);
+
+ /*
+ * Set up a GDT for this process. The whole GDT wouldn't really be for
+ * this process, but the only parts we care about are.
+ */
+ pTable->allocate(_gdtStart, _gdtSize);
+ uint64_t zero = 0;
+ assert(_gdtSize % sizeof(zero) == 0);
+ for (Addr gdtCurrent = _gdtStart;
+ gdtCurrent < _gdtStart + _gdtSize; gdtCurrent += sizeof(zero)) {
+ initVirtMem->write(gdtCurrent, zero);
+ }
+
+ // Set up the vsyscall page for this process.
+ pTable->allocate(vsyscallPage.base, vsyscallPage.size);
+ uint8_t vsyscallBlob[] = {
+ 0x51, // push %ecx
+ 0x52, // push %edp
+ 0x55, // push %ebp
+ 0x89, 0xe5, // mov %esp, %ebp
+ 0x0f, 0x34 // sysenter
+ };
+ initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsyscallOffset,
+ vsyscallBlob, sizeof(vsyscallBlob));
+
+ uint8_t vsysexitBlob[] = {
+ 0x5d, // pop %ebp
+ 0x5a, // pop %edx
+ 0x59, // pop %ecx
+ 0xc3 // ret
+ };
+ initVirtMem->writeBlob(vsyscallPage.base + vsyscallPage.vsysexitOffset,
+ vsysexitBlob, sizeof(vsysexitBlob));
+
+ for (int i = 0; i < contextIds.size(); i++) {
+ ThreadContext * tc = system->getThreadContext(contextIds[i]);
+
+ SegAttr dataAttr = 0;
+ dataAttr.writable = 1;
+ dataAttr.readable = 1;
+ dataAttr.expandDown = 0;
+ dataAttr.dpl = 3;
+ dataAttr.defaultSize = 1;
+ dataAttr.longMode = 0;
+
+ //Initialize the segment registers.
+ for(int seg = 0; seg < NUM_SEGMENTREGS; seg++) {
+ tc->setMiscRegNoEffect(MISCREG_SEG_BASE(seg), 0);
+ tc->setMiscRegNoEffect(MISCREG_SEG_EFF_BASE(seg), 0);
+ tc->setMiscRegNoEffect(MISCREG_SEG_ATTR(seg), dataAttr);
+ tc->setMiscRegNoEffect(MISCREG_SEG_SEL(seg), 0xB);
+ tc->setMiscRegNoEffect(MISCREG_SEG_LIMIT(seg), (uint32_t)(-1));
+ }
+
+ SegAttr csAttr = 0;
+ csAttr.writable = 0;
+ csAttr.readable = 1;
+ csAttr.expandDown = 0;
+ csAttr.dpl = 3;
+ csAttr.defaultSize = 1;
+ csAttr.longMode = 0;
+
+ tc->setMiscRegNoEffect(MISCREG_CS_ATTR, csAttr);
+
+ tc->setMiscRegNoEffect(MISCREG_TSG_BASE, _gdtStart);
+ tc->setMiscRegNoEffect(MISCREG_TSG_EFF_BASE, _gdtStart);
+ tc->setMiscRegNoEffect(MISCREG_TSG_LIMIT, _gdtStart + _gdtSize - 1);
+
+ // Set the LDT selector to 0 to deactivate it.
+ tc->setMiscRegNoEffect(MISCREG_TSL, 0);
+
+ //Set up the registers that describe the operating mode.
+ CR0 cr0 = 0;
+ cr0.pg = 1; // Turn on paging.
+ cr0.cd = 0; // Don't disable caching.
+ cr0.nw = 0; // This is bit is defined to be ignored.
+ cr0.am = 0; // No alignment checking
+ cr0.wp = 0; // Supervisor mode can write read only pages
+ cr0.ne = 1;
+ cr0.et = 1; // This should always be 1
+ cr0.ts = 0; // We don't do task switching, so causing fp exceptions
+ // would be pointless.
+ cr0.em = 0; // Allow x87 instructions to execute natively.
+ cr0.mp = 1; // This doesn't really matter, but the manual suggests
+ // setting it to one.
+ cr0.pe = 1; // We're definitely in protected mode.
+ tc->setMiscReg(MISCREG_CR0, cr0);
+
+ Efer efer = 0;
+ efer.sce = 1; // Enable system call extensions.
+ efer.lme = 1; // Enable long mode.
+ efer.lma = 0; // Deactivate long mode.
+ efer.nxe = 1; // Enable nx support.
+ efer.svme = 0; // Disable svm support for now. It isn't implemented.
+ efer.ffxsr = 1; // Turn on fast fxsave and fxrstor.
+ tc->setMiscReg(MISCREG_EFER, efer);
+ }
+}
+
+template<class IntType>
+void
+X86LiveProcess::argsInit(int pageSize,
+ std::vector<AuxVector<IntType> > extraAuxvs)
{
- typedef M5_64_auxv_t auxv_t;
- Process::startup();
+ int intSize = sizeof(IntType);
+
+ typedef AuxVector<IntType> auxv_t;
+ std::vector<auxv_t> auxv = extraAuxvs;
string filename;
if(argv.size() < 1)
@@ -399,35 +570,35 @@ X86LiveProcess::argsInit(int intSize, int pageSize)
roundUp(stack_size, pageSize));
// map out initial stack contents
- Addr sentry_base = stack_base - sentry_size;
- Addr file_name_base = sentry_base - file_name_size;
- Addr env_data_base = file_name_base - env_data_size;
- Addr arg_data_base = env_data_base - arg_data_size;
- Addr aux_data_base = arg_data_base - info_block_padding - aux_data_size;
- Addr auxv_array_base = aux_data_base - aux_array_size - aux_padding;
- 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;
-
- DPRINTF(X86, "The addresses of items on the initial stack:\n");
- DPRINTF(X86, "0x%x - file name\n", file_name_base);
- DPRINTF(X86, "0x%x - env data\n", env_data_base);
- DPRINTF(X86, "0x%x - arg data\n", arg_data_base);
- DPRINTF(X86, "0x%x - aux data\n", aux_data_base);
- DPRINTF(X86, "0x%x - auxv array\n", auxv_array_base);
- DPRINTF(X86, "0x%x - envp array\n", envp_array_base);
- DPRINTF(X86, "0x%x - argv array\n", argv_array_base);
- DPRINTF(X86, "0x%x - argc \n", argc_base);
- DPRINTF(X86, "0x%x - stack min\n", stack_min);
+ IntType sentry_base = stack_base - sentry_size;
+ IntType file_name_base = sentry_base - file_name_size;
+ IntType env_data_base = file_name_base - env_data_size;
+ IntType arg_data_base = env_data_base - arg_data_size;
+ IntType aux_data_base = arg_data_base - info_block_padding - aux_data_size;
+ IntType auxv_array_base = aux_data_base - aux_array_size - aux_padding;
+ IntType envp_array_base = auxv_array_base - envp_array_size;
+ IntType argv_array_base = envp_array_base - argv_array_size;
+ IntType argc_base = argv_array_base - argc_size;
+
+ DPRINTF(Stack, "The addresses of items on the initial stack:\n");
+ DPRINTF(Stack, "0x%x - file name\n", file_name_base);
+ DPRINTF(Stack, "0x%x - env data\n", env_data_base);
+ DPRINTF(Stack, "0x%x - arg data\n", arg_data_base);
+ DPRINTF(Stack, "0x%x - aux data\n", aux_data_base);
+ DPRINTF(Stack, "0x%x - auxv array\n", auxv_array_base);
+ DPRINTF(Stack, "0x%x - envp array\n", envp_array_base);
+ DPRINTF(Stack, "0x%x - argv array\n", argv_array_base);
+ DPRINTF(Stack, "0x%x - argc \n", argc_base);
+ DPRINTF(Stack, "0x%x - stack min\n", stack_min);
// write contents to stack
// figure out argc
- uint64_t argc = argv.size();
- uint64_t guestArgc = TheISA::htog(argc);
+ IntType argc = argv.size();
+ IntType guestArgc = X86ISA::htog(argc);
//Write out the sentry void *
- uint64_t sentry_NULL = 0;
+ IntType sentry_NULL = 0;
initVirtMem->writeBlob(sentry_base,
(uint8_t*)&sentry_NULL, sentry_size);
@@ -458,17 +629,70 @@ X86LiveProcess::argsInit(int intSize, int pageSize)
initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
//Set the stack pointer register
- threadContexts[0]->setIntReg(StackPointerReg, stack_min);
+ tc->setIntReg(StackPointerReg, stack_min);
Addr prog_entry = objFile->entryPoint();
// There doesn't need to be any segment base added in since we're dealing
// with the flat segmentation model.
- threadContexts[0]->setPC(prog_entry);
- threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ tc->setPC(prog_entry);
+ tc->setNextPC(prog_entry + sizeof(MachInst));
//Align the "stack_min" to a page boundary.
stack_min = roundDown(stack_min, pageSize);
// num_processes++;
}
+
+void
+X86_64LiveProcess::argsInit(int intSize, int pageSize)
+{
+ std::vector<AuxVector<uint64_t> > extraAuxvs;
+ X86LiveProcess::argsInit<uint64_t>(pageSize, extraAuxvs);
+}
+
+void
+I386LiveProcess::argsInit(int intSize, int pageSize)
+{
+ std::vector<AuxVector<uint32_t> > extraAuxvs;
+ //Tell the binary where the vsyscall part of the vsyscall page is.
+ extraAuxvs.push_back(AuxVector<uint32_t>(0x20,
+ vsyscallPage.base + vsyscallPage.vsyscallOffset));
+ extraAuxvs.push_back(AuxVector<uint32_t>(0x21, vsyscallPage.base));
+ X86LiveProcess::argsInit<uint32_t>(pageSize, extraAuxvs);
+}
+
+void
+X86LiveProcess::setSyscallReturn(ThreadContext *tc, SyscallReturn return_value)
+{
+ tc->setIntReg(INTREG_RAX, return_value.value());
+}
+
+X86ISA::IntReg
+X86_64LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < NumArgumentRegs);
+ return tc->readIntReg(ArgumentReg[i]);
+}
+
+void
+X86_64LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+{
+ assert(i < NumArgumentRegs);
+ return tc->setIntReg(ArgumentReg[i], val);
+}
+
+X86ISA::IntReg
+I386LiveProcess::getSyscallArg(ThreadContext *tc, int i)
+{
+ assert(i < NumArgumentRegs32);
+ return tc->readIntReg(ArgumentReg32[i]);
+}
+
+void
+I386LiveProcess::setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val)
+{
+ assert(i < NumArgumentRegs);
+ return tc->setIntReg(ArgumentReg[i], val);
+}
diff --git a/src/arch/x86/process.hh b/src/arch/x86/process.hh
index 5def9e13d..cd6d99e66 100644
--- a/src/arch/x86/process.hh
+++ b/src/arch/x86/process.hh
@@ -62,38 +62,76 @@
#include <vector>
#include "sim/process.hh"
+class SyscallDesc;
+
namespace X86ISA
{
- struct M5_64_auxv_t
+
+ class X86LiveProcess : public LiveProcess
{
- int64_t a_type;
- union {
- int64_t a_val;
- int64_t a_ptr;
- int64_t a_fcn;
- };
+ protected:
+ Addr _gdtStart;
+ Addr _gdtSize;
+
+ SyscallDesc *syscallDescs;
+ const int numSyscallDescs;
- M5_64_auxv_t()
- {}
+ X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile,
+ SyscallDesc *_syscallDescs, int _numSyscallDescs);
- M5_64_auxv_t(int64_t type, int64_t val);
+ template<class IntType>
+ void argsInit(int pageSize,
+ std::vector<AuxVector<IntType> > extraAuxvs);
+
+ public:
+ Addr gdtStart()
+ { return _gdtStart; }
+
+ Addr gdtSize()
+ { return _gdtSize; }
+
+ SyscallDesc* getDesc(int callnum);
+
+ void setSyscallReturn(ThreadContext *tc, SyscallReturn return_value);
};
- class X86LiveProcess : public LiveProcess
+ class X86_64LiveProcess : public X86LiveProcess
{
protected:
- std::vector<M5_64_auxv_t> auxv;
-
- X86LiveProcess(LiveProcessParams * params, ObjectFile *objFile);
+ X86_64LiveProcess(LiveProcessParams *params, ObjectFile *objFile,
+ SyscallDesc *_syscallDescs, int _numSyscallDescs);
+ public:
+ void argsInit(int intSize, int pageSize);
void startup();
- public:
+ X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
+ };
- //Handles traps which request services from the operating system
- virtual void handleTrap(int trapNum, ThreadContext *tc);
+ class I386LiveProcess : public X86LiveProcess
+ {
+ protected:
+ I386LiveProcess(LiveProcessParams *params, ObjectFile *objFile,
+ SyscallDesc *_syscallDescs, int _numSyscallDescs);
+ class VSyscallPage
+ {
+ public:
+ Addr base;
+ Addr size;
+ Addr vsyscallOffset;
+ Addr vsysexitOffset;
+ };
+ VSyscallPage vsyscallPage;
+
+ public:
void argsInit(int intSize, int pageSize);
+ void startup();
+
+ void syscall(int64_t callnum, ThreadContext *tc);
+ X86ISA::IntReg getSyscallArg(ThreadContext *tc, int i);
+ void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
};
}
diff --git a/src/arch/x86/regfile.cc b/src/arch/x86/regfile.cc
index c27ab08ba..7d01c4bb4 100644
--- a/src/arch/x86/regfile.cc
+++ b/src/arch/x86/regfile.cc
@@ -135,23 +135,23 @@ void RegFile::clear()
MiscReg RegFile::readMiscRegNoEffect(int miscReg)
{
- return miscRegFile.readRegNoEffect(miscReg);
+ return miscRegFile.readRegNoEffect((MiscRegIndex)miscReg);
}
MiscReg RegFile::readMiscReg(int miscReg, ThreadContext *tc)
{
- return miscRegFile.readReg(miscReg, tc);
+ return miscRegFile.readReg((MiscRegIndex)miscReg, tc);
}
void RegFile::setMiscRegNoEffect(int miscReg, const MiscReg &val)
{
- miscRegFile.setRegNoEffect(miscReg, val);
+ miscRegFile.setRegNoEffect((MiscRegIndex)miscReg, val);
}
void RegFile::setMiscReg(int miscReg, const MiscReg &val,
ThreadContext * tc)
{
- miscRegFile.setReg(miscReg, val, tc);
+ miscRegFile.setReg((MiscRegIndex)miscReg, val, tc);
}
FloatReg RegFile::readFloatReg(int floatReg, int width)
@@ -214,7 +214,7 @@ int X86ISA::flattenIntIndex(ThreadContext * tc, int reg)
//If we need to fold over the index to match byte semantics, do that.
//Otherwise, just strip off any extra bits and pass it through.
if (reg & (1 << 6))
- return (reg & ~(1 << 6) - 0x4);
+ return (reg & (~(1 << 6) - 0x4));
else
return (reg & ~(1 << 6));
}
@@ -228,7 +228,8 @@ int X86ISA::flattenFloatIndex(ThreadContext * tc, int reg)
return reg;
}
-void RegFile::serialize(std::ostream &os)
+void
+RegFile::serialize(EventManager *em, std::ostream &os)
{
intRegFile.serialize(os);
floatRegFile.serialize(os);
@@ -237,7 +238,8 @@ void RegFile::serialize(std::ostream &os)
SERIALIZE_SCALAR(nextRip);
}
-void RegFile::unserialize(Checkpoint *cp, const std::string &section)
+void
+RegFile::unserialize(EventManager *em, Checkpoint *cp, const string &section)
{
intRegFile.unserialize(cp, section);
floatRegFile.unserialize(cp, section);
@@ -246,11 +248,6 @@ void RegFile::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(nextRip);
}
-void RegFile::changeContext(RegContextParam param, RegContextVal val)
-{
- panic("changeContext not implemented for x86!\n");
-}
-
void X86ISA::copyMiscRegs(ThreadContext *src, ThreadContext *dest)
{
panic("copyMiscRegs not implemented for x86!\n");
diff --git a/src/arch/x86/regfile.hh b/src/arch/x86/regfile.hh
index 650181aca..8938ab0bc 100644
--- a/src/arch/x86/regfile.hh
+++ b/src/arch/x86/regfile.hh
@@ -68,6 +68,7 @@
#include <string>
class Checkpoint;
+class EventManager;
namespace X86ISA
{
@@ -96,8 +97,6 @@ namespace X86ISA
void clear();
- int FlattenIntIndex(int reg);
-
MiscReg readMiscRegNoEffect(int miscReg);
MiscReg readMiscReg(int miscReg, ThreadContext *tc);
@@ -139,12 +138,11 @@ namespace X86ISA
void setIntReg(int intReg, const IntReg &val);
- void serialize(std::ostream &os);
- void unserialize(Checkpoint *cp, const std::string &section);
+ void serialize(EventManager *em, std::ostream &os);
+ void unserialize(EventManager *em, Checkpoint *cp,
+ const std::string &section);
public:
-
- void changeContext(RegContextParam param, RegContextVal val);
};
int flattenIntIndex(ThreadContext * tc, int reg);
diff --git a/src/arch/x86/remote_gdb.cc b/src/arch/x86/remote_gdb.cc
index 5ab0ec3fb..c416042c8 100644
--- a/src/arch/x86/remote_gdb.cc
+++ b/src/arch/x86/remote_gdb.cc
@@ -57,7 +57,7 @@
/*
* Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -65,8 +65,8 @@
*
* 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.
+ * 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
@@ -78,8 +78,8 @@
* 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.
+ * 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.
@@ -96,7 +96,7 @@
* 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
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
*/
/*-
@@ -116,8 +116,8 @@
* 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.
+ * 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.
@@ -157,7 +157,7 @@
#include "cpu/thread_context.hh"
using namespace std;
-using namespace TheISA;
+using namespace X86ISA;
RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
: BaseRemoteGDB(_system, c, NumGDBRegs)
diff --git a/src/arch/x86/stacktrace.cc b/src/arch/x86/stacktrace.cc
index 300e8dcd0..87767583b 100644
--- a/src/arch/x86/stacktrace.cc
+++ b/src/arch/x86/stacktrace.cc
@@ -70,8 +70,6 @@ namespace X86ISA
if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
panic("thread info not compiled into kernel\n");
name_off = vp->readGtoH<int32_t>(addr);
-
- tc->delVirtPort(vp);
}
Addr
@@ -87,7 +85,6 @@ namespace X86ISA
vp = tc->getVirtPort();
tsk = vp->readGtoH<Addr>(base + task_off);
- tc->delVirtPort(vp);
return tsk;
}
@@ -105,7 +102,6 @@ namespace X86ISA
vp = tc->getVirtPort();
pd = vp->readGtoH<uint16_t>(task + pid_off);
- tc->delVirtPort(vp);
return pd;
}
diff --git a/src/arch/x86/system.cc b/src/arch/x86/system.cc
index 947a7793e..ed3dae4e6 100644
--- a/src/arch/x86/system.cc
+++ b/src/arch/x86/system.cc
@@ -55,13 +55,15 @@
* Authors: Gabe Black
*/
+#include "arch/x86/bios/smbios.hh"
+#include "arch/x86/bios/intelmp.hh"
#include "arch/x86/miscregs.hh"
#include "arch/x86/system.hh"
-#include "arch/x86/smbios.hh"
#include "arch/vtophys.hh"
-#include "base/remote_gdb.hh"
+#include "base/intmath.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
+#include "base/remote_gdb.hh"
#include "base/trace.hh"
#include "cpu/thread_context.hh"
#include "mem/physical.hh"
@@ -72,14 +74,12 @@
using namespace LittleEndianGuest;
using namespace X86ISA;
-X86System::X86System(Params *p)
- : System(p)
-{
- smbiosTable = new X86ISA::SMBios::SMBiosTable;
- smbiosTable->smbiosHeader.majorVersion = 2;
- smbiosTable->smbiosHeader.minorVersion = 5;
- smbiosTable->smbiosHeader.intermediateHeader.smbiosBCDRevision = 0x25;
-}
+X86System::X86System(Params *p) :
+ System(p), smbiosTable(p->smbios_table),
+ mpFloatingPointer(p->intel_mp_pointer),
+ mpConfigTable(p->intel_mp_table),
+ rsdp(p->acpi_description_table_pointer)
+{}
void
X86System::startup()
@@ -236,27 +236,67 @@ X86System::startup()
// We should now be in long mode. Yay!
+ Addr ebdaPos = 0xF0000;
+ Addr fixed, table;
+
//Write out the SMBios/DMI table
- writeOutSMBiosTable(0xF0000);
+ writeOutSMBiosTable(ebdaPos, fixed, table);
+ ebdaPos += (fixed + table);
+ ebdaPos = roundUp(ebdaPos, 16);
+
+ //Write out the Intel MP Specification configuration table
+ writeOutMPTable(ebdaPos, fixed, table);
+ ebdaPos += (fixed + table);
}
void
-X86System::writeOutSMBiosTable(Addr header, Addr table)
+X86System::writeOutSMBiosTable(Addr header,
+ Addr &headerSize, Addr &structSize, Addr table)
{
// Get a port to write the table and header to memory.
FunctionalPort * physPort = threadContexts[0]->getPhysPort();
// If the table location isn't specified, just put it after the header.
// The header size as of the 2.5 SMBios specification is 0x1F bytes
- if (!table) {
- if (!smbiosTable->smbiosHeader.intermediateHeader.tableAddr)
- smbiosTable->smbiosHeader.
- intermediateHeader.tableAddr = header + 0x1F;
- } else {
- smbiosTable->smbiosHeader.intermediateHeader.tableAddr = table;
+ if (!table)
+ table = header + 0x1F;
+ smbiosTable->setTableAddr(table);
+
+ smbiosTable->writeOut(physPort, header, headerSize, structSize);
+
+ // Do some bounds checking to make sure we at least didn't step on
+ // ourselves.
+ assert(header > table || header + headerSize <= table);
+ assert(table > header || table + structSize <= header);
+}
+
+void
+X86System::writeOutMPTable(Addr fp,
+ Addr &fpSize, Addr &tableSize, Addr table)
+{
+ // Get a port to write the table and header to memory.
+ FunctionalPort * physPort = threadContexts[0]->getPhysPort();
+
+ // If the table location isn't specified and it exists, just put
+ // it after the floating pointer. The fp size as of the 1.4 Intel MP
+ // specification is 0x10 bytes.
+ if (mpConfigTable) {
+ if (!table)
+ table = fp + 0x10;
+ mpFloatingPointer->setTableAddr(table);
}
- smbiosTable->writeOut(physPort, header);
+ fpSize = mpFloatingPointer->writeOut(physPort, fp);
+ if (mpConfigTable)
+ tableSize = mpConfigTable->writeOut(physPort, table);
+ else
+ tableSize = 0;
+
+ // Do some bounds checking to make sure we at least didn't step on
+ // ourselves and the fp structure was the size we thought it was.
+ assert(fp > table || fp + fpSize <= table);
+ assert(table > fp || table + tableSize <= fp);
+ assert(fpSize == 0x10);
}
diff --git a/src/arch/x86/system.hh b/src/arch/x86/system.hh
index 8a5483ebf..12a471f6f 100644
--- a/src/arch/x86/system.hh
+++ b/src/arch/x86/system.hh
@@ -74,6 +74,11 @@ namespace X86ISA
{
class SMBiosTable;
}
+ namespace IntelMP
+ {
+ class FloatingPointer;
+ class ConfigTable;
+ }
}
class X86System : public System
@@ -95,8 +100,15 @@ class X86System : public System
protected:
X86ISA::SMBios::SMBiosTable * smbiosTable;
+ X86ISA::IntelMP::FloatingPointer * mpFloatingPointer;
+ X86ISA::IntelMP::ConfigTable * mpConfigTable;
+ X86ISA::ACPI::RSDP * rsdp;
+
+ void writeOutSMBiosTable(Addr header,
+ Addr &headerSize, Addr &tableSize, Addr table = 0);
- void writeOutSMBiosTable(Addr header, Addr table = 0);
+ void writeOutMPTable(Addr fp,
+ Addr &fpSize, Addr &tableSize, Addr table = 0);
const Params *params() const { return (const Params *)_params; }
diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc
index a87abf212..3fec4c7da 100644
--- a/src/arch/x86/tlb.cc
+++ b/src/arch/x86/tlb.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 The Hewlett-Packard Development Company
+ * Copyright (c) 2007-2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
@@ -59,6 +59,7 @@
#include "config/full_system.hh"
+#include "arch/x86/insts/microldstop.hh"
#include "arch/x86/pagetable.hh"
#include "arch/x86/tlb.hh"
#include "arch/x86/x86_traits.hh"
@@ -72,6 +73,9 @@
#if FULL_SYSTEM
#include "arch/x86/pagetable_walker.hh"
+#else
+#include "mem/page_table.hh"
+#include "sim/process.hh"
#endif
namespace X86ISA {
@@ -90,7 +94,7 @@ TLB::TLB(const Params *p) : BaseTLB(p), configAddress(0), size(p->size)
#endif
}
-void
+TlbEntry *
TLB::insert(Addr vpn, TlbEntry &entry)
{
//TODO Deal with conflicting entries
@@ -106,6 +110,7 @@ TLB::insert(Addr vpn, TlbEntry &entry)
*newEntry = entry;
newEntry->vaddr = vpn;
entryList.push_front(newEntry);
+ return newEntry;
}
TLB::EntryList::iterator
@@ -138,14 +143,6 @@ TLB::lookup(Addr va, bool update_lru)
return *entry;
}
-#if FULL_SYSTEM
-void
-TLB::walk(ThreadContext * _tc, Addr vaddr)
-{
- walker->start(_tc, vaddr);
-}
-#endif
-
void
TLB::invalidateAll()
{
@@ -188,16 +185,18 @@ TLB::demapPage(Addr va, uint64_t asn)
}
}
-template<class TlbFault>
Fault
-TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
+TLB::translate(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write, bool execute,
+ bool &delayedResponse, bool timing)
{
+ delayedResponse = false;
Addr vaddr = req->getVaddr();
DPRINTF(TLB, "Translating vaddr %#x.\n", vaddr);
uint32_t flags = req->getFlags();
bool storeCheck = flags & StoreCheck;
- int seg = flags & mask(4);
+ int seg = flags & SegmentFlagMask;
//XXX Junk code to surpress the warning
if (storeCheck);
@@ -206,10 +205,11 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
// value.
if (seg == SEGMENT_REG_MS) {
DPRINTF(TLB, "Addresses references internal memory.\n");
- Addr prefix = vaddr & IntAddrPrefixMask;
+ Addr prefix = (vaddr >> 3) & IntAddrPrefixMask;
if (prefix == IntAddrPrefixCPUID) {
panic("CPUID memory space not yet implemented!\n");
} else if (prefix == IntAddrPrefixMSR) {
+ vaddr = vaddr >> 3;
req->setMmapedIpr(true);
Addr regNum = 0;
switch (vaddr & ~IntAddrPrefixMask) {
@@ -357,6 +357,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
case 0x410:
regNum = MISCREG_MC4_CTL;
break;
+ case 0x414:
+ regNum = MISCREG_MC5_CTL;
+ break;
+ case 0x418:
+ regNum = MISCREG_MC6_CTL;
+ break;
+ case 0x41C:
+ regNum = MISCREG_MC7_CTL;
+ break;
case 0x401:
regNum = MISCREG_MC0_STATUS;
break;
@@ -372,6 +381,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
case 0x411:
regNum = MISCREG_MC4_STATUS;
break;
+ case 0x415:
+ regNum = MISCREG_MC5_STATUS;
+ break;
+ case 0x419:
+ regNum = MISCREG_MC6_STATUS;
+ break;
+ case 0x41D:
+ regNum = MISCREG_MC7_STATUS;
+ break;
case 0x402:
regNum = MISCREG_MC0_ADDR;
break;
@@ -387,6 +405,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
case 0x412:
regNum = MISCREG_MC4_ADDR;
break;
+ case 0x416:
+ regNum = MISCREG_MC5_ADDR;
+ break;
+ case 0x41A:
+ regNum = MISCREG_MC6_ADDR;
+ break;
+ case 0x41E:
+ regNum = MISCREG_MC7_ADDR;
+ break;
case 0x403:
regNum = MISCREG_MC0_MISC;
break;
@@ -402,6 +429,15 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
case 0x413:
regNum = MISCREG_MC4_MISC;
break;
+ case 0x417:
+ regNum = MISCREG_MC5_MISC;
+ break;
+ case 0x41B:
+ regNum = MISCREG_MC6_MISC;
+ break;
+ case 0x41F:
+ regNum = MISCREG_MC7_MISC;
+ break;
case 0xC0000080:
regNum = MISCREG_EFER;
break;
@@ -510,7 +546,8 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
tc->readMiscRegNoEffect(MISCREG_PCI_CONFIG_ADDRESS);
if (bits(configAddress, 31, 31)) {
req->setPaddr(PhysAddrPrefixPciConfig |
- bits(configAddress, 30, 0));
+ mbits(configAddress, 30, 2) |
+ (IOPort & mask(2)));
}
} else {
req->setPaddr(PhysAddrPrefixIO | IOPort);
@@ -534,35 +571,38 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
// If we're not in 64-bit mode, do protection/limit checks
if (!efer.lma || !csAttr.longMode) {
DPRINTF(TLB, "Not in long mode. Checking segment protection.\n");
- SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
- if (!attr.writable && write)
- return new GeneralProtection(0);
- if (!attr.readable && !write && !execute)
+ // Check for a NULL segment selector.
+ if (!tc->readMiscRegNoEffect(MISCREG_SEG_SEL(seg)))
return new GeneralProtection(0);
+ bool expandDown = false;
+ SegAttr attr = tc->readMiscRegNoEffect(MISCREG_SEG_ATTR(seg));
+ if (seg >= SEGMENT_REG_ES && seg <= SEGMENT_REG_HS) {
+ if (!attr.writable && write)
+ return new GeneralProtection(0);
+ if (!attr.readable && !write && !execute)
+ return new GeneralProtection(0);
+ expandDown = attr.expandDown;
+
+ }
Addr base = tc->readMiscRegNoEffect(MISCREG_SEG_BASE(seg));
Addr limit = tc->readMiscRegNoEffect(MISCREG_SEG_LIMIT(seg));
- if (!attr.expandDown) {
+ // This assumes we're not in 64 bit mode. If we were, the default
+ // address size is 64 bits, overridable to 32.
+ int size = 32;
+ bool sizeOverride = (flags & (AddrSizeFlagBit << FlagShift));
+ if ((csAttr.defaultSize && sizeOverride) ||
+ (!csAttr.defaultSize && !sizeOverride))
+ size = 16;
+ Addr offset = bits(vaddr - base, size-1, 0);
+ Addr endOffset = offset + req->getSize() - 1;
+ if (expandDown) {
DPRINTF(TLB, "Checking an expand down segment.\n");
- // We don't have to worry about the access going around the
- // end of memory because accesses will be broken up into
- // pieces at boundaries aligned on sizes smaller than an
- // entire address space. We do have to worry about the limit
- // being less than the base.
- if (limit < base) {
- if (limit < vaddr + req->getSize() && vaddr < base)
- return new GeneralProtection(0);
- } else {
- if (limit < vaddr + req->getSize())
- return new GeneralProtection(0);
- }
+ warn_once("Expand down segments are untested.\n");
+ if (offset <= limit || endOffset <= limit)
+ return new GeneralProtection(0);
} else {
- if (limit < base) {
- if (vaddr <= limit || vaddr + req->getSize() >= base)
- return new GeneralProtection(0);
- } else {
- if (vaddr <= limit && vaddr + req->getSize() >= base)
- return new GeneralProtection(0);
- }
+ if (offset > limit || endOffset > limit)
+ return new GeneralProtection(0);
}
}
// If paging is enabled, do the translation.
@@ -571,14 +611,57 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
// The vaddr already has the segment base applied.
TlbEntry *entry = lookup(vaddr);
if (!entry) {
- return new TlbFault(vaddr);
- } else {
- // Do paging protection checks.
- DPRINTF(TLB, "Entry found with paddr %#x, doing protection checks.\n", entry->paddr);
- Addr paddr = entry->paddr | (vaddr & (entry->size-1));
- DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
- req->setPaddr(paddr);
+#if FULL_SYSTEM
+ Fault fault = walker->start(tc, translation, req,
+ write, execute);
+ if (timing || fault != NoFault) {
+ // This gets ignored in atomic mode.
+ delayedResponse = true;
+ return fault;
+ }
+ entry = lookup(vaddr);
+ assert(entry);
+#else
+ DPRINTF(TLB, "Handling a TLB miss for "
+ "address %#x at pc %#x.\n",
+ vaddr, tc->readPC());
+
+ Process *p = tc->getProcessPtr();
+ TlbEntry newEntry;
+ bool success = p->pTable->lookup(vaddr, newEntry);
+ if(!success && !execute) {
+ p->checkAndAllocNextPage(vaddr);
+ success = p->pTable->lookup(vaddr, newEntry);
+ }
+ if(!success) {
+ panic("Tried to execute unmapped address %#x.\n", vaddr);
+ } else {
+ Addr alignedVaddr = p->pTable->pageAlign(vaddr);
+ DPRINTF(TLB, "Mapping %#x to %#x\n", alignedVaddr,
+ newEntry.pageStart());
+ entry = insert(alignedVaddr, newEntry);
+ }
+ DPRINTF(TLB, "Miss was serviced.\n");
+#endif
}
+ // Do paging protection checks.
+ bool inUser = (csAttr.dpl == 3 &&
+ !(flags & (CPL0FlagBit << FlagShift)));
+ if ((inUser && !entry->user) ||
+ (write && !entry->writable)) {
+ // The page must have been present to get into the TLB in
+ // the first place. We'll assume the reserved bits are
+ // fine even though we're not checking them.
+ return new PageFault(vaddr, true, write,
+ inUser, false, execute);
+ }
+
+
+ DPRINTF(TLB, "Entry found with paddr %#x, "
+ "doing protection checks.\n", entry->paddr);
+ Addr paddr = entry->paddr | (vaddr & (entry->size-1));
+ DPRINTF(TLB, "Translated %#x -> %#x.\n", vaddr, paddr);
+ req->setPaddr(paddr);
} else {
//Use the address which already has segmentation applied.
DPRINTF(TLB, "Paging disabled.\n");
@@ -592,160 +675,68 @@ TLB::translate(RequestPtr &req, ThreadContext *tc, bool write, bool execute)
req->setPaddr(vaddr);
}
// Check for an access to the local APIC
+#if FULL_SYSTEM
LocalApicBase localApicBase = tc->readMiscRegNoEffect(MISCREG_APIC_BASE);
- Addr baseAddr = localApicBase.base << 12;
+ Addr baseAddr = localApicBase.base * PageBytes;
Addr paddr = req->getPaddr();
- if (baseAddr <= paddr && baseAddr + (1 << 12) > paddr) {
- req->setMmapedIpr(true);
+ if (baseAddr <= paddr && baseAddr + PageBytes > paddr) {
+ // The Intel developer's manuals say the below restrictions apply,
+ // but the linux kernel, because of a compiler optimization, breaks
+ // them.
+ /*
// Check alignment
if (paddr & ((32/8) - 1))
return new GeneralProtection(0);
// Check access size
if (req->getSize() != (32/8))
return new GeneralProtection(0);
- MiscReg regNum;
- switch (paddr - baseAddr)
- {
- case 0x20:
- regNum = MISCREG_APIC_ID;
- break;
- case 0x30:
- regNum = MISCREG_APIC_VERSION;
- break;
- case 0x80:
- regNum = MISCREG_APIC_TASK_PRIORITY;
- break;
- case 0x90:
- regNum = MISCREG_APIC_ARBITRATION_PRIORITY;
- break;
- case 0xA0:
- regNum = MISCREG_APIC_PROCESSOR_PRIORITY;
- break;
- case 0xB0:
- regNum = MISCREG_APIC_EOI;
- break;
- case 0xD0:
- regNum = MISCREG_APIC_LOGICAL_DESTINATION;
- break;
- case 0xE0:
- regNum = MISCREG_APIC_DESTINATION_FORMAT;
- break;
- case 0xF0:
- regNum = MISCREG_APIC_SPURIOUS_INTERRUPT_VECTOR;
- break;
- case 0x100:
- case 0x108:
- case 0x110:
- case 0x118:
- case 0x120:
- case 0x128:
- case 0x130:
- case 0x138:
- case 0x140:
- case 0x148:
- case 0x150:
- case 0x158:
- case 0x160:
- case 0x168:
- case 0x170:
- case 0x178:
- regNum = MISCREG_APIC_IN_SERVICE(
- (paddr - baseAddr - 0x100) / 0x8);
- break;
- case 0x180:
- case 0x188:
- case 0x190:
- case 0x198:
- case 0x1A0:
- case 0x1A8:
- case 0x1B0:
- case 0x1B8:
- case 0x1C0:
- case 0x1C8:
- case 0x1D0:
- case 0x1D8:
- case 0x1E0:
- case 0x1E8:
- case 0x1F0:
- case 0x1F8:
- regNum = MISCREG_APIC_TRIGGER_MODE(
- (paddr - baseAddr - 0x180) / 0x8);
- break;
- case 0x200:
- case 0x208:
- case 0x210:
- case 0x218:
- case 0x220:
- case 0x228:
- case 0x230:
- case 0x238:
- case 0x240:
- case 0x248:
- case 0x250:
- case 0x258:
- case 0x260:
- case 0x268:
- case 0x270:
- case 0x278:
- regNum = MISCREG_APIC_INTERRUPT_REQUEST(
- (paddr - baseAddr - 0x200) / 0x8);
- break;
- case 0x280:
- regNum = MISCREG_APIC_ERROR_STATUS;
- break;
- case 0x300:
- regNum = MISCREG_APIC_INTERRUPT_COMMAND_LOW;
- break;
- case 0x310:
- regNum = MISCREG_APIC_INTERRUPT_COMMAND_HIGH;
- break;
- case 0x320:
- regNum = MISCREG_APIC_LVT_TIMER;
- break;
- case 0x330:
- regNum = MISCREG_APIC_LVT_THERMAL_SENSOR;
- break;
- case 0x340:
- regNum = MISCREG_APIC_LVT_PERFORMANCE_MONITORING_COUNTERS;
- break;
- case 0x350:
- regNum = MISCREG_APIC_LVT_LINT0;
- break;
- case 0x360:
- regNum = MISCREG_APIC_LVT_LINT1;
- break;
- case 0x370:
- regNum = MISCREG_APIC_LVT_ERROR;
- break;
- case 0x380:
- regNum = MISCREG_APIC_INITIAL_COUNT;
- break;
- case 0x390:
- regNum = MISCREG_APIC_CURRENT_COUNT;
- break;
- case 0x3E0:
- regNum = MISCREG_APIC_DIVIDE_COUNT;
- break;
- default:
- // A reserved register field.
- return new GeneralProtection(0);
- break;
- }
- req->setPaddr(regNum * sizeof(MiscReg));
+ */
+ // Force the access to be uncacheable.
+ req->setFlags(Request::UNCACHEABLE);
+ req->setPaddr(x86LocalAPICAddress(tc->contextId(), paddr - baseAddr));
}
+#endif
return NoFault;
};
Fault
-DTB::translate(RequestPtr &req, ThreadContext *tc, bool write)
+DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
+{
+ bool delayedResponse;
+ return TLB::translate(req, tc, NULL, write,
+ false, delayedResponse, false);
+}
+
+void
+DTB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
{
- return TLB::translate<FakeDTLBFault>(req, tc, write, false);
+ bool delayedResponse;
+ assert(translation);
+ Fault fault = TLB::translate(req, tc, translation,
+ write, false, delayedResponse, true);
+ if (!delayedResponse)
+ translation->finish(fault, req, tc, write);
}
Fault
-ITB::translate(RequestPtr &req, ThreadContext *tc)
+ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
+{
+ bool delayedResponse;
+ return TLB::translate(req, tc, NULL, false,
+ true, delayedResponse, false);
+}
+
+void
+ITB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation)
{
- return TLB::translate<FakeITLBFault>(req, tc, false, true);
+ bool delayedResponse;
+ assert(translation);
+ Fault fault = TLB::translate(req, tc, translation,
+ false, true, delayedResponse, true);
+ if (!delayedResponse)
+ translation->finish(fault, req, tc, false);
}
#if FULL_SYSTEM
diff --git a/src/arch/x86/tlb.hh b/src/arch/x86/tlb.hh
index 89b965e97..2467bc472 100644
--- a/src/arch/x86/tlb.hh
+++ b/src/arch/x86/tlb.hh
@@ -87,8 +87,7 @@ namespace X86ISA
class TLB : public BaseTLB
{
protected:
- friend class FakeITLBFault;
- friend class FakeDTLBFault;
+ friend class Walker;
typedef std::list<TlbEntry *> EntryList;
@@ -118,8 +117,6 @@ namespace X86ISA
protected:
Walker * walker;
-
- void walk(ThreadContext * _tc, Addr vaddr);
#endif
public:
@@ -137,13 +134,13 @@ namespace X86ISA
EntryList freeList;
EntryList entryList;
- template<class TlbFault>
- Fault translate(RequestPtr &req, ThreadContext *tc,
- bool write, bool execute);
+ Fault translate(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write, bool execute,
+ bool &delayedResponse, bool timing);
public:
- void insert(Addr vpn, TlbEntry &entry);
+ TlbEntry * insert(Addr vpn, TlbEntry &entry);
// Checkpointing
virtual void serialize(std::ostream &os);
@@ -159,7 +156,9 @@ namespace X86ISA
_allowNX = false;
}
- Fault translate(RequestPtr &req, ThreadContext *tc);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation);
friend class DTB;
};
@@ -172,7 +171,9 @@ namespace X86ISA
{
_allowNX = true;
}
- Fault translate(RequestPtr &req, ThreadContext *tc, bool write);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write);
#if FULL_SYSTEM
Tick doMmuRegRead(ThreadContext *tc, Packet *pkt);
Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt);
diff --git a/src/arch/x86/types.hh b/src/arch/x86/types.hh
index 90df38d13..29420352b 100644
--- a/src/arch/x86/types.hh
+++ b/src/arch/x86/types.hh
@@ -246,17 +246,6 @@ namespace X86ISA
MiscReg ctrlReg;
} AnyReg;
- //XXX This is very hypothetical. X87 instructions would need to
- //change their "context" constantly. It's also not clear how
- //this would be handled as far as out of order execution.
- //Maybe x87 instructions are in order?
- enum RegContextParam
- {
- CONTEXT_X87_TOP
- };
-
- typedef int RegContextVal;
-
typedef uint16_t RegIndex;
struct CoreSpecific {
diff --git a/src/arch/x86/utility.cc b/src/arch/x86/utility.cc
index 5fe5bf8c3..43a5ca1a9 100644
--- a/src/arch/x86/utility.cc
+++ b/src/arch/x86/utility.cc
@@ -55,11 +55,17 @@
* Authors: Gabe Black
*/
+#include "config/full_system.hh"
+
+#if FULL_SYSTEM
+#include "arch/x86/interrupts.hh"
+#endif
#include "arch/x86/intregs.hh"
#include "arch/x86/miscregs.hh"
#include "arch/x86/segmentregs.hh"
#include "arch/x86/utility.hh"
#include "arch/x86/x86_traits.hh"
+#include "cpu/base.hh"
#include "sim/system.hh"
namespace X86ISA {
@@ -254,9 +260,15 @@ void initCPU(ThreadContext *tc, int cpuId)
lApicBase.bsp = (cpuId == 0);
tc->setMiscReg(MISCREG_APIC_BASE, lApicBase);
- tc->setMiscRegNoEffect(MISCREG_APIC_ID, cpuId << 24);
+ Interrupts * interrupts = dynamic_cast<Interrupts *>(
+ tc->getCpuPtr()->getInterruptController());
+ assert(interrupts);
+
+ interrupts->setRegNoEffect(APIC_ID, cpuId << 24);
- tc->setMiscRegNoEffect(MISCREG_APIC_VERSION, (5 << 16) | 0x14);
+ interrupts->setRegNoEffect(APIC_VERSION, (5 << 16) | 0x14);
+
+ interrupts->setClock(tc->getCpuPtr()->ticks(16));
// TODO Set the SMRAM base address (SMBASE) to 0x00030000
diff --git a/src/arch/x86/utility.hh b/src/arch/x86/utility.hh
index 477a76e0b..6f0812a6a 100644
--- a/src/arch/x86/utility.hh
+++ b/src/arch/x86/utility.hh
@@ -93,7 +93,12 @@ namespace X86ISA
static inline bool
inUserMode(ThreadContext *tc)
{
- return false;
+#if FULL_SYSTEM
+ HandyM5Reg m5reg = tc->readMiscRegNoEffect(MISCREG_M5_REG);
+ return m5reg.cpl == 3;
+#else
+ return true;
+#endif
}
inline bool isCallerSaveIntegerRegister(unsigned int reg) {
diff --git a/src/arch/x86/x86_traits.hh b/src/arch/x86/x86_traits.hh
index d605ce218..0347a7099 100644
--- a/src/arch/x86/x86_traits.hh
+++ b/src/arch/x86/x86_traits.hh
@@ -55,11 +55,13 @@
* Authors: Gabe Black
*/
-#include "sim/host.hh"
-
#ifndef __ARCH_X86_X86TRAITS_HH__
#define __ARCH_X86_X86TRAITS_HH__
+#include <assert.h>
+
+#include "sim/host.hh"
+
namespace X86ISA
{
const int NumMicroIntRegs = 16;
@@ -90,6 +92,37 @@ namespace X86ISA
const Addr PhysAddrPrefixIO = ULL(0x8000000000000000);
const Addr PhysAddrPrefixPciConfig = ULL(0xC000000000000000);
+ const Addr PhysAddrPrefixLocalAPIC = ULL(0x2000000000000000);
+ const Addr PhysAddrPrefixInterrupts = ULL(0xA000000000000000);
+ // Each APIC gets two pages. One page is used for local apics to field
+ // accesses from the CPU, and the other is for all APICs to communicate.
+ const Addr PhysAddrAPICRangeSize = 1 << 12;
+
+ static inline Addr
+ x86IOAddress(const uint32_t port)
+ {
+ return PhysAddrPrefixIO | port;
+ }
+
+ static inline Addr
+ x86PciConfigAddress(const uint32_t addr)
+ {
+ return PhysAddrPrefixPciConfig | addr;
+ }
+
+ static inline Addr
+ x86LocalAPICAddress(const uint8_t id, const uint16_t addr)
+ {
+ assert(addr < (1 << 12));
+ return PhysAddrPrefixLocalAPIC | (id * (1 << 12)) | addr;
+ }
+
+ static inline Addr
+ x86InterruptAddress(const uint8_t id, const uint16_t addr)
+ {
+ assert(addr < PhysAddrAPICRangeSize);
+ return PhysAddrPrefixInterrupts | (id * PhysAddrAPICRangeSize) | addr;
+ }
}
#endif //__ARCH_X86_X86TRAITS_HH__
diff --git a/src/base/CPA.py b/src/base/CPA.py
new file mode 100644
index 000000000..c0beaedef
--- /dev/null
+++ b/src/base/CPA.py
@@ -0,0 +1,8 @@
+from m5.SimObject import SimObject
+from m5.params import *
+
+class CPA(SimObject):
+ type = 'CPA'
+
+ enabled = Param.Bool(False, "Is Annotation enabled?")
+ user_apps = VectorParam.String([], "List of apps to get symbols for")
diff --git a/src/base/SConscript b/src/base/SConscript
index f9d936d84..58c453184 100644
--- a/src/base/SConscript
+++ b/src/base/SConscript
@@ -30,11 +30,15 @@
Import('*')
-Source('annotate.cc')
+if env['CP_ANNOTATE']:
+ SimObject('CPA.py')
+ Source('cp_annotate.cc')
+Source('atomicio.cc')
Source('bigint.cc')
Source('circlebuf.cc')
Source('cprintf.cc')
Source('crc.cc')
+Source('debug.cc')
Source('fast_alloc.cc')
if env['USE_FENV']:
Source('fenv.c')
@@ -72,7 +76,6 @@ Source('loader/symtab.cc')
Source('stats/events.cc')
Source('stats/output.cc')
-Source('stats/statdb.cc')
Source('stats/text.cc')
Source('stats/visit.cc')
@@ -80,16 +83,23 @@ if env['USE_MYSQL']:
Source('mysql.cc')
Source('stats/mysql.cc')
-TraceFlag('Annotate')
-TraceFlag('GDBAcc')
-TraceFlag('GDBExtra')
-TraceFlag('GDBMisc')
-TraceFlag('GDBRead')
-TraceFlag('GDBRecv')
-TraceFlag('GDBSend')
-TraceFlag('GDBWrite')
-TraceFlag('SQL')
-TraceFlag('StatEvents')
+TraceFlag('Annotate', "State machine annotation debugging")
+TraceFlag('AnnotateQ', "State machine annotation queue debugging")
+TraceFlag('AnnotateVerbose', "Dump all state machine annotation details")
+TraceFlag('GDBAcc', "Remote debugger accesses")
+TraceFlag('GDBExtra', "Dump extra information on reads and writes")
+TraceFlag('GDBMisc', "Breakpoints, traps, watchpoints, etc.")
+TraceFlag('GDBRead', "Reads to the remote address space")
+TraceFlag('GDBRecv', "Messages received from the remote application")
+TraceFlag('GDBSend', "Messages sent to the remote application")
+TraceFlag('GDBWrite', "Writes to the remote address space")
+TraceFlag('SQL', "SQL queries sent to the server")
+TraceFlag('StatEvents', "Statistics event tracking")
+
+CompoundFlag('GDBAll',
+ [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend', 'GDBRecv',
+ 'GDBExtra' ],
+ desc="All Remote debugging flags")
+CompoundFlag('AnnotateAll', ['Annotate', 'AnnotateQ', 'AnnotateVerbose'],
+ desc="All Annotation flags")
-CompoundFlag('GDBAll', [ 'GDBMisc', 'GDBAcc', 'GDBRead', 'GDBWrite', 'GDBSend',
- 'GDBRecv', 'GDBExtra' ])
diff --git a/src/base/annotate.cc b/src/base/annotate.cc
deleted file mode 100644
index de7eeed51..000000000
--- a/src/base/annotate.cc
+++ /dev/null
@@ -1,122 +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.
- *
- * Authors: Ali Saidi
- */
-
-#include "base/annotate.hh"
-#include "base/callback.hh"
-#include "base/output.hh"
-#include "base/trace.hh"
-#include "sim/core.hh"
-#include "sim/sim_exit.hh"
-#include "sim/system.hh"
-
-
-
-class AnnotateDumpCallback : public Callback
-{
- public:
- virtual void process();
-};
-
-void
-AnnotateDumpCallback::process()
-{
- Annotate::annotations.dump();
-}
-
-namespace Annotate {
-
-
-Annotate annotations;
-
-Annotate::Annotate()
-{
- registerExitCallback(new AnnotateDumpCallback);
-}
-
-void
-Annotate::add(System *sys, Addr stack, uint32_t sm, uint32_t st,
- uint32_t wm, uint32_t ws)
-{
- AnnotateData *an;
-
- an = new AnnotateData;
- an->time = curTick;
-
- std::map<System*, std::string>::iterator i = nameCache.find(sys);
- if (i == nameCache.end()) {
- nameCache[sys] = sys->name();
- }
-
- an->system = nameCache[sys];
- an->stack = stack;
- an->stateMachine = sm;
- an->curState = st;
- an->waitMachine = wm;
- an->waitState = ws;
-
- data.push_back(an);
- if (an->waitMachine)
- DPRINTF(Annotate, "Annotating: %s(%#llX) %d:%d waiting on %d:%d\n",
- an->system, an->stack, an->stateMachine, an->curState,
- an->waitMachine, an->waitState);
- else
- DPRINTF(Annotate, "Annotating: %s(%#llX) %d:%d beginning\n", an->system,
- an->stack, an->stateMachine, an->curState);
-
- DPRINTF(Annotate, "Now %d events on list\n", data.size());
-
-}
-
-void
-Annotate::dump()
-{
-
- std::list<AnnotateData*>::iterator i;
-
- i = data.begin();
-
- if (i == data.end())
- return;
-
- std::ostream *os = simout.create("annotate.dat");
-
- AnnotateData *an;
-
- while (i != data.end()) {
- DPRINTF(Annotate, "Writing\n", data.size());
- an = *i;
- ccprintf(*os, "%d %s(%#llX) %d %d %d %d\n", an->time, an->system,
- an->stack, an->stateMachine, an->curState, an->waitMachine,
- an->waitState);
- i++;
- }
-}
-
-} //namespace Annotate
diff --git a/src/unittest/offtest.cc b/src/base/atomicio.cc
index ebfb2515c..3f3e6d6f0 100644
--- a/src/unittest/offtest.cc
+++ b/src/base/atomicio.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,45 +28,65 @@
* Authors: Nathan Binkert
*/
-#include <sys/types.h>
-#include <stddef.h>
-#include <stdio.h>
-#include "dev/pcireg.h"
+#include <cerrno>
+#include <cstdio>
-int
-main()
+#include "base/atomicio.hh"
+
+ssize_t
+atomic_read(int fd, void *s, size_t n)
+{
+ char *p = reinterpret_cast<char *>(s);
+ ssize_t pos = 0;
+
+ // Keep reading until we've gotten all of the data.
+ while (n > pos) {
+ ssize_t result = read(fd, p + pos, n - pos);
+
+ // We didn't get any more data, so we should probably punt,
+ // otherwise we'd just keep spinning
+ if (result == 0)
+ break;
+
+ // If there was an error, try again on EINTR/EAGAIN, pass the
+ // error up otherwise.
+ if (result == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return result;
+ }
+
+ pos += result;
+ }
+
+ return pos;
+}
+
+ssize_t
+atomic_write(int fd, const void *s, size_t n)
{
-#define POFFSET(x) \
- printf("offsetof(PCIConfig, hdr."#x") = %d\n", \
- offsetof(PCIConfig, hdr.x))
+ const char *p = reinterpret_cast<const char *>(s);
+ ssize_t pos = 0;
+
+ // Keep writing until we've written all of the data
+ while (n > pos) {
+ ssize_t result = write(fd, p + pos, n - pos);
+
+ // We didn't manage to write anything this time, so we should
+ // probably punt, otherwise we'd just keep spinning
+ if (result == 0)
+ break;
+
+ // If there was an error, try again on EINTR/EAGAIN, pass the
+ // error up otherwise.
+ if (result == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return result;
+ }
- POFFSET(vendor);
- POFFSET(device);
- POFFSET(command);
- POFFSET(status);
- POFFSET(revision);
- POFFSET(progIF);
- POFFSET(subClassCode);
- POFFSET(classCode);
- POFFSET(cacheLineSize);
- POFFSET(latencyTimer);
- POFFSET(headerType);
- POFFSET(bist);
- POFFSET(pci0.baseAddr0);
- POFFSET(pci0.baseAddr1);
- POFFSET(pci0.baseAddr2);
- POFFSET(pci0.baseAddr3);
- POFFSET(pci0.baseAddr4);
- POFFSET(pci0.baseAddr5);
- POFFSET(pci0.cardbusCIS);
- POFFSET(pci0.subsystemVendorID);
- POFFSET(pci0.expansionROM);
- POFFSET(pci0.reserved0);
- POFFSET(pci0.reserved1);
- POFFSET(pci0.interruptLine);
- POFFSET(pci0.interruptPin);
- POFFSET(pci0.minimumGrant);
- POFFSET(pci0.minimumLatency);
+ pos += result;
+ }
- return 0;
+ return pos;
}
diff --git a/src/base/atomicio.hh b/src/base/atomicio.hh
new file mode 100644
index 000000000..5e703f315
--- /dev/null
+++ b/src/base/atomicio.hh
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __BASE_ATOMICIO_HH__
+#define __BASE_ATOMICIO_HH__
+
+#include <unistd.h>
+
+// These functions keep reading/writing, if possible, until all data
+// has been transferred. Basically, try again when there's no error,
+// but there is data left also retry on EINTR.
+// This function blocks until it is done.
+
+ssize_t atomic_read(int fd, void *s, size_t n);
+ssize_t atomic_write(int fd, const void *s, size_t n);
+
+#endif // __BASE_ATOMICIO_HH__
diff --git a/src/base/bitunion.hh b/src/base/bitunion.hh
index 7f7b06966..8ba28f3ba 100644
--- a/src/base/bitunion.hh
+++ b/src/base/bitunion.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2007-2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,7 @@
#include <inttypes.h>
#include "base/bitfield.hh"
-// The following implements the BitUnion system of defining bitfields
+// The following implements the BitUnion system of defining bitfields
//on top of an underlying class. This is done through the pervasive use of
//both named and unnamed unions which all contain the same actual storage.
//Since they're unioned with each other, all of these storage locations
@@ -242,11 +242,7 @@ namespace BitfieldBackend
//bitfields which are defined in the union, creating shared storage with no
//overhead.
#define __BitUnion(type, name) \
- namespace BitfieldUnderlyingClasses \
- { \
- class name; \
- } \
- class BitfieldUnderlyingClasses::name : \
+ class BitfieldUnderlyingClasses##name : \
public BitfieldBackend::BitfieldTypes<type> \
{ \
public: \
@@ -262,8 +258,8 @@ namespace BitfieldBackend
}; \
}; \
typedef BitfieldBackend::BitUnionOperators< \
- BitfieldUnderlyingClasses::name::__DataType, \
- BitfieldUnderlyingClasses::name> name;
+ BitfieldUnderlyingClasses##name::__DataType, \
+ BitfieldUnderlyingClasses##name> name;
//This sets up a bitfield which has other bitfields nested inside of it. The
//__data member functions like the "underlying storage" of the top level
diff --git a/src/base/cast.hh b/src/base/cast.hh
new file mode 100644
index 000000000..30a065cd2
--- /dev/null
+++ b/src/base/cast.hh
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __BASE_CAST_HH__
+#define __BASE_CAST_HH__
+
+#include <cassert>
+
+// This is designed for situations where we have a pointer to a base
+// type, but in all cases when we cast it to a derived type, we know
+// by construction that it should work correctly.
+
+#if defined(DEBUG)
+
+// In debug builds, do the dynamic cast and assert the result is good
+
+template <class T, class U>
+inline T
+safe_cast(U ptr)
+{
+ T ret = dynamic_cast<T>(ptr);
+ assert(ret);
+ return ret;
+}
+
+#else
+
+// In non debug builds statically cast the result to the pointer we
+// want to use. This is technically unsafe, but this is only for
+// cases where we know that this should work by construction.
+
+template <class T, class U>
+inline T
+safe_cast(U ptr)
+{
+ return static_cast<T>(ptr);
+}
+
+#endif
+
+#endif // __BASE_CAST_HH__
diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh
index e8238464b..d2ae45d1e 100644
--- a/src/base/chunk_generator.hh
+++ b/src/base/chunk_generator.hh
@@ -82,6 +82,7 @@ class ChunkGenerator
{
// chunkSize must be a power of two
assert(chunkSize == 0 || isPowerOf2(chunkSize));
+ assert(totalSize >= 0);
// set up initial chunk.
curAddr = startAddr;
diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc
index a0c015671..06d0075b2 100644
--- a/src/base/circlebuf.cc
+++ b/src/base/circlebuf.cc
@@ -29,12 +29,11 @@
*/
#include <algorithm>
+#include <cstdio>
+#include <cstring>
#include <string>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
+#include "base/atomicio.hh"
#include "base/circlebuf.hh"
#include "base/cprintf.hh"
#include "base/intmath.hh"
@@ -59,8 +58,8 @@ CircleBuf::dump()
cprintf("start = %10d, stop = %10d, buflen = %10d\n",
_start, _stop, _buflen);
fflush(stdout);
- ::write(STDOUT_FILENO, _buf, _buflen);
- ::write(STDOUT_FILENO, "<\n", 2);
+ atomic_write(STDOUT_FILENO, _buf, _buflen);
+ atomic_write(STDOUT_FILENO, "<\n", 2);
}
void
@@ -106,19 +105,19 @@ CircleBuf::read(int fd, int len)
if (_stop > _start) {
len = min(len, _stop - _start);
- ::write(fd, _buf + _start, len);
+ atomic_write(fd, _buf + _start, len);
_start += len;
}
else {
int endlen = _buflen - _start;
if (endlen > len) {
- ::write(fd, _buf + _start, len);
+ atomic_write(fd, _buf + _start, len);
_start += len;
}
else {
- ::write(fd, _buf + _start, endlen);
+ atomic_write(fd, _buf + _start, endlen);
_start = min(len - endlen, _stop);
- ::write(fd, _buf, _start);
+ atomic_write(fd, _buf, _start);
}
}
}
@@ -129,11 +128,11 @@ CircleBuf::read(int fd)
_size = 0;
if (_stop > _start) {
- ::write(fd, _buf + _start, _stop - _start);
+ atomic_write(fd, _buf + _start, _stop - _start);
}
else {
- ::write(fd, _buf + _start, _buflen - _start);
- ::write(fd, _buf, _stop);
+ atomic_write(fd, _buf + _start, _buflen - _start);
+ atomic_write(fd, _buf, _stop);
}
_start = _stop;
@@ -159,9 +158,9 @@ void
CircleBuf::readall(int fd)
{
if (_rollover)
- ::write(fd, _buf + _stop, _buflen - _stop);
+ atomic_write(fd, _buf + _stop, _buflen - _stop);
- ::write(fd, _buf, _stop);
+ atomic_write(fd, _buf, _stop);
_start = _stop;
}
@@ -209,7 +208,7 @@ CircleBuf::write(const char *b, int len)
_rollover = true;
}
- if (old_start > old_stop && old_start < _stop ||
- old_start < old_stop && _stop < old_stop)
+ if ((old_start > old_stop && old_start < _stop) ||
+ (old_start < old_stop && _stop < old_stop))
_start = _stop + 1;
}
diff --git a/src/base/cp_annotate.cc b/src/base/cp_annotate.cc
new file mode 100644
index 000000000..0aba2d999
--- /dev/null
+++ b/src/base/cp_annotate.cc
@@ -0,0 +1,1404 @@
+/*
+ * Copyright (c) 2006-2009 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "arch/utility.hh"
+#include "arch/alpha/linux/threadinfo.hh"
+#include "base/cp_annotate.hh"
+#include "base/callback.hh"
+#include "base/loader/object_file.hh"
+#include "base/output.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "sim/arguments.hh"
+#include "sim/core.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+
+struct CPAIgnoreSymbol
+{
+ const char *symbol;
+ size_t len;
+};
+#define CPA_IGNORE_SYMBOL(sym) { #sym, sizeof(#sym) }
+
+CPAIgnoreSymbol ignoreSymbols[] = {
+ CPA_IGNORE_SYMBOL("m5a_"),
+ CPA_IGNORE_SYMBOL("ret_from_sys_call"),
+ CPA_IGNORE_SYMBOL("ret_from_reschedule"),
+ CPA_IGNORE_SYMBOL("_spin_"),
+ CPA_IGNORE_SYMBOL("local_bh_"),
+ CPA_IGNORE_SYMBOL("restore_all"),
+ CPA_IGNORE_SYMBOL("Call_Pal_"),
+ CPA_IGNORE_SYMBOL("pal_post_interrupt"),
+ CPA_IGNORE_SYMBOL("rti_to_"),
+ CPA_IGNORE_SYMBOL("sys_int_2"),
+ CPA_IGNORE_SYMBOL("sys_interrupt"),
+ CPA_IGNORE_SYMBOL("normal_int"),
+ CPA_IGNORE_SYMBOL("TRAP_INTERRUPT_10_"),
+ CPA_IGNORE_SYMBOL("Trap_Interrupt"),
+ CPA_IGNORE_SYMBOL("do_entInt"),
+ CPA_IGNORE_SYMBOL("__do_softirq"),
+ CPA_IGNORE_SYMBOL("_end"),
+ CPA_IGNORE_SYMBOL("entInt"),
+ CPA_IGNORE_SYMBOL("entSys"),
+ {0,0}
+};
+#undef CPA_IGNORE_SYMBOL
+
+using namespace std;
+using namespace TheISA;
+
+bool CPA::exists;
+CPA *CPA::_cpa;
+
+class AnnotateDumpCallback : public Callback
+{
+
+ private:
+ CPA *cpa;
+ public:
+ virtual void process();
+ AnnotateDumpCallback(CPA *_cpa)
+ : cpa(_cpa)
+ {}
+};
+
+void
+AnnotateDumpCallback::process()
+{
+ cpa->dump(true);
+ cpa->dumpKey();
+}
+
+
+CPA::CPA(Params *p)
+ : SimObject(p), numSm(0), numSmt(0), numSys(0), numQs(0), conId(0)
+{
+ if (exists)
+ fatal("Multiple annotation objects found in system");
+ exists = true;
+
+ _enabled = p->enabled;
+ _cpa = this;
+
+ vector<string>::iterator i;
+ i = p->user_apps.begin();
+
+ while (i != p->user_apps.end()) {
+ ObjectFile *of = createObjectFile(*i);
+ string sf;
+ if (!of)
+ fatal("Couldn't load symbols from file: %s\n", *i);
+ sf = *i;
+ sf.erase(0, sf.rfind('/') + 1);;
+ DPRINTFN("file %s short: %s\n", *i, sf);
+ userApp[sf] = new SymbolTable;
+ bool result1 = of->loadGlobalSymbols(userApp[sf]);
+ bool result2 = of->loadLocalSymbols(userApp[sf]);
+ if (!result1 || !result2)
+ panic("blah");
+ assert(result1 && result2);
+ i++;
+ }
+}
+
+void
+CPA::startup()
+{
+ osbin = simout.create("annotate.bin", true);
+ // MAGIC version number 'M''5''A'N' + version/capabilities
+ ah.version = 0x4D35414E00000101ULL;
+ ah.num_recs = 0;
+ ah.key_off = 0;
+ osbin->write((char*)&ah, sizeof(AnnotateHeader));
+
+ registerExitCallback(new AnnotateDumpCallback(this));
+}
+void
+CPA::swSmBegin(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ Arguments args(tc);
+ std::string st;
+ Addr junk;
+ char sm[50];
+ if (!TheISA::inUserMode(tc))
+ debugSymbolTable->findNearestSymbol(
+ tc->readIntReg(ReturnAddressReg), st, junk);
+
+ CopyStringOut(tc, sm, args[0], 50);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+
+ if (!sm[0])
+ warn("Got null SM at tick %d\n", curTick);
+
+ int sysi = getSys(sys);
+ int smi = getSm(sysi, sm, args[1]);
+ DPRINTF(Annotate, "Starting machine: %s(%d) sysi: %d id: %#x\n", sm,
+ smi, sysi, args[1]);
+ DPRINTF(Annotate, "smMap[%d] = %d, %s, %#x\n", smi,
+ smMap[smi-1].first, smMap[smi-1].second.first,
+ smMap[smi-1].second.second);
+
+ uint64_t frame = getFrame(tc);
+ StackId sid = StackId(sysi, frame);
+
+ // check if we need to link to the previous state machine
+ int flags = args[2];
+ if (flags & FL_LINK) {
+ if (smStack[sid].size()) {
+ int prev_smi = smStack[sid].back();
+ DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n",
+ prev_smi, sm, smi, args[1]);
+
+ if (lnMap[smi])
+ DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n",
+ smi, lnMap[smi]);
+ assert(lnMap[smi] == 0);
+ lnMap[smi] = prev_smi;
+
+ add(OP_LINK, FL_NONE, tc->contextId(), prev_smi, smi);
+ } else {
+ DPRINTF(Annotate, "Not Linking to state machine %s(%d) [%#x]\n",
+ sm, smi, args[1]);
+ }
+ }
+
+
+ smStack[sid].push_back(smi);
+
+ DPRINTF(Annotate, "Stack Now (%#X):\n", frame);
+ for (int x = smStack[sid].size()-1; x >= 0; x--)
+ DPRINTF(Annotate, "-- %d\n", smStack[sid][x]);
+
+ // reset the sw state exculsion to false
+ if (swExpl[sid])
+ swExpl[sid] = false;
+
+
+ Id id = Id(sm, frame);
+ if (scLinks[sysi-1][id]) {
+ AnnDataPtr an = scLinks[sysi-1][id];
+ scLinks[sysi-1].erase(id);
+ an->stq = smi;
+ an->dump = true;
+ DPRINTF(Annotate,
+ "Found prev unknown linking from %d to state machine %s(%d)\n",
+ an->sm, sm, smi);
+
+ if (lnMap[smi])
+ DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n",
+ smi, lnMap[smi]);
+ assert(lnMap[smi] == 0);
+ lnMap[smi] = an->sm;
+ }
+
+ // add a new begin ifwe have that info
+ if (st != "") {
+ DPRINTF(Annotate, "st: %s smi: %d stCache.size %d\n", st,
+ smi, stCache.size());
+ int sti = getSt(sm, st);
+ lastState[smi] = sti;
+ add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti);
+ }
+}
+
+void
+CPA::swSmEnd(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ Arguments args(tc);
+ char sm[50];
+ CopyStringOut(tc, sm, args[0], 50);
+ System *sys = tc->getSystemPtr();
+ doSwSmEnd(sys, tc->contextId(), sm, getFrame(tc));
+}
+
+void
+CPA::doSwSmEnd(System *sys, int cpuid, string sm, uint64_t frame)
+{
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, frame);
+
+
+ // reset the sw state exculsion to false
+ if (swExpl[sid])
+ swExpl[sid] = false;
+
+
+ int smib = smStack[sid].back();
+ StringWrap name(sys->name());
+ DPRINTF(Annotate, "Ending machine: %s[%d, %#x] (%d?)\n", sm, sysi,
+ frame, smib);
+
+ if (!smStack[sid].size() || smMap[smib-1].second.first != sm) {
+ DPRINTF(Annotate, "State Machine not unwinding correctly. sid: %d, %#x"
+ " top of stack: %s Current Stack:\n",
+ sysi, frame, smMap[smib-1].second.first);
+ for (int x = smStack[sid].size()-1; x >= 0; x--)
+ DPRINTF(Annotate, "-- %d\n", smStack[sid][x]);
+ DPRINTF(Annotate, "Ending machine: %s; end stack: %s\n", sm,
+ smMap[smib-1].second.first);
+
+ warn("State machine stack not unwinding correctly at %d\n", curTick);
+ } else {
+ DPRINTF(Annotate,
+ "State machine ending:%s sysi:%d id:%#x back:%d getSm:%d\n",
+ sm, sysi, smMap[smib-1].second.second, smStack[sid].back(),
+ getSm(sysi, sm, smMap[smib-1].second.second));
+ assert(getSm(sysi, sm, smMap[smib-1].second.second) ==
+ smStack[sid].back());
+
+ int smi = smStack[sid].back();
+ smStack[sid].pop_back();
+
+ if (lnMap[smi]) {
+ DPRINTF(Annotate, "Linking %d back to %d\n", smi, lnMap[smi]);
+ add(OP_LINK, FL_NONE, cpuid, smi, lnMap[smi]);
+ lnMap.erase(smi);
+ }
+
+ if (smStack[sid].size()) {
+ add(OP_BEGIN, FL_NONE, cpuid, smi, lastState[smi]);
+ }
+
+ DPRINTF(Annotate, "Stack Now:\n");
+ for (int x = smStack[sid].size()-1; x >= 0; x--)
+ DPRINTF(Annotate, "-- %d\n", smStack[sid][x]);
+ }
+}
+
+
+void
+CPA::swExplictBegin(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ Arguments args(tc);
+ char st[50];
+ CopyStringOut(tc, st, args[1], 50);
+
+ StringWrap name(tc->getSystemPtr()->name());
+ DPRINTF(Annotate, "Explict begin of state %s\n", st);
+ uint32_t flags = args[0];
+ if (flags & FL_BAD)
+ warn("BAD state encountered: at cycle %d: %s\n", curTick, st);
+ swBegin(tc->getSystemPtr(), tc->contextId(), st, getFrame(tc), true, args[0]);
+}
+
+void
+CPA::swAutoBegin(ThreadContext *tc, Addr next_pc)
+{
+ if (!enabled())
+ return;
+
+ string sym;
+ Addr sym_addr = 0;
+ SymbolTable *symtab = NULL;
+
+
+ if (!TheISA::inUserMode(tc)) {
+ debugSymbolTable->findNearestSymbol(next_pc, sym, sym_addr);
+ symtab = debugSymbolTable;
+ } else {
+ Linux::ThreadInfo ti(tc);
+ string app = ti.curTaskName();
+ if (userApp.count(app))
+ userApp[app]->findNearestSymbol(next_pc, sym, sym_addr);
+ }
+
+ if (sym_addr)
+ swBegin(tc->getSystemPtr(), tc->contextId(), sym, getFrame(tc));
+}
+
+void
+CPA::swBegin(System *sys, int cpuid, std::string st, uint64_t frame, bool expl,
+ int flags)
+{
+ int x = 0;
+ int len;
+ while (ignoreSymbols[x].len)
+ {
+ len = ignoreSymbols[x].len;
+ if (!st.compare(0,len, ignoreSymbols[x].symbol, len))
+ return;
+ x++;
+ }
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, frame);
+ // if expl is true suspend symbol table based states
+ if (!smStack[sid].size())
+ return;
+ if (!expl && swExpl[sid])
+ return;
+ if (expl)
+ swExpl[sid] = true;
+ DPRINTFS(AnnotateVerbose, sys, "SwBegin: %s sysi: %d\n", st, sysi);
+ int smi = smStack[sid].back();
+ int sti = getSt(smMap[smi-1].second.first, st);
+ if (lastState[smi] != sti) {
+ lastState[smi] = sti;
+ add(OP_BEGIN, flags, cpuid, smi, sti);
+ }
+}
+
+void
+CPA::swEnd(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ std::string st;
+ Addr junk;
+ if (!TheISA::inUserMode(tc))
+ debugSymbolTable->findNearestSymbol(
+ tc->readIntReg(ReturnAddressReg), st, junk);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size()) {
+ DPRINTF(Annotate, "Explict end of State: %s IGNORED\n", st);
+ return;
+ }
+ DPRINTF(Annotate, "Explict end of State: %s\n", st);
+ // return back to symbol table based states
+ swExpl[sid] = false;
+ int smi = smStack[sid].back();
+ if (st != "") {
+ int sti = getSt(smMap[smi-1].second.first, st);
+ lastState[smi] = sti;
+ add(OP_BEGIN, FL_NONE, tc->contextId(), smi, sti);
+ }
+}
+
+void
+CPA::swQ(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ int32_t count = args[2];
+ System *sys = tc->getSystemPtr();
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ if (swExpl[sid])
+ swExpl[sid] = false;
+ int qi = getQ(sysi, q, id);
+ if (count == 0) {
+ //warn("Tried to queue 0 bytes in %s, ignoring\n", q);
+ return;
+ }
+ DPRINTFS(AnnotateQ, sys,
+ "swQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n",
+ q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, count);
+}
+
+void
+CPA::swDq(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ int32_t count = args[2];
+ System *sys = tc->getSystemPtr();
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ if (swExpl[sid])
+ swExpl[sid] = false;
+ DPRINTFS(AnnotateQ, sys,
+ "swDq: %s[%#x] cur size %d %d bytes: %d removing: %d\n",
+ q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ assert(count != 0);
+
+ doDq(sys, FL_NONE, tc->contextId(), smi, q, qi, count);
+}
+
+void
+CPA::swPq(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ int32_t count = args[2];
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ if (swExpl[sid])
+ swExpl[sid] = false;
+ DPRINTFS(AnnotateQ, sys,
+ "swPq: %s [%#x] cur size %d %d bytes: %d peeking: %d\n",
+ q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+
+ assert(count != 0);
+ if (qBytes[qi-1] < count) {
+ dump(true);
+ dumpKey();
+ fatal("Queue %s peeking with not enough bytes available in queue!\n", q);
+ }
+
+ add(OP_PEEK, FL_NONE, tc->contextId(), smi, qi, count);
+}
+
+void
+CPA::swRq(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ int32_t count = args[2];
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ if (swExpl[sid])
+ swExpl[sid] = false;
+ DPRINTFS(AnnotateQ, sys,
+ "swRq: %s [%#x] cur size %d %d bytes: %d reserve: %d\n",
+ q, id, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+
+ assert(count != 0);
+
+ add(OP_RESERVE, FL_NONE, tc->contextId(), smi, qi, count);
+}
+
+
+void
+CPA::swWf(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ int32_t count = args[3];
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ add(OP_WAIT_FULL, FL_NONE, tc->contextId(), smi, qi, count);
+
+ if (!!args[2]) {
+ char sm[50];
+ CopyStringOut(tc, sm, args[2], 50);
+ doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc));
+ }
+}
+
+void
+CPA::swWe(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ int32_t count = args[3];
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ add(OP_WAIT_EMPTY, FL_NONE, tc->contextId(), smi, qi, count);
+
+ if (!!args[2]) {
+ char sm[50];
+ CopyStringOut(tc, sm, args[2], 50);
+ doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc));
+ }
+}
+
+void
+CPA::swSq(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+ int32_t size = args[2];
+ int flags = args[3];
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int qi = getQ(sysi, q, id);
+ DPRINTF(AnnotateQ, "swSq: %s [%#x] cur size: %d bytes: %d, new size: %d\n",
+ q, id, qSize[qi-1], qBytes[qi-1], size);
+
+ if (FL_RESET & flags) {
+ DPRINTF(AnnotateQ, "Resetting Queue %s\n", q);
+ add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, 0);
+ qData[qi-1].clear();
+ qSize[qi-1] = 0;
+ qBytes[qi-1] = 0;
+ }
+
+ if (qBytes[qi-1] < size)
+ doQ(sys, FL_NONE, tc->contextId(), smi, q, qi, size - qBytes[qi-1]);
+ else if (qBytes[qi-1] > size) {
+ DPRINTF(AnnotateQ, "removing for resize of queue %s\n", q);
+ add(OP_SIZE_QUEUE, FL_NONE, tc->contextId(), smi, qi, size);
+ if (size <= 0) {
+ qData[qi-1].clear();
+ qSize[qi-1] = 0;
+ qBytes[qi-1] = 0;
+ return;
+ }
+ int need = qBytes[qi-1] - size;
+ qBytes[qi-1] = size;
+ while (need > 0) {
+ int32_t tail_bytes = qData[qi-1].back()->data;
+ if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) {
+ dump(true);
+ dumpKey();
+ fatal("Queue %s had inconsistancy when doing size queue!\n", q);
+ }
+ if (tail_bytes > need) {
+ qData[qi-1].back()->data -= need;
+ need = 0;
+ } else if (tail_bytes == need) {
+ qData[qi-1].pop_back();
+ qSize[qi-1]--;
+ need = 0;
+ } else {
+ qData[qi-1].pop_back();
+ qSize[qi-1]--;
+ need -= tail_bytes;
+ }
+ }
+ }
+}
+
+void
+CPA::swAq(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char q[50];
+ Arguments args(tc);
+ uint64_t id = args[0];
+ CopyStringOut(tc, q, args[1], 50);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+ int32_t size = args[2];
+
+ int sysi = getSys(sys);
+ int qi = getQ(sysi, q, id);
+ if (qBytes[qi-1] != size) {
+ DPRINTF(AnnotateQ, "Queue %s [%#x] has inconsintant size\n", q, id);
+ //dump(true);
+ //dumpKey();
+ std::list<AnnDataPtr>::iterator ai = qData[qi-1].begin();
+ int x = 0;
+ while (ai != qData[qi-1].end()) {
+ DPRINTF(AnnotateQ, "--Element %d size %d\n", x, (*ai)->data);
+ ai++;
+ x++;
+ }
+
+ warn("%d: Queue Assert: SW said there should be %d byte(s) in %s,"
+ "however there are %d byte(s)\n",
+ curTick, size, q, qBytes[qi-1]);
+ DPRINTF(AnnotateQ, "%d: Queue Assert: SW said there should be %d"
+ " byte(s) in %s, however there are %d byte(s)\n",
+ curTick, size, q, qBytes[qi-1]);
+ }
+}
+
+void
+CPA::swLink(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char lsm[50];
+ Arguments args(tc);
+ CopyStringOut(tc, lsm, args[0], 50);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+
+ int sysi = getSys(sys);
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+ int lsmi = getSm(sysi, lsm, args[1]);
+
+ DPRINTF(Annotate, "Linking from %d to state machine %s(%d) [%#x]\n",
+ smi, lsm, lsmi, args[1]);
+
+ if (lnMap[lsmi])
+ DPRINTF(Annotate, "LnMap already contains entry for %d of %d\n",
+ lsmi, lnMap[lsmi]);
+ assert(lnMap[lsmi] == 0);
+ lnMap[lsmi] = smi;
+
+ add(OP_LINK, FL_NONE, tc->contextId(), smi, lsmi);
+
+ if (!!args[2]) {
+ char sm[50];
+ CopyStringOut(tc, sm, args[2], 50);
+ doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc));
+ }
+}
+
+void
+CPA::swIdentify(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ Arguments args(tc);
+ int sysi = getSys(tc->getSystemPtr());
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ return;
+ int smi = smStack[sid].back();
+
+ DPRINTFS(Annotate, tc->getSystemPtr(), "swIdentify: id %#X\n", args[0]);
+
+ add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, args[0]);
+}
+
+uint64_t
+CPA::swGetId(ThreadContext *tc)
+{
+ if (!enabled())
+ return 0;
+
+ uint64_t id = ++conId;
+ int sysi = getSys(tc->getSystemPtr());
+ StackId sid = StackId(sysi, getFrame(tc));
+ if (!smStack[sid].size())
+ panic("swGetId called without a state machine stack!");
+ int smi = smStack[sid].back();
+
+ DPRINTFS(Annotate, tc->getSystemPtr(), "swGetId: id %#X\n", id);
+
+ add(OP_IDENT, FL_NONE, tc->contextId(), smi, 0, id);
+ return id;
+}
+
+
+void
+CPA::swSyscallLink(ThreadContext *tc)
+{
+ if (!enabled())
+ return;
+
+ char lsm[50];
+ Arguments args(tc);
+ CopyStringOut(tc, lsm, args[0], 50);
+ System *sys = tc->getSystemPtr();
+ StringWrap name(sys->name());
+ int sysi = getSys(sys);
+
+ Id id = Id(lsm, getFrame(tc));
+ StackId sid = StackId(sysi, getFrame(tc));
+
+ if (!smStack[sid].size())
+ return;
+
+ int smi = smStack[sid].back();
+
+ DPRINTF(Annotate, "Linking from %d to state machine %s(UNKNOWN)\n",
+ smi, lsm);
+
+ if (scLinks[sysi-1][id])
+ DPRINTF(Annotate,
+ "scLinks already contains entry for system %d %s[%x] of %d\n",
+ sysi, lsm, getFrame(tc), scLinks[sysi-1][id]);
+ assert(scLinks[sysi-1][id] == 0);
+ scLinks[sysi-1][id] = add(OP_LINK, FL_NONE, tc->contextId(), smi, 0xFFFF);
+ scLinks[sysi-1][id]->dump = false;
+
+ if (!!args[1]) {
+ char sm[50];
+ CopyStringOut(tc, sm, args[1], 50);
+ doSwSmEnd(tc->getSystemPtr(), tc->contextId(), sm, getFrame(tc));
+ }
+}
+
+CPA::AnnDataPtr
+CPA::add(int t, int f, int c, int sm, int stq, int32_t d)
+{
+ AnnDataPtr an = new AnnotateData;
+ an->time = curTick;
+ an->data = d;
+ an->orig_data = d;
+ an->op = t;
+ an->flag = f;
+ an->sm = sm;
+ an->stq = stq;
+ an->cpu = c;
+ an->dump = true;
+
+ data.push_back(an);
+
+ DPRINTF(AnnotateVerbose, "Annotate: op: %d flags: 0x%x sm: %d state: %d time: %d, data: %d\n",
+ an->op, an->flag, an->sm, an->stq, an->time, an->data);
+
+ // Don't dump Links because we might be setting no-dump on it
+ if (an->op != OP_LINK)
+ dump(false);
+
+ return an;
+}
+
+void
+CPA::dumpKey()
+{
+ std::streampos curpos = osbin->tellp();
+ ah.key_off = curpos;
+
+ // Output the various state machines and their corresponding states
+ *osbin << "# Automatically generated state machine descriptor file" << endl;
+
+ *osbin << "sms = {}" << endl << endl;
+ vector<string> state_machines;
+ state_machines.resize(numSmt+1);
+
+ // State machines, id -> states
+ SCache::iterator i = smtCache.begin();
+ while (i != smtCache.end()) {
+ state_machines[i->second] = i->first;
+ i++;
+ }
+
+ for (int x = 1; x < state_machines.size(); x++) {
+ vector<string> states;
+ states.resize(numSt[x-1]+1);
+ assert(x-1 < stCache.size());
+ SCache::iterator i = stCache[x-1].begin();
+ while (i != stCache[x-1].end()) {
+ states[i->second] = i->first;
+ i++;
+ }
+ *osbin << "sms[\"" << state_machines[x] << "\"] = [\"NULL\"";
+ for (int y = 1; y < states.size(); y++)
+ *osbin << ", \"" << states[y] << "\"";
+ *osbin << "]" << endl;
+ }
+
+ *osbin << endl << endl << endl;
+
+ // state machine number -> system, name, id
+ *osbin << "smNum = [\"NULL\"";
+ for (int x = 0; x < smMap.size(); x++)
+ *osbin << ", (" << smMap[x].first << ", \"" << smMap[x].second.first <<
+ "\", " << smMap[x].second.second << ")";
+ *osbin << "]" << endl;
+
+ *osbin << endl << endl << endl;
+
+ // Output the systems
+ vector<string> systems;
+ systems.resize(numSys+1);
+ NameCache::iterator i2 = nameCache.begin();
+ while (i2 != nameCache.end()) {
+ systems[i2->second.second] = i2->second.first;
+ i2++;
+ }
+
+ *osbin << "sysNum = [\"NULL\"";
+ for (int x = 1; x < systems.size(); x++) {
+ *osbin << ", \"" << systems[x] << "\"";
+ }
+ *osbin << "]" << endl;
+
+ // queue number -> system, qname, qid
+ *osbin << "queues = [\"NULL\"";
+ for (int x = 0; x < qMap.size(); x++)
+ *osbin << ", (" << qMap[x].first << ", \"" << qMap[x].second.first <<
+ "\", " << qMap[x].second.second << ")";
+ *osbin << "]" << endl;
+
+ *osbin << "smComb = [s for s in [(i,r) for i in xrange(1,len(sysNum)) "
+ << "for r in xrange (1,len(smNum))]]" << endl;
+ ah.key_len = osbin->tellp() - curpos;
+
+ // output index
+ curpos = osbin->tellp();
+ ah.idx_off = curpos;
+
+ for (int x = 0; x < annotateIdx.size(); x++)
+ osbin->write((char*)&annotateIdx[x], sizeof(uint64_t));
+ ah.idx_len = osbin->tellp() - curpos;
+
+ osbin->seekp(0);
+ osbin->write((char*)&ah, sizeof(AnnotateHeader));
+ osbin->flush();
+
+}
+
+void
+CPA::dump(bool all)
+{
+
+ list<AnnDataPtr>::iterator i;
+
+ i = data.begin();
+
+ if (i == data.end())
+ return;
+
+ // Dump the data every
+ if (!all && data.size() < 10000)
+ return;
+
+ DPRINTF(Annotate, "Writing %d\n", data.size());
+ while (i != data.end()) {
+ AnnDataPtr an = *i;
+
+ // If we can't dump this record, hold here
+ if (!an->dump && !all)
+ break;
+
+ ah.num_recs++;
+ if (ah.num_recs % 100000 == 0)
+ annotateIdx.push_back(osbin->tellp());
+
+
+ osbin->write((char*)&(an->time), sizeof(an->time));
+ osbin->write((char*)&(an->orig_data), sizeof(an->orig_data));
+ osbin->write((char*)&(an->sm), sizeof(an->sm));
+ osbin->write((char*)&(an->stq), sizeof(an->stq));
+ osbin->write((char*)&(an->op), sizeof(an->op));
+ osbin->write((char*)&(an->flag), sizeof(an->flag));
+ osbin->write((char*)&(an->cpu), sizeof(an->cpu));
+ i++;
+ }
+ if (data.begin() != i)
+ data.erase(data.begin(), i);
+
+ if (all)
+ osbin->flush();
+}
+
+void
+CPA::doQ(System *sys, int flags, int cpuid, int sm,
+ string q, int qi, int count)
+{
+ qSize[qi-1]++;
+ qBytes[qi-1] += count;
+ if (qSize[qi-1] > 2501 || qBytes[qi-1] > 2000000000)
+ warn("Queue %s is %d elements/%d bytes, "
+ "maybe things aren't being removed?\n",
+ q, qSize[qi-1], qBytes[qi-1]);
+ if (flags & FL_QOPP)
+ qData[qi-1].push_front(add(OP_QUEUE, flags, cpuid, sm, qi, count));
+ else
+ qData[qi-1].push_back(add(OP_QUEUE, flags, cpuid, sm, qi, count));
+ DPRINTFS(AnnotateQ, sys, "Queing in queue %s size now %d/%d\n",
+ q, qSize[qi-1], qBytes[qi-1]);
+ assert(qSize[qi-1] >= 0);
+ assert(qBytes[qi-1] >= 0);
+}
+
+
+void
+CPA::doDq(System *sys, int flags, int cpuid, int sm,
+ string q, int qi, int count)
+{
+
+ StringWrap name(sys->name());
+ if (count == -1) {
+ add(OP_DEQUEUE, flags, cpuid, sm, qi, count);
+ qData[qi-1].clear();
+ qSize[qi-1] = 0;
+ qBytes[qi-1] = 0;
+ DPRINTF(AnnotateQ, "Dequeing all data in queue %s size now %d/%d\n",
+ q, qSize[qi-1], qBytes[qi-1]);
+ return;
+ }
+
+ assert(count > 0);
+ if (qSize[qi-1] <= 0 || qBytes[qi-1] <= 0 || !qData[qi-1].size()) {
+ dump(true);
+ dumpKey();
+ fatal("Queue %s dequing with no data available in queue!\n",
+ q);
+ }
+ assert(qSize[qi-1] >= 0);
+ assert(qBytes[qi-1] >= 0);
+ assert(qData[qi-1].size());
+
+ int32_t need = count;
+ qBytes[qi-1] -= count;
+ if (qBytes[qi-1] < 0) {
+ dump(true);
+ dumpKey();
+ fatal("Queue %s dequing with no bytes available in queue!\n",
+ q);
+ }
+
+ while (need > 0) {
+ int32_t head_bytes = qData[qi-1].front()->data;
+ if (qSize[qi-1] <= 0 || qBytes[qi-1] < 0) {
+ dump(true);
+ dumpKey();
+ fatal("Queue %s dequing with nothing in queue!\n",
+ q);
+ }
+
+ if (head_bytes > need) {
+ qData[qi-1].front()->data -= need;
+ need = 0;
+ } else if (head_bytes == need) {
+ qData[qi-1].pop_front();
+ qSize[qi-1]--;
+ need = 0;
+ } else {
+ qData[qi-1].pop_front();
+ qSize[qi-1]--;
+ need -= head_bytes;
+ }
+ }
+
+ add(OP_DEQUEUE, flags, cpuid, sm, qi, count);
+ DPRINTF(AnnotateQ, "Dequeing in queue %s size now %d/%d\n",
+ q, qSize[qi-1], qBytes[qi-1]);
+}
+
+
+
+void
+CPA::serialize(std::ostream &os)
+{
+
+ SERIALIZE_SCALAR(numSm);
+ SERIALIZE_SCALAR(numSmt);
+ arrayParamOut(os, "numSt", numSt);
+ arrayParamOut(os, "numQ", numQ);
+ SERIALIZE_SCALAR(numSys);
+ SERIALIZE_SCALAR(numQs);
+ SERIALIZE_SCALAR(conId);
+ arrayParamOut(os, "qSize", qSize);
+ arrayParamOut(os, "qSize", qSize);
+ arrayParamOut(os, "qBytes", qBytes);
+
+ std::list<AnnDataPtr>::iterator ai;
+
+ SCache::iterator i;
+ int x = 0, y = 0;
+
+ // smtCache (SCache)
+ x = 0;
+ y = 0;
+ i = smtCache.begin();
+ while (i != smtCache.end()) {
+ paramOut(os, csprintf("smtCache%d.str", x), i->first);
+ paramOut(os, csprintf("smtCache%d.int", x), i->second);
+ x++; i++;
+ }
+
+ // stCache (StCache)
+ for (x = 0; x < stCache.size(); x++) {
+ i = stCache[x].begin();
+ y = 0;
+ while (i != stCache[x].end()) {
+ paramOut(os, csprintf("stCache%d_%d.str", x, y), i->first);
+ paramOut(os, csprintf("stCache%d_%d.int", x, y), i->second);
+ y++; i++;
+ }
+ }
+
+ // qCache (IdCache)
+ IdHCache::iterator idi;
+ for (x = 0; x < qCache.size(); x++) {
+ idi = qCache[x].begin();
+ y = 0;
+ while (idi != qCache[x].end()) {
+ paramOut(os, csprintf("qCache%d_%d.str", x, y), idi->first.first);
+ paramOut(os, csprintf("qCache%d_%d.id", x, y), idi->first.second);
+ paramOut(os, csprintf("qCache%d_%d.int", x, y), idi->second);
+ y++; idi++;
+ }
+ }
+
+ // smCache (IdCache)
+ for (x = 0; x < smCache.size(); x++) {
+ idi = smCache[x].begin();
+ y = 0;
+ paramOut(os, csprintf("smCache%d", x), smCache[x].size());
+ while (idi != smCache[x].end()) {
+ paramOut(os, csprintf("smCache%d_%d.str", x, y), idi->first.first);
+ paramOut(os, csprintf("smCache%d_%d.id", x, y), idi->first.second);
+ paramOut(os, csprintf("smCache%d_%d.int", x, y), idi->second);
+ y++; idi++;
+ }
+ }
+
+ // scLinks (ScCache) -- data not serialize
+
+
+ // namecache (NameCache)
+ NameCache::iterator ni;
+
+ ni = nameCache.begin();
+ x = 0;
+ while (ni != nameCache.end()) {
+ paramOut(os, csprintf("nameCache%d.name", x), ni->first->name());
+ paramOut(os, csprintf("nameCache%d.str", x), ni->second.first);
+ paramOut(os, csprintf("nameCache%d.int", x), ni->second.second);
+ x++; ni++;
+ }
+
+ // smStack (SmStack)
+ SmStack::iterator si;
+ si = smStack.begin();
+ x = 0;
+ paramOut(os, "smStackIdCount", smStack.size());
+ while (si != smStack.end()) {
+ paramOut(os, csprintf("smStackId%d.sys", x), si->first.first);
+ paramOut(os, csprintf("smStackId%d.frame", x), si->first.second);
+ paramOut(os, csprintf("smStackId%d.count", x), si->second.size());
+ for (y = 0; y < si->second.size(); y++)
+ paramOut(os, csprintf("smStackId%d_%d", x, y), si->second[y]);
+ x++; si++;
+ }
+
+ // lnMap (LinkMap)
+ x = 0;
+ LinkMap::iterator li;
+ li = lnMap.begin();
+ paramOut(os, "lnMapSize", lnMap.size());
+ while (li != lnMap.end()) {
+ paramOut(os, csprintf("lnMap%d.smi", x), li->first);
+ paramOut(os, csprintf("lnMap%d.lsmi", x), li->second);
+ x++; li++;
+ }
+
+ // swExpl (vector)
+ SwExpl::iterator swexpli;
+ swexpli = swExpl.begin();
+ x = 0;
+ paramOut(os, "swExplCount", swExpl.size());
+ while (swexpli != swExpl.end()) {
+ paramOut(os, csprintf("swExpl%d.sys", x), swexpli->first.first);
+ paramOut(os, csprintf("swExpl%d.frame", x), swexpli->first.second);
+ paramOut(os, csprintf("swExpl%d.swexpl", x), swexpli->second);
+ x++; swexpli++;
+ }
+
+ // lastState (IMap)
+ x = 0;
+ IMap::iterator ii;
+ ii = lastState.begin();
+ paramOut(os, "lastStateSize", lastState.size());
+ while (ii != lastState.end()) {
+ paramOut(os, csprintf("lastState%d.smi", x), ii->first);
+ paramOut(os, csprintf("lastState%d.sti", x), ii->second);
+ x++; ii++;
+ }
+
+ // smMap (IdMap)
+ for (x = 0; x < smMap.size(); x++) {
+ paramOut(os, csprintf("smMap%d.sys", x), smMap[x].first);
+ paramOut(os, csprintf("smMap%d.smname", x), smMap[x].second.first);
+ paramOut(os, csprintf("smMap%d.id", x), smMap[x].second.second);
+ }
+
+ // qMap (IdMap)
+ for (x = 0; x < qMap.size(); x++) {
+ paramOut(os, csprintf("qMap%d.sys", x), qMap[x].first);
+ paramOut(os, csprintf("qMap%d.qname", x), qMap[x].second.first);
+ paramOut(os, csprintf("qMap%d.id", x), qMap[x].second.second);
+ }
+
+ // qData (vector<AnnotateList>)
+ for(x = 0; x < qData.size(); x++) {
+ if (!qData[x].size())
+ continue;
+ y = 0;
+ ai = qData[x].begin();
+ while (ai != qData[x].end()) {
+ nameOut(os, csprintf("%s.Q%d_%d", name(), x, y));
+ (*ai)->serialize(os);
+ ai++;
+ y++;
+ }
+ }
+}
+
+void
+CPA::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(numSm);
+ UNSERIALIZE_SCALAR(numSmt);
+ arrayParamIn(cp, section, "numSt", numSt);
+ arrayParamIn(cp, section, "numQ", numQ);
+ UNSERIALIZE_SCALAR(numSys);
+ UNSERIALIZE_SCALAR(numQs);
+ UNSERIALIZE_SCALAR(conId);
+ arrayParamIn(cp, section, "qSize", qSize);
+ arrayParamIn(cp, section, "qBytes", qBytes);
+
+
+ // smtCache (SCache
+ string str;
+ int smi;
+ for (int x = 0; x < numSmt; x++) {
+ paramIn(cp, section, csprintf("smtCache%d.str", x), str);
+ paramIn(cp, section, csprintf("smtCache%d.int", x), smi);
+ smtCache[str] = smi;
+ }
+
+ // stCache (StCache)
+ stCache.resize(numSmt);
+ for (int x = 0; x < numSmt; x++) {
+ for (int y = 0; y < numSt[x]; y++) {
+ paramIn(cp, section, csprintf("stCache%d_%d.str", x,y), str);
+ paramIn(cp, section, csprintf("stCache%d_%d.int", x,y), smi);
+ stCache[x][str] = smi;
+ }
+ }
+
+ // qCache (IdCache)
+ uint64_t id;
+ qCache.resize(numSys);
+ for (int x = 0; x < numSys; x++) {
+ for (int y = 0; y < numQ[x]; y++) {
+ paramIn(cp, section, csprintf("qCache%d_%d.str", x,y), str);
+ paramIn(cp, section, csprintf("qCache%d_%d.id", x,y), id);
+ paramIn(cp, section, csprintf("qCache%d_%d.int", x,y), smi);
+ qCache[x][Id(str,id)] = smi;
+ }
+ }
+
+ // smCache (IdCache)
+ smCache.resize(numSys);
+ for (int x = 0; x < numSys; x++) {
+ int size;
+ paramIn(cp, section, csprintf("smCache%d", x), size);
+ for (int y = 0; y < size; y++) {
+ paramIn(cp, section, csprintf("smCache%d_%d.str", x,y), str);
+ paramIn(cp, section, csprintf("smCache%d_%d.id", x,y), id);
+ paramIn(cp, section, csprintf("smCache%d_%d.int", x,y), smi);
+ smCache[x][Id(str,id)] = smi;
+ }
+ }
+
+ // scLinks (ScCache) -- data not serialized, just creating one per sys
+ for (int x = 0; x < numSys; x++)
+ scLinks.push_back(ScHCache());
+
+ // nameCache (NameCache)
+ for (int x = 0; x < numSys; x++) {
+ System *sys;
+ SimObject *sptr;
+ string str;
+ int sysi;
+
+ objParamIn(cp, section, csprintf("nameCache%d.name", x), sptr);
+ sys = dynamic_cast<System*>(sptr);
+
+ paramIn(cp, section, csprintf("nameCache%d.str", x), str);
+ paramIn(cp, section, csprintf("nameCache%d.int", x), sysi);
+ nameCache[sys] = std::make_pair<std::string,int>(str, sysi);
+ }
+
+ //smStack (SmStack)
+ int smStack_size;
+ paramIn(cp, section, "smStackIdCount", smStack_size);
+ for (int x = 0; x < smStack_size; x++) {
+ int sysi;
+ uint64_t frame;
+ int count;
+ paramIn(cp, section, csprintf("smStackId%d.sys", x), sysi);
+ paramIn(cp, section, csprintf("smStackId%d.frame", x), frame);
+ paramIn(cp, section, csprintf("smStackId%d.count", x), count);
+ StackId sid = StackId(sysi, frame);
+ for (int y = 0; y < count; y++) {
+ paramIn(cp, section, csprintf("smStackId%d_%d", x, y), smi);
+ smStack[sid].push_back(smi);
+ }
+ }
+
+ // lnMap (LinkMap)
+ int lsmi;
+ int lnMap_size;
+ paramIn(cp, section, "lnMapSize", lnMap_size);
+ for (int x = 0; x < lnMap_size; x++) {
+ paramIn(cp, section, csprintf("lnMap%d.smi", x), smi);
+ paramIn(cp, section, csprintf("lnMap%d.lsmi", x), lsmi);
+ lnMap[smi] = lsmi;
+ }
+
+ // swExpl (vector)
+ int swExpl_size;
+ paramIn(cp, section, "swExplCount", swExpl_size);
+ for (int x = 0; x < swExpl_size; x++) {
+ int sysi;
+ uint64_t frame;
+ bool b;
+ paramIn(cp, section, csprintf("swExpl%d.sys", x), sysi);
+ paramIn(cp, section, csprintf("swExpl%d.frame", x), frame);
+ paramIn(cp, section, csprintf("swExpl%d.swexpl", x), b);
+ StackId sid = StackId(sysi, frame);
+ swExpl[sid] = b;
+ }
+
+ // lastState (IMap)
+ int sti;
+ int lastState_size;
+ paramIn(cp, section, "lastStateSize", lastState_size);
+ for (int x = 0; x < lastState_size; x++) {
+ paramIn(cp, section, csprintf("lastState%d.smi", x), smi);
+ paramIn(cp, section, csprintf("lastState%d.sti", x), sti);
+ lastState[smi] = sti;
+ }
+
+
+ //smMap (IdMap)
+ smMap.resize(numSm);
+ for (int x = 0; x < smMap.size(); x++) {
+ paramIn(cp, section, csprintf("smMap%d.sys", x), smMap[x].first);
+ paramIn(cp, section, csprintf("smMap%d.smname", x), smMap[x].second.first);
+ paramIn(cp, section, csprintf("smMap%d.id", x), smMap[x].second.second);
+ }
+
+ //qMap (IdMap)
+ qMap.resize(numQs);
+ for (int x = 0; x < qMap.size(); x++) {
+ paramIn(cp, section, csprintf("qMap%d.sys", x), qMap[x].first);
+ paramIn(cp, section, csprintf("qMap%d.qname", x), qMap[x].second.first);
+ paramIn(cp, section, csprintf("qMap%d.id", x), qMap[x].second.second);
+ }
+
+
+ // qData (vector<AnnotateList>)
+ qData.resize(qSize.size());
+ for (int x = 0; x < qSize.size(); x++) {
+ if (!qSize[x])
+ continue;
+ for (int y = 0; y < qSize[x]; y++) {
+ AnnDataPtr a = new AnnotateData;
+ a->unserialize(cp, csprintf("%s.Q%d_%d", section, x, y));
+ data.push_back(a);
+ qData[x].push_back(a);
+ }
+ }
+}
+
+void
+CPA::AnnotateData::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(time);
+ SERIALIZE_SCALAR(data);
+ SERIALIZE_SCALAR(sm);
+ SERIALIZE_SCALAR(stq);
+ SERIALIZE_SCALAR(op);
+ SERIALIZE_SCALAR(flag);
+ SERIALIZE_SCALAR(cpu);
+}
+
+void
+CPA::AnnotateData::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(time);
+ UNSERIALIZE_SCALAR(data);
+ orig_data = data;
+ UNSERIALIZE_SCALAR(sm);
+ UNSERIALIZE_SCALAR(stq);
+ UNSERIALIZE_SCALAR(op);
+ UNSERIALIZE_SCALAR(flag);
+ UNSERIALIZE_SCALAR(cpu);
+ dump = true;
+}
+
+CPA*
+CPAParams::create()
+{
+ return new CPA(this);
+}
+
diff --git a/src/base/cp_annotate.hh b/src/base/cp_annotate.hh
new file mode 100644
index 000000000..13ced82de
--- /dev/null
+++ b/src/base/cp_annotate.hh
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2006-2009 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __BASE__CP_ANNOTATE_HH__
+#define __BASE__CP_ANNOTATE_HH__
+
+#include "base/loader/symtab.hh"
+#include "config/cp_annotate.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+#include "sim/startup.hh"
+#include "sim/system.hh"
+
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+#include "base/hashmap.hh"
+#include "base/trace.hh"
+#if CP_ANNOTATE
+#include "params/CPA.hh"
+#endif
+
+class System;
+class ThreadContext;
+
+
+#if !CP_ANNOTATE
+class CPA
+{
+ public:
+ enum flags {
+ FL_NONE = 0x00,
+ FL_HW = 0x01,
+ FL_BAD = 0x02,
+ FL_QOPP = 0x04,
+ FL_WAIT = 0x08,
+ FL_LINK = 0x10,
+ FL_RESET = 0x20
+ };
+
+ static CPA *cpa() { return NULL; }
+ static bool available() { return false; }
+ bool enabled() { return false; }
+ void swSmBegin(ThreadContext *tc) { return; }
+ void swSmEnd(ThreadContext *tc) { return; }
+ void swExplictBegin(ThreadContext *tc) { return; }
+ void swAutoBegin(ThreadContext *tc, Addr next_pc) { return; }
+ void swEnd(ThreadContext *tc) { return; }
+ void swQ(ThreadContext *tc) { return; }
+ void swDq(ThreadContext *tc) { return; }
+ void swPq(ThreadContext *tc) { return; }
+ void swRq(ThreadContext *tc) { return; }
+ void swWf(ThreadContext *tc) { return; }
+ void swWe(ThreadContext *tc) { return; }
+ void swSq(ThreadContext *tc) { return; }
+ void swAq(ThreadContext *tc) { return; }
+ void swLink(ThreadContext *tc) { return; }
+ void swIdentify(ThreadContext *tc) { return; }
+ uint64_t swGetId(ThreadContext *tc) { return 0; }
+ void swSyscallLink(ThreadContext *tc) { return; }
+ void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string st) { return; }
+ void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+ void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL,
+ int32_t count = 1) { return; }
+};
+#else
+class CPA : SimObject
+{
+ public:
+ typedef CPAParams Params;
+
+ /** The known operations that are written to the annotation output file. */
+ enum ops {
+ OP_BEGIN = 0x01,
+ OP_WAIT_EMPTY = 0x02,
+ OP_WAIT_FULL = 0x03,
+ OP_QUEUE = 0x04,
+ OP_DEQUEUE = 0x05,
+ OP_SIZE_QUEUE = 0x08,
+ OP_PEEK = 0x09,
+ OP_LINK = 0x0A,
+ OP_IDENT = 0x0B,
+ OP_RESERVE = 0x0C
+ };
+
+ /** Flags for the various options.*/
+ enum flags {
+ /* no flags */
+ FL_NONE = 0x00,
+ /* operation was done on hardware */
+ FL_HW = 0x01,
+ /* operation should cause a warning when encountered */
+ FL_BAD = 0x02,
+ /* Queue like a stack, not a queue */
+ FL_QOPP = 0x04,
+ /* Mark HW state as waiting for some non-resource constraint
+ * (e.g. wait because SM only starts after 10 items are queued) */
+ FL_WAIT = 0x08,
+ /* operation is linking to another state machine */
+ FL_LINK = 0x10,
+ /* queue should be completely cleared/reset before executing this
+ * operation */
+ FL_RESET = 0x20
+ };
+
+
+
+ protected:
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ /* struct that is written to the annotation output file */
+ struct AnnotateData : public RefCounted {
+
+ Tick time;
+ uint32_t data;
+ uint32_t orig_data;
+ uint16_t sm;
+ uint16_t stq;
+ uint8_t op;
+ uint8_t flag;
+ uint8_t cpu;
+ bool dump;
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ };
+
+ typedef RefCountingPtr<AnnotateData> AnnDataPtr;
+
+ /* header for the annotation file */
+ struct AnnotateHeader {
+ uint64_t version;
+ uint64_t num_recs;
+ uint64_t key_off;
+ uint64_t idx_off;
+ uint32_t key_len;
+ uint32_t idx_len;
+ };
+
+ AnnotateHeader ah;
+
+ std::vector<uint64_t> annotateIdx;
+
+ // number of state machines encountered in the simulation
+ int numSm;
+ // number of states encountered in the simulation
+ int numSmt;
+ // number of states/queues for a given state machine/system respectively
+ std::vector<int> numSt, numQ;
+ // number of systems in the simulation
+ int numSys;
+ // number of queues in the state machine
+ int numQs;
+ // maximum connection id assigned so far
+ uint64_t conId;
+
+ // Convert state strings into state ids
+ typedef m5::hash_map<std::string, int> SCache;
+ typedef std::vector<SCache> StCache;
+
+ // Convert sm and queue name,id into queue id
+ typedef std::pair<std::string, uint64_t> Id;
+ typedef m5::hash_map<Id, int> IdHCache;
+ typedef std::vector<IdHCache> IdCache;
+
+ // Hold mapping of sm and queues to output python
+ typedef std::vector<std::pair<int, Id> > IdMap;
+
+ // System pointer to name,id
+ typedef std::map<System*, std::pair<std::string, int> > NameCache;
+
+ // array of systems each of which is a stack of running sm
+ typedef std::pair<int, uint64_t> StackId;
+ typedef std::map<StackId, std::vector<int> > SmStack;
+
+ // map of each context and if it's currently in explict state mode
+ // states are not automatically updated until it leaves
+ typedef std::map<StackId, bool> SwExpl;
+
+ typedef std::map<int,int> IMap;
+ // List of annotate records have not been written/completed yet
+ typedef std::list<AnnDataPtr> AnnotateList;
+
+ // Maintain link state information
+ typedef std::map<int, int> LinkMap;
+
+ // SC Links
+ typedef m5::hash_map<Id, AnnDataPtr> ScHCache;
+ typedef std::vector<ScHCache> ScCache;
+
+
+ AnnotateList data;
+
+ // vector indexed by queueid to find current number of elements and bytes
+ std::vector<int> qSize;
+ std::vector<int32_t> qBytes;
+
+
+ // Turn state machine string into state machine id (small int)
+ // Used for outputting key to convert id back into string
+ SCache smtCache;
+ // Turn state machine id, state name into state id (small int)
+ StCache stCache;
+ // turn system, queue, and queue identify into qid (small int)
+ // turn system, state, and context into state machine id (small int)
+ IdCache qCache, smCache;
+ //Link state machines accross system calls
+ ScCache scLinks;
+ // System pointer to name,id
+ NameCache nameCache;
+ // Stack of state machines currently nested (should unwind correctly)
+ SmStack smStack;
+ // Map of currently outstanding links
+ LinkMap lnMap;
+ // If the state machine is currently exculding automatic changes
+ SwExpl swExpl;
+ // Last state that a given state machine was in
+ IMap lastState;
+ // Hold mapping of sm and queues to output python
+ IdMap smMap, qMap;
+ // Items still in queue, used for sanity checking
+ std::vector<AnnotateList> qData;
+
+ void doDq(System *sys, int flags, int cpu, int sm, std::string q, int qi,
+ int count);
+ void doQ(System *sys, int flags, int cpu, int sm, std::string q, int qi,
+ int count);
+
+ void doSwSmEnd(System *sys, int cpuid, std::string sm, uint64_t frame);
+
+ // Turn a system id, state machine string, state machine id into a small int
+ // for annotation output
+ int
+ getSm(int sysi, std::string si, uint64_t id)
+ {
+ int smi;
+ Id smid = Id(si, id);
+
+ smi = smCache[sysi-1][smid];
+ if (smi == 0) {
+ smCache[sysi-1][smid] = smi = ++numSm;
+ assert(smi < 65535);
+ smMap.push_back(std::make_pair<int, Id>(sysi, smid));
+ }
+ return smi;
+ }
+
+ // Turn a state machine string, state string into a small int
+ // for annotation output
+ int
+ getSt(std::string sm, std::string s)
+ {
+ int sti, smi;
+
+ smi = smtCache[sm];
+ if (smi == 0)
+ smi = smtCache[sm] = ++numSmt;
+
+ while (stCache.size() < smi) {
+ //stCache.resize(sm);
+ stCache.push_back(SCache());
+ numSt.push_back(0);
+ }
+ //assert(stCache.size() == sm);
+ //assert(numSt.size() == sm);
+ sti = stCache[smi-1][s];
+ if (sti == 0)
+ stCache[smi-1][s] = sti = ++numSt[smi-1];
+ return sti;
+ }
+
+ // Turn state machine pointer into a smal int for annotation output
+ int
+ getSys(System *s)
+ {
+ NameCache::iterator i = nameCache.find(s);
+ if (i == nameCache.end()) {
+ nameCache[s] = std::make_pair<std::string,int>(s->name(), ++numSys);
+ i = nameCache.find(s);
+ // might need to put smstackid into map here, but perhaps not
+ //smStack.push_back(std::vector<int>());
+ //swExpl.push_back(false);
+ numQ.push_back(0);
+ qCache.push_back(IdHCache());
+ smCache.push_back(IdHCache());
+ scLinks.push_back(ScHCache());
+ }
+ return i->second.second;
+ }
+
+ // Turn queue name, and queue context into small int for
+ // annotation output
+ int
+ getQ(int sys, std::string q, uint64_t id)
+ {
+ int qi;
+ Id qid = Id(q, id);
+
+ qi = qCache[sys-1][qid];
+ if (qi == 0) {
+ qi = qCache[sys-1][qid] = ++numQs;
+ assert(qi < 65535);
+ qSize.push_back(0);
+ qBytes.push_back(0);
+ qData.push_back(AnnotateList());
+ numQ[sys-1]++;
+ qMap.push_back(std::make_pair<int, Id>(sys, qid));
+ }
+ return qi;
+ }
+
+ void swBegin(System *sys, int cpuid, std::string st, uint64_t frame,
+ bool expl = false, int flags = FL_NONE);
+
+ AnnDataPtr add(int t, int f, int c, int sm, int stq, int32_t data=0);
+
+ std::ostream *osbin;
+
+ bool _enabled;
+
+ /** Only allow one CPA object in a system. It doesn't make sense to have
+ * more that one per simulation because if a part of the system was
+ * important it would have annotations and queues, and with more than one
+ * object none of the sanity checking for queues will work. */
+ static bool exists;
+ static CPA *_cpa;
+
+
+ std::map<std::string, SymbolTable*> userApp;
+
+ public:
+ static CPA *cpa() { return _cpa; }
+ void swSmBegin(ThreadContext *tc);
+ void swSmEnd(ThreadContext *tc);
+ void swExplictBegin(ThreadContext *tc);
+ void swAutoBegin(ThreadContext *tc, Addr next_pc);
+ void swEnd(ThreadContext *tc);
+ void swQ(ThreadContext *tc);
+ void swDq(ThreadContext *tc);
+ void swPq(ThreadContext *tc);
+ void swRq(ThreadContext *tc);
+ void swWf(ThreadContext *tc);
+ void swWe(ThreadContext *tc);
+ void swSq(ThreadContext *tc);
+ void swAq(ThreadContext *tc);
+ void swLink(ThreadContext *tc);
+ void swIdentify(ThreadContext *tc);
+ uint64_t swGetId(ThreadContext *tc);
+ void swSyscallLink(ThreadContext *tc);
+
+ inline void hwBegin(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string st)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int smi = getSm(sysi, sm, frame);
+ add(OP_BEGIN, FL_HW | f, 0, smi, getSt(sm, st));
+ if (f & FL_BAD)
+ warn("BAD state encountered: at cycle %d: %s\n", curTick, st);
+ }
+
+ inline void hwQ(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwQ: %s[%#x] cur size %d %d bytes: %d adding: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ doQ(sys, FL_HW | f, 0, getSm(sysi, sm, frame), q, qi, count);
+
+ }
+
+ inline void hwDq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwDQ: %s[%#x] cur size %d %d bytes: %d removing: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ doDq(sys, FL_HW | f, 0, getSm(sysi,sm, frame), q, qi, count);
+ }
+
+ inline void hwPq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwPQ: %s[%#x] cur size %d %d bytes: %d peeking: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ add(OP_PEEK, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwRq(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ DPRINTFS(AnnotateQ, sys,
+ "hwRQ: %s[%#x] cur size %d %d bytes: %d reserving: %d\n",
+ q, qid, qSize[qi-1], qData[qi-1].size(), qBytes[qi-1], count);
+ add(OP_RESERVE, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwWf(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ add(OP_WAIT_FULL, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ inline void hwWe(flags f, System *sys, uint64_t frame, std::string sm,
+ std::string q, uint64_t qid, System *q_sys = NULL, int32_t count = 1)
+ {
+ if (!enabled())
+ return;
+
+ int sysi = getSys(sys);
+ int qi = getQ(q_sys ? getSys(q_sys) : sysi, q, qid);
+ add(OP_WAIT_EMPTY, FL_HW | f, 0, getSm(sysi, sm, frame), qi, count);
+ }
+
+ public:
+ CPA(Params *p);
+ void startup();
+
+ // This code is ISA specific and will need to be changed
+ // if the annotation code is used for something other than Alpha
+ inline uint64_t getFrame(ThreadContext *tc)
+ { return (tc->readMiscRegNoEffect(TheISA::IPR_PALtemp23) &
+ ~ULL(0x3FFF)); }
+
+ static bool available() { return true; }
+
+ bool
+ enabled()
+ {
+ if (!this)
+ return false;
+ return _enabled;
+ }
+
+ void dump(bool all);
+ void dumpKey();
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+#endif // !CP_ANNOTATE
+
+#endif //__BASE__CP_ANNOTATE_HH__
+
diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc
index d4ba9ca21..5c11e501c 100644
--- a/src/base/cprintf.cc
+++ b/src/base/cprintf.cc
@@ -40,7 +40,7 @@ using namespace std;
namespace cp {
Print::Print(std::ostream &stream, const std::string &format)
- : stream(stream), format(format.c_str()), ptr(format.c_str())
+ : stream(stream), format(format.c_str()), ptr(format.c_str()), cont(false)
{
saved_flags = stream.flags();
saved_fill = stream.fill();
@@ -48,7 +48,7 @@ Print::Print(std::ostream &stream, const std::string &format)
}
Print::Print(std::ostream &stream, const char *format)
- : stream(stream), format(format), ptr(format)
+ : stream(stream), format(format), ptr(format), cont(false)
{
saved_flags = stream.flags();
saved_fill = stream.fill();
@@ -60,8 +60,10 @@ Print::~Print()
}
void
-Print::process(Format &fmt)
+Print::process()
{
+ fmt.clear();
+
size_t len;
while (*ptr) {
@@ -221,8 +223,15 @@ Print::process(Format &fmt)
number = number * 10 + (*ptr - '0');
break;
+ case '*':
+ if (have_precision)
+ fmt.get_precision = true;
+ else
+ fmt.get_width = true;
+ break;
+
case '%':
- assert("we shouldn't get here");
+ assert(false && "we shouldn't get here");
break;
default:
diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh
index cff73a228..2920e210d 100644
--- a/src/base/cprintf.hh
+++ b/src/base/cprintf.hh
@@ -51,24 +51,53 @@ struct Print
std::ostream &stream;
const char *format;
const char *ptr;
+ bool cont;
std::ios::fmtflags saved_flags;
char saved_fill;
int saved_precision;
- void process(Format &fmt);
+ Format fmt;
+ void process();
public:
Print(std::ostream &stream, const std::string &format);
Print(std::ostream &stream, const char *format);
~Print();
+ int
+ get_number(int data)
+ {
+ return data;
+ }
+
+ template <typename T>
+ int
+ get_number(const T& data)
+ {
+ return 0;
+ }
+
template <typename T>
void
add_arg(const T &data)
{
- Format fmt;
- process(fmt);
+ if (!cont)
+ process();
+
+ if (fmt.get_width) {
+ fmt.get_width = false;
+ cont = true;
+ fmt.width = get_number(data);
+ return;
+ }
+
+ if (fmt.get_precision) {
+ fmt.get_precision = false;
+ cont = true;
+ fmt.precision = get_number(data);
+ return;
+ }
switch (fmt.format) {
case Format::character:
diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh
index 4e8b2b09e..6bf6b2b66 100644
--- a/src/base/cprintf_formats.hh
+++ b/src/base/cprintf_formats.hh
@@ -31,8 +31,9 @@
#ifndef __BASE_CPRINTF_FORMATS_HH__
#define __BASE_CPRINTF_FORMATS_HH__
-#include <sstream>
+#include <cstring>
#include <ostream>
+#include <sstream>
namespace cp {
@@ -49,6 +50,8 @@ struct Format
enum { best, fixed, scientific } float_format;
int precision;
int width;
+ bool get_precision;
+ bool get_width;
Format() { clear(); }
@@ -64,6 +67,8 @@ struct Format
format = none;
precision = -1;
width = 0;
+ get_precision = false;
+ get_width = false;
}
};
diff --git a/src/base/crc.cc b/src/base/crc.cc
index 08f039577..ce837a408 100644
--- a/src/base/crc.cc
+++ b/src/base/crc.cc
@@ -1,6 +1,6 @@
/*
* Copyright (c) 1988, 1992, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -12,8 +12,8 @@
* 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.
+ * 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.
diff --git a/src/unittest/tracetest.cc b/src/base/debug.cc
index b1343aac3..de201af18 100644
--- a/src/unittest/tracetest.cc
+++ b/src/base/debug.cc
@@ -28,29 +28,18 @@
* Authors: Nathan Binkert
*/
-#include "sim/host.hh"
-#include "base/trace.hh"
+#include <sys/types.h>
+#include <signal.h>
+#include <unistd.h>
-using namespace std;
+#include "base/cprintf.hh"
-Tick curTick = 0;
-
-struct foo
-{
- foo()
- {
- char foo[9] = "testing";
- DPRINTF(Loader, "%s\n", foo);
- }
-};
-
-int
-main()
+void
+debug_break()
{
- Trace::flags[Trace::Loader] = true;
- Trace::dprintf_stream = &cout;
-
- foo f;
-
- return 0;
+#ifndef NDEBUG
+ kill(getpid(), SIGTRAP);
+#else
+ cprintf("debug_break suppressed, compiled with NDEBUG\n");
+#endif
}
diff --git a/src/python/swig/init.hh b/src/base/debug.hh
index 23d2c19a9..b1577f782 100644
--- a/src/python/swig/init.hh
+++ b/src/base/debug.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * 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
@@ -28,9 +28,9 @@
* Authors: Nathan Binkert
*/
-#ifndef __PYTHON_SWIG_INIT_HH__
-#define __PYTHON_SWIG_INIT_HH__
+#ifndef __BASE_DEBUG_HH__
+#define __BASE_DEBUG_HH__
-void init_swig();
+void debug_break();
-#endif // __PYTHON_SWIG_INIT_HH__
+#endif // __BASE_DEBUG_HH__
diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc
index e1298a8bd..a91a99d20 100644
--- a/src/base/fast_alloc.cc
+++ b/src/base/fast_alloc.cc
@@ -34,7 +34,8 @@
* by permission.
*/
-#include <assert.h>
+#include <cassert>
+
#include "base/fast_alloc.hh"
#if !NO_FAST_ALLOC
@@ -45,21 +46,22 @@
void *FastAlloc::freeLists[Num_Buckets];
-#ifdef FAST_ALLOC_STATS
+#if FAST_ALLOC_STATS
unsigned FastAlloc::newCount[Num_Buckets];
unsigned FastAlloc::deleteCount[Num_Buckets];
unsigned FastAlloc::allocCount[Num_Buckets];
#endif
-void *FastAlloc::moreStructs(int bucket)
+void *
+FastAlloc::moreStructs(int bucket)
{
assert(bucket > 0 && bucket < Num_Buckets);
int sz = bucket * Alloc_Quantum;
- const int nstructs = Num_Structs_Per_New; // how many to allocate?
+ const int nstructs = Num_Structs_Per_New; // how many to allocate?
char *p = ::new char[nstructs * sz];
-#ifdef FAST_ALLOC_STATS
+#if FAST_ALLOC_STATS
++allocCount[bucket];
#endif
@@ -71,14 +73,13 @@ void *FastAlloc::moreStructs(int bucket)
return (p + sz);
}
+#if FAST_ALLOC_DEBUG
-#ifdef FAST_ALLOC_DEBUG
-
-#include <typeinfo>
-#include <iostream>
#include <iomanip>
+#include <iostream>
#include <map>
#include <string>
+#include <typeinfo>
using namespace std;
@@ -97,7 +98,6 @@ FastAlloc::FastAlloc(FastAlloc *prev, FastAlloc *next)
inUseNext = next;
}
-
// constructor: marks as in use, add to in-use list
FastAlloc::FastAlloc()
{
@@ -131,7 +131,6 @@ FastAlloc::~FastAlloc()
inUseNext->inUsePrev = inUsePrev;
}
-
// summarize in-use list
void
FastAlloc::dump_summary()
@@ -148,48 +147,43 @@ FastAlloc::dump_summary()
cout << " count type\n"
<< " ----- ----\n";
for (mapiter = typemap.begin(); mapiter != typemap.end(); ++mapiter)
- {
cout << setw(6) << mapiter->second << " " << mapiter->first << endl;
- }
}
-
// show oldest n items on in-use list
void
FastAlloc::dump_oldest(int n)
{
// sanity check: don't want to crash the debugger if you forget to
// pass in a parameter
- if (n < 0 || n > numInUse)
- {
+ if (n < 0 || n > numInUse) {
cout << "FastAlloc::dump_oldest: bad arg " << n
<< " (" << numInUse << " objects in use" << endl;
return;
}
- for (FastAlloc *p = inUseHead.inUsePrev;
+ for (FastAlloc *p = inUseHead.inUseNext;
p != &inUseHead && n > 0;
- p = p->inUsePrev, --n)
- {
+ p = p->inUseNext, --n)
cout << p << " " << typeid(*p).name() << endl;
- }
}
-
//
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
+void
fast_alloc_summary()
{
FastAlloc::dump_summary();
}
+void
fast_alloc_oldest(int n)
{
FastAlloc::dump_oldest(n);
}
-#endif
+#endif // FAST_ALLOC_DEBUG
#endif // NO_FAST_ALLOC
diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh
index 3e22e59c1..775c93d50 100644
--- a/src/base/fast_alloc.hh
+++ b/src/base/fast_alloc.hh
@@ -34,10 +34,10 @@
* by permission.
*/
-#ifndef __FAST_ALLOC_H__
-#define __FAST_ALLOC_H__
+#ifndef __BASE_FAST_ALLOC_HH__
+#define __BASE_FAST_ALLOC_HH__
-#include <stddef.h>
+#include <cstddef>
// Fast structure allocator. Designed for small objects that are
// frequently allocated and deallocated. This code is derived from the
@@ -62,35 +62,30 @@
// collapse the destructor call chain back up the inheritance
// hierarchy.
-// Uncomment this #define to track in-use objects
-// (for debugging memory leaks).
-//#define FAST_ALLOC_DEBUG
-
-// Uncomment this #define to count news, deletes, and chunk allocations
-// (by bucket).
-// #define FAST_ALLOC_STATS
-
#include "config/no_fast_alloc.hh"
+#include "config/fast_alloc_debug.hh"
+#include "config/fast_alloc_stats.hh"
#if NO_FAST_ALLOC
-class FastAlloc {
+class FastAlloc
+{
};
#else
-class FastAlloc {
+class FastAlloc
+{
public:
-
static void *allocate(size_t);
static void deallocate(void *, size_t);
void *operator new(size_t);
void operator delete(void *, size_t);
-#ifdef FAST_ALLOC_DEBUG
+#if FAST_ALLOC_DEBUG
FastAlloc();
- FastAlloc(FastAlloc*,FastAlloc*); // for inUseHead, see below
+ FastAlloc(FastAlloc *, FastAlloc *); // for inUseHead, see below
virtual ~FastAlloc();
#else
virtual ~FastAlloc() {}
@@ -121,21 +116,21 @@ class FastAlloc {
static void *freeLists[Num_Buckets];
-#ifdef FAST_ALLOC_STATS
+#if FAST_ALLOC_STATS
static unsigned newCount[Num_Buckets];
static unsigned deleteCount[Num_Buckets];
static unsigned allocCount[Num_Buckets];
#endif
-#ifdef FAST_ALLOC_DEBUG
+#if FAST_ALLOC_DEBUG
// per-object debugging fields
- bool inUse; // in-use flag
- FastAlloc *inUsePrev; // ptrs to build list of in-use objects
+ bool inUse; // in-use flag
+ FastAlloc *inUsePrev; // ptrs to build list of in-use objects
FastAlloc *inUseNext;
// static (global) debugging vars
- static int numInUse; // count in-use objects
- static FastAlloc inUseHead; // dummy head for list of in-use objects
+ static int numInUse; // count in-use objects
+ static FastAlloc inUseHead; // dummy head for list of in-use objects
public:
// functions to dump debugging info (see fast_alloc.cc for C
@@ -145,16 +140,14 @@ class FastAlloc {
#endif
};
-
-inline
-int FastAlloc::bucketFor(size_t sz)
+inline int
+FastAlloc::bucketFor(size_t sz)
{
return (sz + Alloc_Quantum - 1) >> Log2_Alloc_Quantum;
}
-
-inline
-void *FastAlloc::allocate(size_t sz)
+inline void *
+FastAlloc::allocate(size_t sz)
{
int b;
void *p;
@@ -170,21 +163,19 @@ void *FastAlloc::allocate(size_t sz)
else
p = moreStructs(b);
-#ifdef FAST_ALLOC_STATS
+#if FAST_ALLOC_STATS
++newCount[b];
#endif
return p;
}
-
-inline
-void FastAlloc::deallocate(void *p, size_t sz)
+inline void
+FastAlloc::deallocate(void *p, size_t sz)
{
int b;
- if (sz > Max_Alloc_Size)
- {
+ if (sz > Max_Alloc_Size) {
::delete [] (char *)p;
return;
}
@@ -192,25 +183,23 @@ void FastAlloc::deallocate(void *p, size_t sz)
b = bucketFor(sz);
*(void **)p = freeLists[b];
freeLists[b] = p;
-#ifdef FAST_ALLOC_STATS
+#if FAST_ALLOC_STATS
++deleteCount[b];
#endif
}
-
-inline
-void *FastAlloc::operator new(size_t sz)
+inline void *
+FastAlloc::operator new(size_t sz)
{
return allocate(sz);
}
-
-inline
-void FastAlloc::operator delete(void *p, size_t sz)
+inline void
+FastAlloc::operator delete(void *p, size_t sz)
{
deallocate(p, sz);
}
#endif // NO_FAST_ALLOC
-#endif // __FAST_ALLOC_H__
+#endif // __BASE_FAST_ALLOC_HH__
diff --git a/src/base/flags.hh b/src/base/flags.hh
new file mode 100644
index 000000000..2e0506391
--- /dev/null
+++ b/src/base/flags.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __BASE_FLAGS_HH__
+#define __BASE_FLAGS_HH__
+
+template <typename T>
+class Flags
+{
+ private:
+ T _flags;
+
+ public:
+ typedef T Type;
+ Flags() : _flags(0) {}
+ Flags(Type flags) : _flags(flags) {}
+
+ operator const Type() const { return _flags; }
+
+ template <typename U>
+ const Flags<T> &
+ operator=(const Flags<U> &flags)
+ {
+ _flags = flags._flags;
+ return *this;
+ }
+
+ const Flags<T> &
+ operator=(T flags)
+ {
+ _flags = flags;
+ return *this;
+ }
+
+ bool isSet() const { return _flags; }
+ bool isSet(Type flags) const { return (_flags & flags); }
+ bool allSet() const { return !(~_flags); }
+ bool allSet(Type flags) const { return (_flags & flags) == flags; }
+ bool noneSet() const { return _flags == 0; }
+ bool noneSet(Type flags) const { return (_flags & flags) == 0; }
+ void clear() { _flags = 0; }
+ void clear(Type flags) { _flags &= ~flags; }
+ void set(Type flags) { _flags |= flags; }
+ void set(Type f, bool val) { _flags = (_flags & ~f) | (val ? f : 0); }
+ void
+ update(Type flags, Type mask)
+ {
+ _flags = (_flags & ~mask) | (flags & mask);
+ }
+};
+
+#endif // __BASE_FLAGS_HH__
diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh
index f8d799780..ff2aa151f 100644
--- a/src/base/hashmap.hh
+++ b/src/base/hashmap.hh
@@ -81,6 +81,16 @@ namespace __hash_namespace {
return(__stl_hash_string(s.c_str()));
}
};
+
+ template <>
+ struct hash<std::pair<std::string, uint64_t> > {
+ size_t operator() (std::pair<std::string, uint64_t> r) const {
+ return (__stl_hash_string(r.first.c_str())) ^ r.second;
+ }
+ };
+
+
+
}
diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh
index cb1d6003b..5e478553b 100644
--- a/src/base/hybrid_pred.hh
+++ b/src/base/hybrid_pred.hh
@@ -62,12 +62,12 @@ class HybridPredictor : public GenericPredictor
//
// Stats
//
- Stats::Scalar<> pred_one; //num_one_preds
- Stats::Scalar<> pred_zero; //num_zero_preds
- Stats::Scalar<> correct_pred_one; //num_one_correct
- Stats::Scalar<> correct_pred_zero; //num_zero_correct
- Stats::Scalar<> record_one; //num_one_updates
- Stats::Scalar<> record_zero; //num_zero_updates
+ Stats::Scalar pred_one; //num_one_preds
+ Stats::Scalar pred_zero; //num_zero_preds
+ Stats::Scalar correct_pred_one; //num_one_correct
+ Stats::Scalar correct_pred_zero; //num_zero_correct
+ Stats::Scalar record_one; //num_one_updates
+ Stats::Scalar record_zero; //num_zero_updates
Stats::Formula total_preds;
Stats::Formula frac_preds_zero;
diff --git a/src/base/inet.cc b/src/base/inet.cc
index b8da12a99..8c3240fa6 100644
--- a/src/base/inet.cc
+++ b/src/base/inet.cc
@@ -206,4 +206,25 @@ TcpOpt::sack(vector<SackRange> &vec) const
return false;
}
+int
+hsplit(const EthPacketPtr &ptr)
+{
+ int split_point = 0;
+
+ IpPtr ip(ptr);
+ if (ip) {
+ split_point = ip.pstart();
+
+ TcpPtr tcp(ip);
+ if (tcp)
+ split_point = tcp.pstart();
+
+ UdpPtr udp(ip);
+ if (udp)
+ split_point = udp.pstart();
+ }
+ return split_point;
+}
+
+
/* namespace Net */ }
diff --git a/src/base/inet.hh b/src/base/inet.hh
index 1bf7c585f..59b05291d 100644
--- a/src/base/inet.hh
+++ b/src/base/inet.hh
@@ -140,6 +140,8 @@ class EthPtr
EthPacketPtr packet() { return p; }
bool operator!() const { return !p; }
operator bool() const { return p; }
+ int off() const { return 0; }
+ int pstart() const { return off() + ((const EthHdr*)p->data)->size(); }
};
/*
@@ -162,6 +164,9 @@ struct IpHdr : public ip_hdr
uint32_t dst() const { return ntohl(ip_dst); }
void sum(uint16_t sum) { ip_sum = sum; }
+ void id(uint16_t _id) { ip_id = htons(_id); }
+ void len(uint16_t _len) { ip_len = htons(_len); }
+
bool options(std::vector<const IpOpt *> &vec) const;
@@ -179,32 +184,31 @@ class IpPtr
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;
+ p = 0;
+
+ if (ptr) {
+ EthHdr *eth = (EthHdr *)ptr->data;
+ if (eth->type() == ETH_TYPE_IP)
+ p = ptr;
+ }
}
public:
- IpPtr() {}
- IpPtr(const EthPacketPtr &ptr) { set(ptr); }
- IpPtr(const EthPtr &ptr) { set(ptr.p); }
+ IpPtr() : p(0) {}
+ IpPtr(const EthPacketPtr &ptr) : p(0) { set(ptr); }
+ IpPtr(const EthPtr &ptr) : p(0) { set(ptr.p); }
IpPtr(const IpPtr &ptr) : p(ptr.p) { }
- IpHdr *operator->() { return h(); }
- IpHdr &operator*() { return *h(); }
- operator IpHdr *() { return h(); }
+ IpHdr *get() { return (IpHdr *)(p->data + sizeof(eth_hdr)); }
+ IpHdr *operator->() { return get(); }
+ IpHdr &operator*() { return *get(); }
- const IpHdr *operator->() const { return h(); }
- const IpHdr &operator*() const { return *h(); }
- operator const IpHdr *() const { return h(); }
+ const IpHdr *get() const
+ { return (const IpHdr *)(p->data + sizeof(eth_hdr)); }
+ const IpHdr *operator->() const { return get(); }
+ const IpHdr &operator*() const { return *get(); }
const IpPtr &operator=(const EthPacketPtr &ptr) { set(ptr); return *this; }
const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; }
@@ -214,7 +218,8 @@ class IpPtr
EthPacketPtr packet() { return p; }
bool operator!() const { return !p; }
operator bool() const { return p; }
- operator bool() { return p; }
+ int off() const { return sizeof(eth_hdr); }
+ int pstart() const { return off() + get()->size(); }
};
uint16_t cksum(const IpPtr &ptr);
@@ -262,6 +267,8 @@ struct TcpHdr : public tcp_hdr
uint16_t urp() const { return ntohs(th_urp); }
void sum(uint16_t sum) { th_sum = sum; }
+ void seq(uint32_t _seq) { th_seq = htonl(_seq); }
+ void flags(uint8_t _flags) { th_flags = _flags; }
bool options(std::vector<const TcpOpt *> &vec) const;
@@ -276,41 +283,39 @@ class TcpPtr
{
protected:
EthPacketPtr p;
- int off;
-
- const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); }
- TcpHdr *h() { return (TcpHdr *)(p->data + off); }
+ int _off;
- void set(const EthPacketPtr &ptr, int offset) { p = ptr; off = offset; }
+ void set(const EthPacketPtr &ptr, int offset) { p = ptr; _off = offset; }
void set(const IpPtr &ptr)
{
- if (ptr->proto() == IP_PROTO_TCP)
+ if (ptr && 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) {}
+ TcpPtr() : p(0), _off(0) {}
+ TcpPtr(const IpPtr &ptr) : p(0), _off(0) { set(ptr); }
+ TcpPtr(const TcpPtr &ptr) : p(ptr.p), _off(ptr._off) {}
- TcpHdr *operator->() { return h(); }
- TcpHdr &operator*() { return *h(); }
- operator TcpHdr *() { return h(); }
+ TcpHdr *get() { return (TcpHdr *)(p->data + _off); }
+ TcpHdr *operator->() { return get(); }
+ TcpHdr &operator*() { return *get(); }
- const TcpHdr *operator->() const { return h(); }
- const TcpHdr &operator*() const { return *h(); }
- operator const TcpHdr *() const { return h(); }
+ const TcpHdr *get() const { return (const TcpHdr *)(p->data + _off); }
+ const TcpHdr *operator->() const { return get(); }
+ const TcpHdr &operator*() const { return *get(); }
const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; }
- const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); 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; }
+ int off() const { return _off; }
+ int pstart() const { return off() + get()->size(); }
};
uint16_t cksum(const TcpPtr &ptr);
@@ -354,6 +359,7 @@ struct UdpHdr : public udp_hdr
uint16_t sum() const { return uh_sum; }
void sum(uint16_t sum) { uh_sum = sum; }
+ void len(uint16_t _len) { uh_ulen = htons(_len); }
int size() const { return sizeof(udp_hdr); }
const uint8_t *bytes() const { return (const uint8_t *)this; }
@@ -366,45 +372,45 @@ class UdpPtr
{
protected:
EthPacketPtr p;
- int off;
+ 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 EthPacketPtr &ptr, int offset) { p = ptr; _off = offset; }
void set(const IpPtr &ptr)
{
- if (ptr->proto() == IP_PROTO_UDP)
+ if (ptr && 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) {}
+ UdpPtr() : p(0), _off(0) {}
+ UdpPtr(const IpPtr &ptr) : p(0), _off(0) { set(ptr); }
+ UdpPtr(const UdpPtr &ptr) : p(ptr.p), _off(ptr._off) {}
- UdpHdr *operator->() { return h(); }
- UdpHdr &operator*() { return *h(); }
- operator UdpHdr *() { return h(); }
+ UdpHdr *get() { return (UdpHdr *)(p->data + _off); }
+ UdpHdr *operator->() { return get(); }
+ UdpHdr &operator*() { return *get(); }
- const UdpHdr *operator->() const { return h(); }
- const UdpHdr &operator*() const { return *h(); }
- operator const UdpHdr *() const { return h(); }
+ const UdpHdr *get() const { return (const UdpHdr *)(p->data + _off); }
+ const UdpHdr *operator->() const { return get(); }
+ const UdpHdr &operator*() const { return *get(); }
const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; }
- const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); 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; }
+ int off() const { return _off; }
+ int pstart() const { return off() + get()->size(); }
};
uint16_t cksum(const UdpPtr &ptr);
+int hsplit(const EthPacketPtr &ptr);
+
/* namespace Net */ }
#endif // __BASE_INET_HH__
diff --git a/src/base/inifile.cc b/src/base/inifile.cc
index 809cbe172..24d0013c4 100644
--- a/src/base/inifile.cc
+++ b/src/base/inifile.cc
@@ -29,22 +29,8 @@
* Steve Reinhardt
*/
-#define USE_CPP
-
-#ifdef USE_CPP
-#include <sys/signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#endif
-
#include <fstream>
#include <iostream>
-
#include <vector>
#include <string>
@@ -67,103 +53,6 @@ IniFile::~IniFile()
}
}
-
-#ifdef USE_CPP
-bool
-IniFile::loadCPP(const string &file, vector<char *> &cppArgs)
-{
- // Open the file just to verify that we can. Otherwise if the
- // file doesn't exist or has bad permissions the user will get
- // confusing errors from cpp/g++.
- ifstream tmpf(file.c_str());
-
- if (!tmpf.is_open())
- return false;
-
- tmpf.close();
-
- char *cfile = strncpy(new char[file.size() + 1], file.c_str(),
- file.size());
- char *dir = dirname(cfile);
- char *dir_arg = NULL;
- if (*dir != '.') {
- string arg = "-I";
- arg += dir;
-
- dir_arg = new char[arg.size() + 1];
- strncpy(dir_arg, arg.c_str(), arg.size());
- }
-
- delete [] cfile;
-
- char tempfile[] = "/tmp/configXXXXXX";
- int tmp_fd = mkstemp(tempfile);
-
- int pid = fork();
-
- if (pid == -1)
- return false;
-
- if (pid == 0) {
- char filename[FILENAME_MAX];
- string::size_type i = file.copy(filename, sizeof(filename) - 1);
- filename[i] = '\0';
-
- int arg_count = cppArgs.size();
-
- const char **args = new const char *[arg_count + 20];
-
- int nextArg = 0;
- args[nextArg++] = "g++";
- args[nextArg++] = "-E";
- args[nextArg++] = "-P";
- args[nextArg++] = "-nostdinc";
- args[nextArg++] = "-nostdinc++";
- args[nextArg++] = "-x";
- args[nextArg++] = "c++";
- args[nextArg++] = "-undef";
-
- for (int i = 0; i < arg_count; i++)
- args[nextArg++] = cppArgs[i];
-
- if (dir_arg)
- args[nextArg++] = dir_arg;
-
- args[nextArg++] = filename;
- args[nextArg++] = NULL;
-
- close(STDOUT_FILENO);
- if (dup2(tmp_fd, STDOUT_FILENO) == -1)
- exit(1);
-
- // execvp signature is intentionally broken wrt const-ness for
- // backwards compatibility... see man page
- execvp("g++", const_cast<char * const *>(args));
-
- exit(0);
- }
-
- int retval;
- waitpid(pid, &retval, 0);
-
- delete [] dir_arg;
-
- // check for normal completion of CPP
- if (!WIFEXITED(retval) || WEXITSTATUS(retval) != 0)
- return false;
-
- close(tmp_fd);
-
- bool status = false;
-
- status = load(tempfile);
-
- unlink(tempfile);
-
- return status;
-}
-#endif
-
bool
IniFile::load(const string &file)
{
diff --git a/src/base/inifile.hh b/src/base/inifile.hh
index 631b29b87..83cf80cf0 100644
--- a/src/base/inifile.hh
+++ b/src/base/inifile.hh
@@ -61,8 +61,8 @@ class IniFile
///
class Entry
{
- std::string value; ///< The entry value.
- mutable bool referenced; ///< Has this entry been used?
+ std::string value; ///< The entry value.
+ mutable bool referenced; ///< Has this entry been used?
public:
/// Constructor.
@@ -96,8 +96,8 @@ class IniFile
/// EntryTable type. Map of strings to Entry object pointers.
typedef m5::hash_map<std::string, Entry *> EntryTable;
- EntryTable table; ///< Table of entries.
- mutable bool referenced; ///< Has this section been used?
+ EntryTable table; ///< Table of entries.
+ mutable bool referenced; ///< Has this section been used?
public:
/// Constructor.
@@ -167,14 +167,6 @@ class IniFile
/// @retval True if successful, false if errors were encountered.
bool load(std::istream &f);
- /// Load the specified file, passing it through the C preprocessor.
- /// Parameter settings found in the file will be merged with any
- /// already defined in this object.
- /// @param file The path of the file to load.
- /// @param cppFlags Vector of extra flags to pass to cpp.
- /// @retval True if successful, false if errors were encountered.
- bool loadCPP(const std::string &file, std::vector<char *> &cppFlags);
-
/// Load the specified file.
/// Parameter settings found in the file will be merged with any
/// already defined in this object.
diff --git a/src/base/intmath.hh b/src/base/intmath.hh
index 227012e30..c536fda51 100644
--- a/src/base/intmath.hh
+++ b/src/base/intmath.hh
@@ -197,9 +197,9 @@ roundDown(T val, int align)
inline bool
isHex(char c)
{
- return c >= '0' && c <= '9' ||
- c >= 'A' && c <= 'F' ||
- c >= 'a' && c <= 'f';
+ return (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f');
}
inline bool
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc
index 8fbad8030..1412adfc3 100644
--- a/src/base/loader/aout_object.cc
+++ b/src/base/loader/aout_object.cc
@@ -34,7 +34,7 @@
#include "base/loader/symtab.hh"
-#include "base/trace.hh" // for DPRINTF
+#include "base/trace.hh" // for DPRINTF
#include "base/loader/exec_aout.h"
diff --git a/src/base/loader/coff_sym.h b/src/base/loader/coff_sym.h
index 4c6540395..be0631141 100644
--- a/src/base/loader/coff_sym.h
+++ b/src/base/loader/coff_sym.h
@@ -65,7 +65,7 @@
*
* 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,
+ * EXCEPT for globals! These are assumed to be bunched together,
* probably right after the last 'normal' symbol. Globals ARE sorted
* in ascending order.
*
@@ -76,13 +76,13 @@
* 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.
+ * "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.
*/
@@ -97,31 +97,31 @@
*/
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*/
+ 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)
@@ -138,39 +138,39 @@ typedef struct ecoff_symhdr {
*
* 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
+ * 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) */
+ 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 */
+ /* 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;
+ coff_uint reserved2;
} FDR, *pFDR;
#define cbFDR sizeof(FDR)
#define fdNil ((pFDR)0)
@@ -189,31 +189,31 @@ typedef struct ecoff_fdr {
*/
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 */
+ 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 */
+ 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
+#define ipdNil -1
/*
* The structure of the runtime procedure descriptor created by the loader
@@ -225,16 +225,16 @@ typedef struct pdr {
*/
#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;
+ 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)
@@ -253,24 +253,24 @@ typedef struct runtime_pdr {
* the first line of a procedure and represent the first address.
*/
-typedef coff_int LINER, *pLINER;
+typedef coff_int LINER, *pLINER;
#define lineNil ((pLINER)0)
#define cbLINER sizeof(LINER)
-#define ilineNil -1
+#define ilineNil -1
/*
- * The Symbol Structure (GFW, to those who Know!)
+ * 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 */
+ 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)
@@ -287,22 +287,22 @@ typedef struct ecoff_sym {
/* 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.
+ * 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 */
+ 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 */
+/* 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
@@ -310,12 +310,12 @@ typedef struct ecoff_extsym {
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 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 tq1 : 4; /* 6 type qualifiers - tqPtr, etc. */
unsigned tq2 : 4;
unsigned tq3 : 4;
} TIR, *pTIR;
@@ -327,22 +327,22 @@ typedef struct {
* Relative symbol record
*
* If the rfd field is 4095, the index field indexes into the global symbol
- * table.
+ * table.
*/
typedef struct {
- unsigned rfd : 12; /* index into the file indirect table */
- unsigned index : 20; /* index int sym/aux/iss tables */
+ 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.
+ * 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 */
+ 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)
@@ -353,36 +353,36 @@ typedef struct {
* 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,
+ 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
+ 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.
+ 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 */
+ 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)
@@ -401,12 +401,12 @@ typedef union {
*/
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 */
+ 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 optNil ((pOPTR) 0)
#define cbOPTR sizeof(OPTR)
#define ioptNil -1
@@ -414,15 +414,15 @@ typedef struct {
* 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
+ * 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
+#define rfdNil -1
/*
* The file indirect table in the mips loader is known as an array of FITs.
@@ -430,9 +430,9 @@ typedef coff_long RFDT, *pRFDT;
* 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)
+#define cbFIT sizeof(FIT)
+#define ifiNil -1
+#define fiNil ((pFIT) 0)
#ifdef _LANGUAGE_PASCAL
#define ifdNil -1
@@ -448,18 +448,18 @@ typedef coff_int FIT, *pFIT;
#define ioptNil -1
#define rfdNil -1
#define ifiNil -1
-#endif /* _LANGUAGE_PASCAL */
+#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.
+ * 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.
*/
/*
@@ -467,7 +467,7 @@ typedef coff_int FIT, *pFIT;
* 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
+ * 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
@@ -477,42 +477,42 @@ typedef coff_int FIT, *pFIT;
* 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)
+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)
+stMember scNil byte offset iaux (if member of struct/union)
+stMember scBits bit offset iaux (bit field spec)
-stBlock scText address isymMac (text block)
+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)
+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)
+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)
+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
+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)
+stConstant scInfo value --- (scalar)
+stConstant scInfo iss --- (complex, e.g. string)
*
*/
diff --git a/src/base/loader/coff_symconst.h b/src/base/loader/coff_symconst.h
index f383c19e6..18529113f 100644
--- a/src/base/loader/coff_symconst.h
+++ b/src/base/loader/coff_symconst.h
@@ -59,30 +59,30 @@
*/
/* 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
+#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
+#define magicSym 0x7009
/* The Alpha uses this value instead, for some reason. */
-#define magicSym2 0x1992
+#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 */
+#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 */
@@ -90,111 +90,111 @@
* 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 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
+#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 */
+#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 */
+#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
+#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
+#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
+#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
index a5a0ad9a4..d1719f1c6 100644
--- a/src/base/loader/ecoff_object.cc
+++ b/src/base/loader/ecoff_object.cc
@@ -34,7 +34,7 @@
#include "base/misc.hh"
#include "base/loader/symtab.hh"
-#include "base/trace.hh" // for DPRINTF
+#include "base/trace.hh" // for DPRINTF
#include "base/loader/exec_ecoff.h"
#include "base/loader/coff_sym.h"
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
index 8e41ffd16..16fc698dd 100644
--- a/src/base/loader/elf_object.cc
+++ b/src/base/loader/elf_object.cc
@@ -29,6 +29,7 @@
* Ali Saidi
*/
+#include <cassert>
#include <string>
#include "gelf.h"
@@ -36,7 +37,7 @@
#include "base/loader/elf_object.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
-#include "base/trace.hh" // for DPRINTF
+#include "base/trace.hh" // for DPRINTF
#include "sim/byteswap.hh"
using namespace std;
@@ -79,13 +80,19 @@ ElfObject::tryFile(const string &fname, int fd, size_t len, uint8_t *data)
arch = ObjectFile::SPARC32;
} else if (ehdr.e_machine == EM_MIPS
&& ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
- arch = ObjectFile::Mips;
+ if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) {
+ arch = ObjectFile::Mips;
+ } else {
+ fatal("The binary you're trying to load is compiled for big "
+ "endian MIPS. M5\nonly supports little endian MIPS. "
+ "Please recompile your binary.\n");
+ }
} else if (ehdr.e_machine == EM_X86_64 &&
ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
- //In the future, we might want to differentiate between 32 bit
- //and 64 bit x86 processes in case there are differences in their
- //initial stack frame.
- arch = ObjectFile::X86;
+ arch = ObjectFile::X86_64;
+ } else if (ehdr.e_machine == EM_386 &&
+ ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
+ arch = ObjectFile::I386;
} else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
arch = ObjectFile::Alpha;
} else if (ehdr.e_machine == EM_ARM) {
@@ -284,6 +291,8 @@ ElfObject::ElfObject(const string &_filename, int _fd,
data.size = phdr.p_filesz;
data.fileImage = fileData + phdr.p_offset;
} else {
+ // If it's none of the above but is loadable,
+ // load the filesize worth of data
Segment extra;
extra.baseAddr = phdr.p_paddr;
extra.size = phdr.p_filesz;
diff --git a/src/base/loader/hex_file.cc b/src/base/loader/hex_file.cc
index 1855ebe0c..61d6c8009 100755
--- a/src/base/loader/hex_file.cc
+++ b/src/base/loader/hex_file.cc
@@ -28,134 +28,111 @@
* Authors: Jaidev Patwardhan
*/
+#include <cctype>
+#include <cstdio>
#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/hex_file.hh"
#include "base/loader/symtab.hh"
-
-
#include "mem/translating_port.hh"
using namespace std;
-/* Load a Hex File into memory.
- Currently only used with MIPS BARE_IRON mode.
- A hex file consists of [Address Data] tuples that get directly loaded into
- physical memory. The address specified is a word address (i.e., to get the byte address, shift left by 2)
- The data is a full 32-bit hex value.
+/*
+ * Load a Hex File into memory. Currently only used with MIPS
+ * BARE_IRON mode. A hex file consists of [Address Data] tuples that
+ * get directly loaded into physical memory. The address specified is
+ * a word address (i.e., to get the byte address, shift left by 2) The
+ * data is a full 32-bit hex value.
*/
HexFile::HexFile(const string _filename)
: filename(_filename)
{
- fp = fopen(filename.c_str(),"r");
- if(fp == NULL)
- {
- panic("Unable to open %s\n",filename.c_str());
- }
-
+ fp = fopen(filename.c_str(), "r");
+ if (fp == NULL)
+ panic("Unable to open %s\n", filename.c_str());
}
HexFile::~HexFile()
{
}
-
bool
-HexFile::loadSections(Port *memPort, Addr addrMask)
+HexFile::loadSections(Port *memPort)
{
- char Line[64];
- Addr MemAddr;
- uint32_t Data;
- while(!feof(fp))
- {
- fgets(Line,64,fp);
- parseLine(Line,&MemAddr,&Data);
- // printf("Hex:%u\n",Data);
-
- if(MemAddr != 0)
- {
- // Now, write to memory
- memPort->writeBlob(MemAddr<<2,(uint8_t *)&Data,sizeof(Data));
+ char Line[64];
+ Addr MemAddr;
+ uint32_t Data;
+ while (!feof(fp)) {
+ char *ret = fgets(Line, sizeof(Line), fp);
+ if (!ret)
+ panic("malformed file");
+ parseLine(Line, &MemAddr, &Data);
+ if (MemAddr != 0) {
+ // Now, write to memory
+ memPort->writeBlob(MemAddr << 2, (uint8_t *)&Data, sizeof(Data));
}
}
return true;
}
-void HexFile::parseLine(char *Str,Addr *A, uint32_t *D)
-{
- int i=0;
- bool Flag = false;
- *A = 0;
- *D = 0;
- int Digit = 0;
- unsigned Number = 0;
- /* Skip white spaces */
- while(Str[i] != '\0' && Str[i]==' ')
- i++;
- /* Ok, we're at some character...process things */
- while(Str[i] != '\0')
- {
- if(Str[i]>='0' && Str[i]<='9')
- {
- Digit=Str[i]-'0';
- }
- else if(Str[i]>='a' && Str[i]<='f')
- {
- Digit=Str[i]-'a'+10;
- }
- else if(Str[i]>='A' && Str[i]<='F')
- {
+void
+HexFile::parseLine(char *Str, Addr *A, uint32_t *D)
+{
+ int i = 0;
+ bool Flag = false;
+ *A = 0;
+ *D = 0;
+ int Digit = 0;
+ unsigned Number = 0;
+
+ /* Skip white spaces */
+ while (Str[i] != '\0' && Str[i]==' ')
+ i++;
+
+ /* Ok, we're at some character...process things */
+ while (Str[i] != '\0') {
+ if (Str[i] >= '0' && Str[i] <= '9') {
+ Digit = Str[i] - '0';
+ } else if (Str[i] >= 'a' && Str[i] <= 'f') {
+ Digit = Str[i] - 'a' + 10;
+ } else if (Str[i] >= 'A' && Str[i] <= 'F') {
Digit=Str[i]-'A'+10;
- }
- else if(Str[i] == ' ' || Str[i]=='\n')
- {
- if(Number == 0)
- return;
- if(Flag == false)
- {
- *A = Number;
- Number = 0;
- Flag = true;
- }
- else
- {
- *D = Number;
- return;
+ } else if (Str[i] == ' ' || Str[i] == '\n') {
+ if (Number == 0)
+ return;
+ if (Flag == false) {
+ *A = Number;
+ Number = 0;
+ Flag = true;
+ } else {
+ *D = Number;
+ return;
}
+ } else {
+ // Ok, we've encountered a non-hex character, cannot be a
+ // valid line, skip and return 0's
+ *A = 0;
+ *D = 0;
+ return;
}
- else
- {
- // Ok, we've encountered a non-hex character, cannot be a valid line, skip and return 0's
- *A = 0;
- *D = 0;
- return;
- }
- Number<<=4;
- Number+=Digit;
- i++;
+ Number <<= 4;
+ Number += Digit;
+ i++;
}
- if(Flag != true)
- {
- *A = 0;
- *D = 0;
- }
- else
- *D = Number;
+ if (Flag != true) {
+ *A = 0;
+ *D = 0;
+ } else {
+ *D = Number;
+ }
}
-
-
void
HexFile::close()
{
- fclose(fp);
+ fclose(fp);
}
diff --git a/src/base/loader/hex_file.hh b/src/base/loader/hex_file.hh
index 1dbfd034f..40483e684 100755
--- a/src/base/loader/hex_file.hh
+++ b/src/base/loader/hex_file.hh
@@ -28,50 +28,31 @@
* Authors: Jaidev Patwardhan
*/
-#ifndef __HEX_FILE_HH__
-#define __HEX_FILE_HH__
+#ifndef __BASE_LOADER_HEX_FILE_HH__
+#define __BASE_LOADER_HEX_FILE_HH__
+#include <cstdio>
#include <limits>
#include <string>
-#include "sim/host.hh" // for Addr
-#include <fstream>
+#include "sim/host.hh" // for Addr
class Port;
class HexFile
{
- public:
-
-
protected:
const std::string filename;
FILE *fp;
+ void parseLine(char *, Addr *, uint32_t *);
+
public:
- virtual ~HexFile();
HexFile(const std::string _filename);
+ virtual ~HexFile();
void close();
-
- bool loadSections(Port *memPort, Addr addrMask =
- std::numeric_limits<Addr>::max());
-
- protected:
-
- typedef struct {
- Addr MemAddr;
- uint32_t Data;
- } HexLine;
-
- Addr entry;
- Addr globalPtr;
-
- public:
- void parseLine(char *,Addr *,uint32_t *);
- Addr entryPoint() const { return entry; }
- Addr globalPointer() const { return globalPtr; }
-
+ bool loadSections(Port *memPort);
};
-#endif // __HEX_FILE_HH__
+#endif // __BASE_LOADER_HEX_FILE_HH__
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
index 7f2bef0bf..d363cde84 100644
--- a/src/base/loader/object_file.hh
+++ b/src/base/loader/object_file.hh
@@ -35,7 +35,7 @@
#include <limits>
#include <string>
-#include "sim/host.hh" // for Addr
+#include "sim/host.hh" // for Addr
class Port;
class SymbolTable;
@@ -50,7 +50,8 @@ class ObjectFile
SPARC64,
SPARC32,
Mips,
- X86,
+ X86_64,
+ I386,
Arm
};
diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh
index 184c0a996..cc1dc368f 100644
--- a/src/base/loader/symtab.hh
+++ b/src/base/loader/symtab.hh
@@ -34,8 +34,9 @@
#include <iosfwd>
#include <map>
+#include <string>
-#include "sim/host.hh" // for Addr
+#include "sim/host.hh" // for Addr
class Checkpoint;
class SymbolTable
diff --git a/src/base/misc.cc b/src/base/misc.cc
index afb48ca80..035282baf 100644
--- a/src/base/misc.cc
+++ b/src/base/misc.cc
@@ -28,8 +28,10 @@
* Authors: Nathan Binkert
*/
+#include <cstdlib>
#include <iostream>
#include <string>
+#include <zlib.h>
#include "base/cprintf.hh"
#include "base/hostinfo.hh"
@@ -42,42 +44,24 @@
using namespace std;
-void
-__panic(const char *func, const char *file, int line, const char *fmt,
- CPRINTF_DEFINITION)
-{
- string format = "panic: ";
- format += fmt;
- switch (format[format.size() - 1]) {
- case '\n':
- case '\r':
- break;
- default:
- format += "\n";
- }
-
- format += " @ cycle %d\n[%s:%s, line %d]\n";
-
- CPrintfArgsList args(VARARGS_ALLARGS);
-
- args.push_back(curTick);
- args.push_back(func);
- args.push_back(file);
- args.push_back(line);
+bool want_warn = true;
+bool want_info = true;
+bool want_hack = true;
- ccprintf(cerr, format.c_str(), args);
-
- abort();
-}
+bool warn_verbose = false;
+bool info_verbose = false;
+bool hack_verbose = false;
void
-__fatal(const char *func, const char *file, int line, const char *fmt,
- CPRINTF_DEFINITION)
+__exit_message(const char *prefix, int code,
+ const char *func, const char *file, int line,
+ const char *fmt, CPRINTF_DEFINITION)
{
CPrintfArgsList args(VARARGS_ALLARGS);
- string format = "fatal: ";
- format += fmt;
+ string format = prefix;
+ format += ": ";
+ format += fmt;
switch (format[format.size() - 1]) {
case '\n':
case '\r':
@@ -85,28 +69,39 @@ __fatal(const char *func, const char *file, int line, const char *fmt,
default:
format += "\n";
}
+
+ uint32_t crc = crc32(0, (const Bytef*)fmt, strlen(fmt));
format += " @ cycle %d\n[%s:%s, line %d]\n";
format += "Memory Usage: %ld KBytes\n";
+ format += "For more information see: http://www.m5sim.org/%s/%x\n";
args.push_back(curTick);
args.push_back(func);
args.push_back(file);
args.push_back(line);
args.push_back(memUsage());
+ args.push_back(prefix);
+ args.push_back(crc);
ccprintf(cerr, format.c_str(), args);
- exit(1);
+ if (code < 0)
+ abort();
+ else
+ exit(code);
}
void
-__warn(const char *func, const char *file, int line, const char *fmt,
- CPRINTF_DEFINITION)
+__base_message(std::ostream &stream, const char *prefix, bool verbose,
+ const char *func, const char *file, int line,
+ const char *fmt, CPRINTF_DEFINITION)
{
- string format = "warn: ";
- format += fmt;
+ CPrintfArgsList args(VARARGS_ALLARGS);
+ string format = prefix;
+ format += ": ";
+ format += fmt;
switch (format[format.size() - 1]) {
case '\n':
case '\r':
@@ -114,21 +109,22 @@ __warn(const char *func, const char *file, int line, const char *fmt,
default:
format += "\n";
}
+
+ uint32_t crc = crc32(0, (const Bytef*)fmt, strlen(fmt));
+
+ if (verbose) {
+ format += " @ cycle %d\n[%s:%s, line %d]\n";
+ args.push_back(curTick);
+ args.push_back(func);
+ args.push_back(file);
+ args.push_back(line);
+ }
-#ifdef VERBOSE_WARN
- format += " @ cycle %d\n[%s:%s, line %d]\n";
-#endif
-
- CPrintfArgsList args(VARARGS_ALLARGS);
-
-#ifdef VERBOSE_WARN
- args.push_back(curTick);
- args.push_back(func);
- args.push_back(file);
- args.push_back(line);
-#endif
+ if (strcmp(prefix, "warn") == 0) {
+ format += "For more information see: http://www.m5sim.org/%s/%x\n";
+ args.push_back(prefix);
+ args.push_back(crc);
+ }
- ccprintf(cerr, format.c_str(), args);
- if (simout.isFile(*outputStream))
- ccprintf(*outputStream, format.c_str(), args);
+ ccprintf(stream, format.c_str(), args);
}
diff --git a/src/base/misc.hh b/src/base/misc.hh
index 1509ea2d2..25dcbaa62 100644
--- a/src/base/misc.hh
+++ b/src/base/misc.hh
@@ -29,10 +29,8 @@
* Dave Greene
*/
-#ifndef __MISC_HH__
-#define __MISC_HH__
-
-#include <cassert>
+#ifndef __BASE_MISC_HH__
+#define __BASE_MISC_HH__
#include "base/compiler.hh"
#include "base/cprintf.hh"
@@ -42,6 +40,30 @@
#define __FUNCTION__ "how to fix me?"
#endif
+// General exit message, these functions will never return and will
+// either abort() if code is < 0 or exit with the code if >= 0
+void __exit_message(const char *prefix, int code,
+ const char *func, const char *file, int line,
+ const char *format, CPRINTF_DECLARATION) M5_ATTR_NORETURN;
+
+void __exit_message(const char *prefix, int code,
+ const char *func, const char *file, int line,
+ const std::string &format, CPRINTF_DECLARATION) M5_ATTR_NORETURN;
+
+inline void
+__exit_message(const char *prefix, int code,
+ const char *func, const char *file, int line,
+ const std::string& format, CPRINTF_DEFINITION)
+{
+ __exit_message(prefix, code, func, file, line, format.c_str(),
+ VARARGS_ALLARGS);
+}
+
+M5_PRAGMA_NORETURN(__exit_message)
+#define exit_message(prefix, code, ...) \
+ __exit_message(prefix, code, __FUNCTION__, __FILE__, __LINE__, \
+ __VA_ARGS__)
+
//
// This implements a cprintf based panic() function. panic() should
// be called when something happens that should never ever happen
@@ -49,20 +71,7 @@
// calls abort which can dump core or enter the debugger.
//
//
-void __panic(const char *func, const char *file, int line, const char *format,
- CPRINTF_DECLARATION) M5_ATTR_NORETURN;
-void __panic(const char *func, const char *file, int line,
- const std::string &format, CPRINTF_DECLARATION)
-M5_ATTR_NORETURN;
-
-inline void
-__panic(const char *func, const char *file, int line,
- const std::string &format, CPRINTF_DEFINITION)
-{
- __panic(func, file, line, format.c_str(), VARARGS_ALLARGS);
-}
-M5_PRAGMA_NORETURN(__panic)
-#define panic(...) __panic(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) exit_message("panic", -1, __VA_ARGS__)
//
// This implements a cprintf based fatal() function. fatal() should
@@ -72,54 +81,70 @@ M5_PRAGMA_NORETURN(__panic)
// "normal" exit with an error code, as opposed to abort() like
// panic() does.
//
-void __fatal(const char *func, const char *file, int line, const char *format,
- CPRINTF_DECLARATION) M5_ATTR_NORETURN;
-void __fatal(const char *func, const char *file, int line,
- const std::string &format, CPRINTF_DECLARATION)
- M5_ATTR_NORETURN;
+#define fatal(...) exit_message("fatal", 1, __VA_ARGS__)
-inline void
-__fatal(const char *func, const char *file, int line,
- const std::string &format, CPRINTF_DEFINITION)
-{
- __fatal(func, file, line, format.c_str(), VARARGS_ALLARGS);
-}
-M5_PRAGMA_NORETURN(__fatal)
-#define fatal(...) __fatal(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
+void
+__base_message(std::ostream &stream, const char *prefix, bool verbose,
+ const char *func, const char *file, int line,
+ const char *format, CPRINTF_DECLARATION);
-//
-// This implements a cprintf based warn
-//
-void __warn(const char *func, const char *file, int line, const char *format,
- CPRINTF_DECLARATION);
inline void
-__warn(const char *func, const char *file, int line, const std::string &format,
- CPRINTF_DECLARATION)
+__base_message(std::ostream &stream, const char *prefix, bool verbose,
+ const char *func, const char *file, int line,
+ const std::string &format, CPRINTF_DECLARATION)
{
- __warn(func, file, line, format, VARARGS_ALLARGS);
+ __base_message(stream, prefix, verbose, func, file, line, format.c_str(),
+ VARARGS_ALLARGS);
}
-#define warn(...) __warn(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__)
-
-// Only print the warning message the first time it is seen. This
-// doesn't check the warning string itself, it just only lets one
-// warning come from the statement. So, even if the arguments change
-// and that would have resulted in a different warning message,
-// subsequent messages would still be supressed.
-#define warn_once(...) do { \
- static bool once = false; \
- if (!once) { \
- warn(__VA_ARGS__); \
- once = true; \
- } \
+
+#define base_message(stream, prefix, verbose, ...) \
+ __base_message(stream, prefix, verbose, __FUNCTION__, __FILE__, __LINE__, \
+ __VA_ARGS__)
+
+// Only print the message the first time this expression is
+// encountered. i.e. This doesn't check the string itself and
+// prevent duplicate strings, this prevents the statement from
+// happening more than once. So, even if the arguments change and that
+// would have resulted in a different message thoes messages would be
+// supressed.
+#define base_message_once(...) do { \
+ static bool once = false; \
+ if (!once) { \
+ base_message(__VA_ARGS__); \
+ once = true; \
+ } \
} while (0)
-//
-// assert() that prints out the current cycle
-//
-#define m5_assert(TEST) do { \
- if (!(TEST)) \
- ccprintf(std::cerr, "Assertion failure, curTick = %d\n", curTick); \
- assert(TEST); \
-} while (0)
+#define cond_message(cond, ...) do { \
+ if (cond) \
+ base_message(__VA_ARGS__); \
+ } while (0)
+
+#define cond_message_once(cond, ...) do { \
+ static bool once = false; \
+ if (!once && cond) { \
+ base_message(__VA_ARGS__); \
+ once = true; \
+ } \
+ } while (0)
+
+
+extern bool want_warn, warn_verbose;
+extern bool want_info, info_verbose;
+extern bool want_hack, hack_verbose;
+
+#define warn(...) \
+ cond_message(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__)
+#define inform(...) \
+ cond_message(want_info, std::cout, "info", info_verbose, __VA_ARGS__)
+#define hack(...) \
+ cond_message(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__)
+
+#define warn_once(...) \
+ cond_message_once(want_warn, std::cerr, "warn", warn_verbose, __VA_ARGS__)
+#define inform_once(...) \
+ cond_message_once(want_info, std::cout, "info", info_verbose, __VA_ARGS__)
+#define hack_once(...) \
+ cond_message_once(want_hack, std::cerr, "hack", hack_verbose, __VA_ARGS__)
-#endif // __MISC_HH__
+#endif // __BASE_MISC_HH__
diff --git a/src/base/output.cc b/src/base/output.cc
index 9d02a4a71..ea13e23d4 100644
--- a/src/base/output.cc
+++ b/src/base/output.cc
@@ -36,6 +36,8 @@
#include <fstream>
+#include <gzstream.hh>
+
#include "base/misc.hh"
#include "base/output.hh"
@@ -50,7 +52,45 @@ OutputDirectory::OutputDirectory()
{}
OutputDirectory::~OutputDirectory()
-{}
+{
+ for (map_t::iterator i = files.begin(); i != files.end(); i++) {
+ if (i->second)
+ delete i->second;
+ }
+}
+
+std::ostream *
+OutputDirectory::checkForStdio(const string &name) const
+{
+ if (name == "cerr" || name == "stderr")
+ return &cerr;
+
+ if (name == "cout" || name == "stdout")
+ return &cout;
+
+ return NULL;
+}
+
+ostream *
+OutputDirectory::openFile(const string &filename,
+ ios_base::openmode mode) const
+{
+ if (filename.find(".gz", filename.length()-3) < filename.length()) {
+ ogzstream *file = new ogzstream(filename.c_str(), mode);
+
+ if (!file->is_open())
+ fatal("Cannot open file %s", filename);
+
+ return file;
+ } else {
+ ofstream *file = new ofstream(filename.c_str(), mode);
+
+ if (!file->is_open())
+ fatal("Cannot open file %s", filename);
+
+ return file;
+ }
+}
void
OutputDirectory::setDirectory(const string &d)
@@ -60,19 +100,13 @@ OutputDirectory::setDirectory(const string &d)
dir = d;
- if (dir != ".") {
- if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST)
- panic("couldn't make output dir %s: %s\n",
- dir, strerror(errno));
- }
-
// guarantee that directory ends with a '/'
if (dir[dir.size() - 1] != '/')
dir += "/";
}
const string &
-OutputDirectory::directory()
+OutputDirectory::directory() const
{
if (dir.empty())
panic("Output directory not set!");
@@ -80,8 +114,8 @@ OutputDirectory::directory()
return dir;
}
-string
-OutputDirectory::resolve(const string &name)
+inline string
+OutputDirectory::resolve(const string &name) const
{
return (name[0] != '/') ? dir + name : name;
}
@@ -89,16 +123,14 @@ OutputDirectory::resolve(const string &name)
ostream *
OutputDirectory::create(const string &name, bool binary)
{
- if (name == "cerr" || name == "stderr")
- return &cerr;
-
- if (name == "cout" || name == "stdout")
- return &cout;
+ ostream *file = checkForStdio(name);
+ if (file)
+ return file;
- ofstream *file = new ofstream(resolve(name).c_str(),
- ios::trunc | binary ? ios::binary : (ios::openmode)0);
- if (!file->is_open())
- panic("Cannot open file %s", name);
+ string filename = resolve(name);
+ ios_base::openmode mode =
+ ios::trunc | binary ? ios::binary : (ios::openmode)0;
+ file = openFile(filename, mode);
return file;
}
@@ -106,21 +138,16 @@ OutputDirectory::create(const string &name, bool binary)
ostream *
OutputDirectory::find(const string &name)
{
- if (name == "cerr" || name == "stderr")
- return &cerr;
-
- if (name == "cout" || name == "stdout")
- return &cout;
+ ostream *file = checkForStdio(name);
+ if (file)
+ return file;
string filename = resolve(name);
map_t::iterator i = files.find(filename);
if (i != files.end())
return (*i).second;
- ofstream *file = new ofstream(filename.c_str(), ios::trunc);
- if (!file->is_open())
- panic("Cannot open file %s", filename);
-
+ file = openFile(filename);
files[filename] = file;
return file;
}
diff --git a/src/base/output.hh b/src/base/output.hh
index 5de0c4005..38c63714c 100644
--- a/src/base/output.hh
+++ b/src/base/output.hh
@@ -31,7 +31,7 @@
#ifndef __BASE_OUTPUT_HH__
#define __BASE_OUTPUT_HH__
-#include <iosfwd>
+#include <ios>
#include <map>
#include <string>
@@ -43,14 +43,20 @@ class OutputDirectory
map_t files;
std::string dir;
+ std::string resolve(const std::string &name) const;
+
+ protected:
+ std::ostream *checkForStdio(const std::string &name) const;
+ std::ostream *openFile(const std::string &filename,
+ std::ios_base::openmode mode = std::ios::trunc) const;
+
public:
OutputDirectory();
~OutputDirectory();
void setDirectory(const std::string &dir);
- const std::string &directory();
+ const std::string &directory() const;
- std::string resolve(const std::string &name);
std::ostream *create(const std::string &name, bool binary = false);
std::ostream *find(const std::string &name);
diff --git a/src/base/random_mt.cc b/src/base/random_mt.cc
index 1492240ee..6ea54ec03 100644
--- a/src/base/random_mt.cc
+++ b/src/base/random_mt.cc
@@ -123,15 +123,15 @@ Random::genrand()
int kk;
for (kk = 0; kk < N - M; kk++) {
- y = mt[kk] & UPPER_MASK | mt[kk+1] & LOWER_MASK;
+ y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (; kk < N - 1; kk++) {
- y = mt[kk] & UPPER_MASK | mt[kk+1] & LOWER_MASK;
+ y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
- y = mt[N - 1] & UPPER_MASK | mt[0] & LOWER_MASK;
+ y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1UL];
mti = 0;
diff --git a/src/base/range_map.hh b/src/base/range_map.hh
index 6d3450739..0ffc28ed9 100644
--- a/src/base/range_map.hh
+++ b/src/base/range_map.hh
@@ -46,7 +46,8 @@ class range_map
typedef typename RangeMap::iterator iterator;
template <class U>
- const iterator find(const Range<U> &r)
+ const iterator
+ find(const Range<U> &r)
{
iterator i;
@@ -69,7 +70,15 @@ class range_map
}
template <class U>
- bool intersect(const Range<U> &r)
+ const iterator
+ find(const U &r)
+ {
+ return find(RangeSize(r, 1));
+ }
+
+ template <class U>
+ bool
+ intersect(const Range<U> &r)
{
iterator i;
i = find(r);
@@ -80,7 +89,8 @@ class range_map
template <class U,class W>
- iterator insert(const Range<U> &r, const W d)
+ iterator
+ insert(const Range<U> &r, const W d)
{
if (intersect(r))
return tree.end();
@@ -88,42 +98,50 @@ class range_map
return tree.insert(std::make_pair<Range<T>,V>(r, d)).first;
}
- size_t erase(T k)
+ size_t
+ erase(T k)
{
return tree.erase(k);
}
- void erase(iterator p)
+ void
+ erase(iterator p)
{
tree.erase(p);
}
- void erase(iterator p, iterator q)
+ void
+ erase(iterator p, iterator q)
{
tree.erase(p,q);
}
- void clear()
+ void
+ clear()
{
tree.erase(tree.begin(), tree.end());
}
- iterator begin()
+ iterator
+ begin()
{
return tree.begin();
}
- iterator end()
+ iterator
+ end()
{
return tree.end();
}
- size_t size()
+ size_t
+ size()
{
return tree.size();
}
- bool empty()
+ bool
+ empty()
{
return tree.empty();
}
@@ -180,7 +198,8 @@ class range_multimap
}
template <class U>
- bool intersect(const Range<U> &r)
+ bool
+ intersect(const Range<U> &r)
{
std::pair<iterator,iterator> p;
p = find(r);
@@ -191,7 +210,8 @@ class range_multimap
template <class U,class W>
- iterator insert(const Range<U> &r, const W d)
+ iterator
+ insert(const Range<U> &r, const W d)
{
std::pair<iterator,iterator> p;
p = find(r);
@@ -202,42 +222,50 @@ class range_multimap
return tree.end();
}
- size_t erase(T k)
+ size_t
+ erase(T k)
{
return tree.erase(k);
}
- void erase(iterator p)
+ void
+ erase(iterator p)
{
tree.erase(p);
}
- void erase(iterator p, iterator q)
+ void
+ erase(iterator p, iterator q)
{
tree.erase(p,q);
}
- void clear()
+ void
+ clear()
{
tree.erase(tree.begin(), tree.end());
}
- iterator begin()
+ iterator
+ begin()
{
return tree.begin();
}
- iterator end()
+ iterator
+ end()
{
return tree.end();
}
- size_t size()
+ size_t
+ size()
{
return tree.size();
}
- bool empty()
+ bool
+ empty()
{
return tree.empty();
}
diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
index d5095e7f9..93d86447e 100644
--- a/src/base/remote_gdb.cc
+++ b/src/base/remote_gdb.cc
@@ -30,7 +30,7 @@
/*
* Copyright (c) 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -38,8 +38,8 @@
*
* 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.
+ * 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
@@ -51,8 +51,8 @@
* 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.
+ * 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.
@@ -69,7 +69,7 @@
* 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
+ * @(#)kgdb_stub.c 8.4 (Berkeley) 1/12/94
*/
/*-
@@ -89,8 +89,8 @@
* 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.
+ * 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.
@@ -195,6 +195,11 @@ GDBListener::name()
void
GDBListener::listen()
{
+ if (ListenSocket::allDisabled()) {
+ warn_once("Sockets disabled, not accepting gdb connections");
+ return;
+ }
+
while (!listener.listen(port, true)) {
DPRINTF(GDBMisc, "Can't bind port %d\n", port);
port++;
@@ -341,14 +346,16 @@ uint8_t
BaseRemoteGDB::getbyte()
{
uint8_t b;
- ::read(fd, &b, 1);
+ if (::read(fd, &b, 1) != 1)
+ warn("could not read byte from debugger");
return b;
}
void
BaseRemoteGDB::putbyte(uint8_t b)
{
- ::write(fd, &b, 1);
+ if (::write(fd, &b, 1) != 1)
+ warn("could not write byte to debugger");
}
// Send a packet to gdb
@@ -454,14 +461,11 @@ BaseRemoteGDB::read(Addr vaddr, size_t size, char *data)
DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size);
#if FULL_SYSTEM
- VirtualPort *port = context->getVirtPort(context);
+ VirtualPort *port = context->getVirtPort();
#else
TranslatingPort *port = context->getMemPort();
#endif
port->readBlob(vaddr, (uint8_t*)data, size);
-#if FULL_SYSTEM
- context->delVirtPort(port);
-#endif
#if TRACING_ON
if (DTRACE(GDBRead)) {
@@ -499,14 +503,12 @@ BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data)
DPRINTFNR("\n");
}
#if FULL_SYSTEM
- VirtualPort *port = context->getVirtPort(context);
+ VirtualPort *port = context->getVirtPort();
#else
TranslatingPort *port = context->getMemPort();
#endif
port->writeBlob(vaddr, (uint8_t*)data, size);
-#if FULL_SYSTEM
- context->delVirtPort(port);
-#else
+#if !FULL_SYSTEM
delete port;
#endif
diff --git a/src/base/res_list.hh b/src/base/res_list.hh
index 442280e15..024b56982 100644
--- a/src/base/res_list.hh
+++ b/src/base/res_list.hh
@@ -635,7 +635,7 @@ res_list<T>::remove(iterator q)
// A little "garbage collection"
if (++remove_count > 10) {
- // free_extras();
+ // free_extras();
remove_count = 0;
}
diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh
index 79de11156..38c4ec74f 100644
--- a/src/base/sat_counter.hh
+++ b/src/base/sat_counter.hh
@@ -64,13 +64,13 @@ class SaturatingCounterPred : public GenericPredictor
unsigned *table;
// Statistics
- Stats::Scalar<> predicted_one; // Total predictions of one, preds_one
- Stats::Scalar<> predicted_zero; // Total predictions of zero, preds_zero
- Stats::Scalar<> correct_pred_one; // Total correct predictions of one, correct_one
- Stats::Scalar<> correct_pred_zero; // Total correct predictions of zero, correct_zero
+ Stats::Scalar predicted_one; // Total predictions of one, preds_one
+ Stats::Scalar predicted_zero; // Total predictions of zero, preds_zero
+ Stats::Scalar correct_pred_one; // Total correct predictions of one, correct_one
+ Stats::Scalar correct_pred_zero; // Total correct predictions of zero, correct_zero
- Stats::Scalar<> record_zero; //updates_zero
- Stats::Scalar<> record_one; //updates_one
+ Stats::Scalar record_zero; //updates_zero
+ Stats::Scalar record_one; //updates_one
Stats::Formula preds_total;
Stats::Formula pred_frac_zero;
diff --git a/src/base/socket.cc b/src/base/socket.cc
index adcc48735..bcc5236b0 100644
--- a/src/base/socket.cc
+++ b/src/base/socket.cc
@@ -43,6 +43,23 @@
using namespace std;
+bool ListenSocket::listeningDisabled = false;
+bool ListenSocket::anyListening = false;
+
+void
+ListenSocket::disableAll()
+{
+ if (anyListening)
+ panic("Too late to disable all listeners, already have a listener");
+ listeningDisabled = true;
+}
+
+bool
+ListenSocket::allDisabled()
+{
+ return listeningDisabled;
+}
+
////////////////////////////////////////////////////////////////////////
//
//
@@ -92,6 +109,7 @@ ListenSocket::listen(int port, bool reuse)
listening = true;
+ anyListening = true;
return true;
}
diff --git a/src/base/socket.hh b/src/base/socket.hh
index 8e55eae72..942318e45 100644
--- a/src/base/socket.hh
+++ b/src/base/socket.hh
@@ -34,6 +34,14 @@
class ListenSocket
{
protected:
+ static bool listeningDisabled;
+ static bool anyListening;
+
+ public:
+ static void disableAll();
+ static bool allDisabled();
+
+ protected:
bool listening;
int fd;
diff --git a/src/base/statistics.cc b/src/base/statistics.cc
index 2acef83c5..0a59248e7 100644
--- a/src/base/statistics.cc
+++ b/src/base/statistics.cc
@@ -32,81 +32,106 @@
#include <fstream>
#include <list>
#include <map>
+#include <set>
#include <string>
#include "base/callback.hh"
#include "base/cprintf.hh"
+#include "base/debug.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"
using namespace std;
namespace Stats {
-StatData *
-DataAccess::find() const
+typedef map<const void *, Info *> MapType;
+
+// We wrap these in a function to make sure they're built in time.
+list<Info *> &
+statsList()
{
- return Database::find(const_cast<void *>((const void *)this));
+ static list<Info *> the_list;
+ return the_list;
}
-const StatData *
-getStatData(const void *stat)
+MapType &
+statsMap()
{
- return Database::find(const_cast<void *>(stat));
+ static MapType the_map;
+ return the_map;
}
void
-DataAccess::map(StatData *data)
+InfoAccess::setInfo(Info *info)
{
- Database::regStat(this, data);
+ if (statsMap().find(this) != statsMap().end())
+ panic("shouldn't register stat twice!");
+
+ statsList().push_back(info);
+
+#ifndef NDEBUG
+ pair<MapType::iterator, bool> result =
+#endif
+ statsMap().insert(make_pair(this, info));
+ assert(result.second && "this should never fail");
+ assert(statsMap().find(this) != statsMap().end());
}
-StatData *
-DataAccess::statData()
+void
+InfoAccess::setParams(const StorageParams *params)
{
- StatData *ptr = find();
- assert(ptr);
- return ptr;
+ info()->storageParams = params;
}
-const StatData *
-DataAccess::statData() const
+void
+InfoAccess::setInit()
{
- const StatData *ptr = find();
- assert(ptr);
- return ptr;
+ info()->flags |= init;
}
-void
-DataAccess::setInit()
+Info *
+InfoAccess::info()
{
- statData()->flags |= init;
+ MapType::const_iterator i = statsMap().find(this);
+ assert(i != statsMap().end());
+ return (*i).second;
}
-void
-DataAccess::setPrint()
+const Info *
+InfoAccess::info() const
{
- Database::regPrint(this);
+ MapType::const_iterator i = statsMap().find(this);
+ assert(i != statsMap().end());
+ return (*i).second;
}
-StatData::StatData()
- : flags(none), precision(-1), prereq(0)
+StorageParams::~StorageParams()
{
- static int count = 0;
- id = count++;
}
-StatData::~StatData()
+int Info::id_count = 0;
+
+int debug_break_id = -1;
+
+Info::Info()
+ : flags(none), precision(-1), prereq(0), storageParams(NULL)
+{
+ id = id_count++;
+ if (debug_break_id >= 0 and debug_break_id == id)
+ debug_break();
+}
+
+Info::~Info()
{
}
bool
-StatData::less(StatData *stat1, StatData *stat2)
+Info::less(Info *stat1, Info *stat2)
{
const string &name1 = stat1->name;
const string &name2 = stat2->name;
@@ -117,8 +142,8 @@ StatData::less(StatData *stat1, StatData *stat2)
tokenize(v1, name1, '.');
tokenize(v2, name2, '.');
- int last = min(v1.size(), v2.size()) - 1;
- for (int i = 0; i < last; ++i)
+ size_type last = min(v1.size(), v2.size()) - 1;
+ for (off_type i = 0; i < last; ++i)
if (v1[i] != v2[i])
return v1[i] < v2[i];
@@ -132,9 +157,9 @@ StatData::less(StatData *stat1, StatData *stat2)
}
bool
-StatData::baseCheck() const
+Info::baseCheck() const
{
- if (!(flags & init)) {
+ if (!(flags & Stats::init)) {
#ifdef DEBUG
cprintf("this is stat number %d\n", id);
#endif
@@ -150,54 +175,40 @@ StatData::baseCheck() const
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
+Info::enable()
{
- if (!root)
- return 0;
- else
- return root->size();
}
void
-FormulaBase::reset()
+VectorInfoBase::enable()
{
-}
-
-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;
+ size_type s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+ if (subdescs.size() < s)
+ subdescs.resize(s);
}
void
-FormulaBase::update(StatData *)
+VectorDistInfoBase::enable()
{
+ size_type s = size();
+ if (subnames.size() < s)
+ subnames.resize(s);
+ if (subdescs.size() < s)
+ subdescs.resize(s);
}
-string
-FormulaBase::str() const
+void
+Vector2dInfoBase::enable()
{
- return root ? root->str() : "";
+ if (subnames.size() < x)
+ subnames.resize(x);
+ if (subdescs.size() < x)
+ subdescs.resize(x);
+ if (y_subnames.size() < y)
+ y_subnames.resize(y);
}
Formula::Formula()
@@ -232,38 +243,86 @@ Formula::operator+=(Temp r)
}
void
-check()
+Formula::result(VResult &vec) const
{
- 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);
- }
+ if (root)
+ vec = root->result();
+}
- int j = 0;
- for (i = Database::stats().begin(); i != end; ++i) {
- StatData *data = *i;
- if (!(data->flags & print))
- data->name = "__Stat" + to_string(j++);
- }
+Result
+Formula::total() const
+{
+ return root ? root->total() : 0.0;
+}
+
+size_type
+Formula::size() const
+{
+ if (!root)
+ return 0;
+ else
+ return root->size();
+}
+
+void
+Formula::reset()
+{
+}
+
+bool
+Formula::zero() const
+{
+ VResult vec;
+ result(vec);
+ for (off_t i = 0; i < vec.size(); ++i)
+ if (vec[i] != 0.0)
+ return false;
+ return true;
+}
- Database::stats().sort(StatData::less);
+string
+Formula::str() const
+{
+ return root ? root->str() : "";
+}
- if (i == end)
- return;
+void
+enable()
+{
+ typedef list<Info *>::iterator iter_t;
+
+ iter_t i, end = statsList().end();
+ for (i = statsList().begin(); i != end; ++i) {
+ Info *info = *i;
+ assert(info);
+ if (!info->check() || !info->baseCheck())
+ panic("stat check failed for '%s' %d\n", info->name, info->id);
+ }
- iter_t last = i;
- ++i;
+ off_t j = 0;
+ for (i = statsList().begin(); i != end; ++i) {
+ Info *info = *i;
+ if (!(info->flags & print))
+ info->name = "__Stat" + to_string(j++);
+ }
- for (i = Database::stats().begin(); i != end; ++i) {
- if ((*i)->name == (*last)->name)
- panic("same name used twice! name=%s\n", (*i)->name);
+ statsList().sort(Info::less);
+
+ for (i = statsList().begin(); i != end; ++i) {
+ Info *info = *i;
+ info->enable();
+ }
+}
- last = i;
+void
+prepare()
+{
+ list<Info *>::iterator i = statsList().begin();
+ list<Info *>::iterator end = statsList().end();
+ while (i != end) {
+ Info *info = *i;
+ info->prepare();
+ ++i;
}
}
@@ -272,11 +331,11 @@ CallbackQueue resetQueue;
void
reset()
{
- Database::stat_list_t::iterator i = Database::stats().begin();
- Database::stat_list_t::iterator end = Database::stats().end();
+ list<Info *>::iterator i = statsList().begin();
+ list<Info *>::iterator end = statsList().end();
while (i != end) {
- StatData *data = *i;
- data->reset();
+ Info *info = *i;
+ info->reset();
++i;
}
diff --git a/src/base/statistics.hh b/src/base/statistics.hh
index 3a859d364..88704207d 100644
--- a/src/base/statistics.hh
+++ b/src/base/statistics.hh
@@ -26,7 +26,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Nathan Binkert
- * Erik Hallnor
*/
/** @file
@@ -56,9 +55,11 @@
#include <cmath>
#include <functional>
#include <iosfwd>
+#include <list>
#include <string>
#include <vector>
+#include "base/cast.hh"
#include "base/cprintf.hh"
#include "base/intmath.hh"
#include "base/refcnt.hh"
@@ -76,14 +77,19 @@ extern Tick curTick;
/* A namespace for all of the Statistics */
namespace Stats {
-/* Contains the statistic implementation details */
+struct StorageParams
+{
+ virtual ~StorageParams();
+};
+
//////////////////////////////////////////////////////////////////////
//
// Statistics Framework Base classes
//
//////////////////////////////////////////////////////////////////////
-struct StatData
+class Info
{
+ public:
/** The name of the stat. */
std::string name;
/** The description of the stat. */
@@ -93,18 +99,41 @@ struct StatData
/** The display precision. */
int precision;
/** A pointer to a prerequisite Stat. */
- const StatData *prereq;
+ const Info *prereq;
/**
* A unique stat ID for each stat in the simulator.
* Can be used externally for lookups as well as for debugging.
*/
+ static int id_count;
int id;
- StatData();
- virtual ~StatData();
+ public:
+ const StorageParams *storageParams;
+
+ public:
+ Info();
+ virtual ~Info();
+
+ /**
+ * 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;
+
+ /**
+ * Enable the stat for use
+ */
+ virtual void enable();
+
+ /**
+ * Prepare the stat for dumping.
+ */
+ virtual void prepare() = 0;
/**
- * Reset the corresponding stat to the default state.
+ * Reset the stat to the default state.
*/
virtual void reset() = 0;
@@ -115,14 +144,6 @@ struct StatData
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;
@@ -135,94 +156,95 @@ struct StatData
* @param stat2 The second stat.
* @return stat1's name is alphabetically before stat2's
*/
- static bool less(StatData *stat1, StatData *stat2);
+ static bool less(Info *stat1, Info *stat2);
+};
+
+template <class Stat, class Base>
+class InfoWrap : public Base
+{
+ protected:
+ Stat &s;
+
+ public:
+ InfoWrap(Stat &stat) : s(stat) {}
+
+ bool check() const { return s.check(); }
+ void prepare() { s.prepare(); }
+ void reset() { s.reset(); }
+ void
+ visit(Visit &visitor)
+ {
+ visitor.visit(*static_cast<Base *>(this));
+ }
+ bool zero() const { return s.zero(); }
};
-class ScalarData : public StatData
+class ScalarInfoBase : public Info
{
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
+class ScalarInfo : public InfoWrap<Stat, ScalarInfoBase>
{
- protected:
- Stat &s;
-
public:
- ScalarStatData(Stat &stat) : s(stat) {}
+ ScalarInfo(Stat &stat) : InfoWrap<Stat, ScalarInfoBase>(stat) {}
- 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(); }
+ Counter value() const { return this->s.value(); }
+ Result result() const { return this->s.result(); }
+ Result total() const { return this->s.total(); }
};
-struct VectorData : public StatData
+class VectorInfoBase : public Info
{
+ public:
/** Names and descriptions of subfields. */
- mutable std::vector<std::string> subnames;
- mutable std::vector<std::string> subdescs;
+ std::vector<std::string> subnames;
+ std::vector<std::string> subdescs;
+
+ public:
+ void enable();
- virtual size_t size() const = 0;
+ public:
+ virtual size_type 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);
- }
- }
+ virtual Result total() const = 0;
};
template <class Stat>
-class VectorStatData : public VectorData
+class VectorInfo : public InfoWrap<Stat, VectorInfoBase>
{
protected:
- Stat &s;
mutable VCounter cvec;
mutable VResult rvec;
public:
- VectorStatData(Stat &stat) : s(stat) {}
+ VectorInfo(Stat &stat) : InfoWrap<Stat, VectorInfoBase>(stat) {}
- virtual bool check() const { return s.check(); }
- virtual bool zero() const { return s.zero(); }
- virtual void reset() { s.reset(); }
+ size_type size() const { return this->s.size(); }
- virtual size_t size() const { return s.size(); }
- virtual VCounter &value() const
+ VCounter &
+ value() const
{
- s.value(cvec);
+ this->s.value(cvec);
return cvec;
}
- virtual const VResult &result() const
+
+ const VResult &
+ result() const
{
- s.result(rvec);
+ this->s.result(rvec);
return rvec;
}
- virtual Result total() const { return s.total(); }
- virtual void visit(Visit &visitor)
- {
- update();
- s.update(this);
- visitor.visit(*this);
- }
+
+ Result total() const { return this->s.total(); }
};
-struct DistDataData
+struct DistData
{
Counter min_val;
Counter max_val;
@@ -232,173 +254,146 @@ struct DistDataData
Counter sum;
Counter squares;
Counter samples;
-
- Counter min;
- Counter max;
- Counter bucket_size;
- int size;
- bool fancy;
};
-struct DistData : public StatData
+class DistInfoBase : public Info
{
+ public:
/** Local storage for the entry values, used for printing. */
- DistDataData data;
+ DistData data;
};
template <class Stat>
-class DistStatData : public DistData
+class DistInfo : public InfoWrap<Stat, DistInfoBase>
{
- protected:
- Stat &s;
-
public:
- DistStatData(Stat &stat) : s(stat) {}
-
- 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);
- }
+ DistInfo(Stat &stat) : InfoWrap<Stat, DistInfoBase>(stat) {}
};
-struct VectorDistData : public StatData
+class VectorDistInfoBase : public Info
{
- std::vector<DistDataData> data;
+ public:
+ std::vector<DistData> data;
- /** Names and descriptions of subfields. */
- mutable std::vector<std::string> subnames;
- mutable std::vector<std::string> subdescs;
+ /** Names and descriptions of subfields. */
+ std::vector<std::string> subnames;
+ std::vector<std::string> subdescs;
+ void enable();
+ protected:
/** 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);
- }
+ public:
+ virtual size_type size() const = 0;
};
template <class Stat>
-class VectorDistStatData : public VectorDistData
+class VectorDistInfo : public InfoWrap<Stat, VectorDistInfoBase>
{
- protected:
- Stat &s;
-
public:
- VectorDistStatData(Stat &stat) : s(stat) {}
+ VectorDistInfo(Stat &stat) : InfoWrap<Stat, VectorDistInfoBase>(stat) {}
- 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);
- }
+ size_type size() const { return this->s.size(); }
};
-struct Vector2dData : public StatData
+class Vector2dInfoBase : public Info
{
+ public:
/** Names and descriptions of subfields. */
std::vector<std::string> subnames;
std::vector<std::string> subdescs;
std::vector<std::string> y_subnames;
+ size_type x;
+ size_type y;
+
/** 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);
- }
+ void enable();
};
template <class Stat>
-class Vector2dStatData : public Vector2dData
+class Vector2dInfo : public InfoWrap<Stat, Vector2dInfoBase>
{
- protected:
- Stat &s;
-
public:
- Vector2dStatData(Stat &stat) : s(stat) {}
-
- 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);
- }
+ Vector2dInfo(Stat &stat) : InfoWrap<Stat, Vector2dInfoBase>(stat) {}
};
-class DataAccess
+class InfoAccess
{
protected:
- StatData *find() const;
- void map(StatData *data);
+ /** Set up an info class for this statistic */
+ void setInfo(Info *info);
+ /** Save Storage class parameters if any */
+ void setParams(const StorageParams *params);
+ /** Save Storage class parameters if any */
+ void setInit();
- StatData *statData();
- const StatData *statData() const;
+ /** Grab the information class for this statistic */
+ Info *info();
+ /** Grab the information class for this statistic */
+ const Info *info() const;
- void setInit();
- void setPrint();
+ public:
+ /**
+ * Reset the stat to the default state.
+ */
+ void reset() { }
+
+ /**
+ * @return true if this stat has a value and satisfies its
+ * requirement as a prereq
+ */
+ bool zero() const { return true; }
+
+ /**
+ * Check that this stat has been set up properly and is ready for
+ * use
+ * @return true for success
+ */
+ bool check() const { return true; }
};
-template <class Parent, class Child, template <class> class Data>
-class Wrap : public Child
+template <class Derived, template <class> class InfoType>
+class DataWrap : public InfoAccess
{
+ public:
+ typedef InfoType<Derived> Info;
+
protected:
- Parent &self() { return *reinterpret_cast<Parent *>(this); }
+ Derived &self() { return *static_cast<Derived *>(this); }
protected:
- Data<Child> *statData()
+ Info *
+ info()
{
- StatData *__data = DataAccess::statData();
- Data<Child> *ptr = dynamic_cast<Data<Child> *>(__data);
- assert(ptr);
- return ptr;
+ return safe_cast<Info *>(InfoAccess::info());
}
public:
- const Data<Child> *statData() const
+ const Info *
+ info() const
{
- const StatData *__data = DataAccess::statData();
- const Data<Child> *ptr = dynamic_cast<const Data<Child> *>(__data);
- assert(ptr);
- return ptr;
+ return safe_cast<const Info *>(InfoAccess::info());
}
protected:
/**
* Copy constructor, copies are not allowed.
*/
- Wrap(const Wrap &stat);
+ DataWrap(const DataWrap &stat);
+
/**
* Can't copy stats.
*/
- void operator=(const Wrap &);
+ void operator=(const DataWrap &);
public:
- Wrap()
+ DataWrap()
{
- this->map(new Data<Child>(*this));
+ this->setInfo(new Info(self()));
}
/**
@@ -406,13 +401,15 @@ class Wrap : public Child
* @param name The new name.
* @return A reference to this stat.
*/
- Parent &name(const std::string &_name)
+ Derived &
+ name(const std::string &_name)
{
- Data<Child> *data = this->statData();
- data->name = _name;
- this->setPrint();
+ Info *info = this->info();
+ info->name = _name;
+ info->flags |= print;
return this->self();
}
+ const std::string &name() const { return this->info()->name; }
/**
* Set the description and marks this stat to print at the end of
@@ -420,20 +417,22 @@ class Wrap : public Child
* @param desc The new description.
* @return A reference to this stat.
*/
- Parent &desc(const std::string &_desc)
+ Derived &
+ desc(const std::string &_desc)
{
- this->statData()->desc = _desc;
+ this->info()->desc = _desc;
return this->self();
}
/**
* Set the precision and marks this stat to print at the end of simulation.
- * @param p The new precision
+ * @param _precision The new precision
* @return A reference to this stat.
*/
- Parent &precision(int _precision)
+ Derived &
+ precision(int _precision)
{
- this->statData()->precision = _precision;
+ this->info()->precision = _precision;
return this->self();
}
@@ -442,9 +441,10 @@ class Wrap : public Child
* @param f The new flags.
* @return A reference to this stat.
*/
- Parent &flags(StatFlags _flags)
+ Derived &
+ flags(StatFlags _flags)
{
- this->statData()->flags |= _flags;
+ this->info()->flags |= _flags;
return this->self();
}
@@ -455,17 +455,20 @@ class Wrap : public Child
* @return A reference to this stat.
*/
template <class Stat>
- Parent &prereq(const Stat &prereq)
+ Derived &
+ prereq(const Stat &prereq)
{
- this->statData()->prereq = prereq.statData();
+ this->info()->prereq = prereq.info();
return this->self();
}
};
-template <class Parent, class Child, template <class Child> class Data>
-class WrapVec : public Wrap<Parent, Child, Data>
+template <class Derived, template <class> class InfoType>
+class DataWrapVec : public DataWrap<Derived, InfoType>
{
public:
+ typedef InfoType<Derived> Info;
+
// The following functions are specific to vectors. If you use them
// in a non vector context, you will get a nice compiler error!
@@ -476,15 +479,23 @@ class WrapVec : public Wrap<Parent, Child, Data>
* @param name The new name of the subfield.
* @return A reference to this stat.
*/
- Parent &subname(int index, const std::string &name)
+ Derived &
+ subname(off_type index, const std::string &name)
{
- std::vector<std::string> &subn = this->statData()->subnames;
+ Derived &self = this->self();
+ Info *info = self.info();
+
+ std::vector<std::string> &subn = info->subnames;
if (subn.size() <= index)
subn.resize(index + 1);
subn[index] = name;
- return this->self();
+ return self;
}
+ // The following functions are specific to 2d vectors. If you use
+ // them in a non vector context, you will get a nice compiler
+ // error because info doesn't have the right variables.
+
/**
* Set the subfield description for the given index and marks this stat to
* print at the end of simulation.
@@ -492,9 +503,12 @@ class WrapVec : public Wrap<Parent, Child, Data>
* @param desc The new description of the subfield
* @return A reference to this stat.
*/
- Parent &subdesc(int index, const std::string &desc)
+ Derived &
+ subdesc(off_type index, const std::string &desc)
{
- std::vector<std::string> &subd = this->statData()->subdescs;
+ Info *info = this->info();
+
+ std::vector<std::string> &subd = info->subdescs;
if (subd.size() <= index)
subd.resize(index + 1);
subd[index] = desc;
@@ -502,31 +516,61 @@ class WrapVec : public Wrap<Parent, Child, Data>
return this->self();
}
+ void
+ prepare()
+ {
+ Derived &self = this->self();
+ Info *info = this->info();
+
+ size_t size = self.size();
+ for (off_type i = 0; i < size; ++i)
+ self.data(i)->prepare(info);
+ }
+
+ void
+ reset()
+ {
+ Derived &self = this->self();
+ Info *info = this->info();
+
+ size_t size = self.size();
+ for (off_type i = 0; i < size; ++i)
+ self.data(i)->reset(info);
+ }
};
-template <class Parent, class Child, template <class Child> class Data>
-class WrapVec2d : public WrapVec<Parent, Child, Data>
+template <class Derived, template <class> class InfoType>
+class DataWrapVec2d : public DataWrapVec<Derived, InfoType>
{
public:
+ typedef InfoType<Derived> Info;
+
/**
* @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)
+ Derived &
+ 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();
+ Derived &self = this->self();
+ Info *info = this->info();
+
+ info->y_subnames.resize(self.y);
+ for (off_type i = 0; i < self.y; ++i)
+ info->y_subnames[i] = names[i];
+ return self;
}
- Parent &ysubname(int index, const std::string subname)
+
+ Derived &
+ ysubname(off_type 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();
+ Derived &self = this->self();
+ Info *info = this->info();
+
+ assert(index < self.y);
+ info->y_subnames.resize(self.y);
+ info->y_subnames[index] = subname.c_str();
+ return self;
}
};
@@ -539,57 +583,57 @@ class WrapVec2d : public WrapVec<Parent, Child, Data>
/**
* Templatized storage and interface for a simple scalar stat.
*/
-struct StatStor
+class StatStor
{
- public:
- /** The paramaters for this storage type, none for a scalar. */
- struct Params { };
-
private:
/** The statistic value. */
Counter data;
public:
+ struct Params : public StorageParams {};
+
+ public:
/**
* Builds this storage element and calls the base constructor of the
* datatype.
*/
- StatStor(const Params &) : data(Counter()) {}
+ StatStor(Info *info)
+ : 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; }
+ void set(Counter val) { 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; }
+ void inc(Counter val) { 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; }
+ void dec(Counter val) { 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; }
+ Counter value() 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; }
+ Result result() const { return (Result)data; }
+ /**
+ * Prepare stat data for dumping or serialization
+ */
+ void prepare(Info *info) { }
/**
* Reset stat value to default
*/
- void reset() { data = Counter(); }
+ void reset(Info *info) { data = Counter(); }
/**
* @return true if zero value
@@ -604,12 +648,8 @@ struct StatStor
* being watched. This is good for keeping track of residencies in structures
* among other things.
*/
-struct AvgStor
+class AvgStor
{
- public:
- /** The paramaters for this storage type */
- struct Params { };
-
private:
/** The current count. */
Counter current;
@@ -619,18 +659,24 @@ struct AvgStor
mutable Tick last;
public:
+ struct Params : public StorageParams {};
+
+ public:
/**
* Build and initializes this stat storage.
*/
- AvgStor(Params &p) : current(0), total(0), last(0) { }
+ AvgStor(Info *info)
+ : current(0), total(0), last(0)
+ { }
/**
* 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) {
+ void
+ set(Counter val)
+ {
total += current * (curTick - last);
last = curTick;
current = val;
@@ -639,71 +685,74 @@ struct AvgStor
/**
* 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(current + val, p); }
+ void inc(Counter val) { set(current + val); }
/**
* 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(current - val, p); }
+ void dec(Counter val) { set(current - val); }
/**
* Return the current count.
- * @param p The parameters for this storage.
* @return The current count.
*/
- Counter value(const Params &p) const { return current; }
+ Counter value() const { return current; }
/**
* Return the current average.
- * @param p The parameters for this storage.
* @return The current average.
*/
- Result result(const Params &p) const
+ Result
+ result() const
{
- total += current * (curTick - last);
- last = curTick;
+ assert(last == curTick);
return (Result)(total + current) / (Result)(curTick + 1);
}
/**
- * Reset stat value to default
+ * @return true if zero value
*/
- void reset()
+ bool zero() const { return total == 0.0; }
+
+ /**
+ * Prepare stat data for dumping or serialization
+ */
+ void
+ prepare(Info *info)
{
- total = 0;
+ total += current * (curTick - last);
last = curTick;
}
/**
- * @return true if zero value
+ * Reset stat value to default
*/
- bool zero() const { return total == 0.0; }
+ void
+ reset(Info *info)
+ {
+ total = 0.0;
+ last = curTick;
+ }
+
};
/**
* Implementation of a scalar stat. The type of stat is determined by the
* Storage template.
*/
-template <class Stor>
-class ScalarBase : public DataAccess
+template <class Derived, class Stor>
+class ScalarBase : public DataWrap<Derived, ScalarInfo>
{
public:
typedef Stor Storage;
-
- /** Define the params of the storage class. */
- typedef typename Storage::Params Params;
+ typedef typename Stor::Params Params;
protected:
/** The storage of this stat. */
char storage[sizeof(Storage)] __attribute__ ((aligned (8)));
- /** The parameters for this stat. */
- Params params;
-
protected:
/**
* Retrieve the storage.
@@ -731,8 +780,8 @@ class ScalarBase : public DataAccess
void
doInit()
{
- new (storage) Storage(params);
- setInit();
+ new (storage) Storage(this->info());
+ this->setInit();
}
public:
@@ -740,14 +789,13 @@ class ScalarBase : public DataAccess
* Return the current value of this stat as its base type.
* @return The current value.
*/
- Counter value() const { return data()->value(params); }
+ Counter value() const { return data()->value(); }
public:
- /**
- * Create and initialize this stat, register it with the database.
- */
ScalarBase()
- { }
+ {
+ this->doInit();
+ }
public:
// Common operators for stats
@@ -755,12 +803,12 @@ class ScalarBase : public DataAccess
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
- void operator++() { data()->inc(1, params); }
+ void operator++() { data()->inc(1); }
/**
* Decrement the stat by 1. This calls the associated storage object dec
* function.
*/
- void operator--() { data()->dec(1, params); }
+ void operator--() { data()->dec(1); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
@@ -773,7 +821,7 @@ class ScalarBase : public DataAccess
* @param v The new value.
*/
template <typename U>
- void operator=(const U &v) { data()->set(v, params); }
+ void operator=(const U &v) { data()->set(v); }
/**
* Increment the stat by the given value. This calls the associated
@@ -781,7 +829,7 @@ class ScalarBase : public DataAccess
* @param v The value to add.
*/
template <typename U>
- void operator+=(const U &v) { data()->inc(v, params); }
+ void operator+=(const U &v) { data()->inc(v); }
/**
* Decrement the stat by the given value. This calls the associated
@@ -789,99 +837,102 @@ class ScalarBase : public DataAccess
* @param v The value to substract.
*/
template <typename U>
- void operator-=(const U &v) { data()->dec(v, params); }
+ void operator-=(const U &v) { data()->dec(v); }
/**
* Return the number of elements, always 1 for a scalar.
* @return 1.
*/
- size_t size() const { return 1; }
+ size_type size() const { return 1; }
- bool check() const { return true; }
-
- /**
- * Reset stat value to default
- */
- void reset() { data()->reset(); }
+ Counter value() { return data()->value(); }
- Counter value() { return data()->value(params); }
-
- Result result() { return data()->result(params); }
+ Result result() { return data()->result(); }
Result total() { return result(); }
bool zero() { return result() == 0.0; }
+ void reset() { data()->reset(this->info()); }
+ void prepare() { data()->prepare(this->info()); }
};
-class ProxyData : public ScalarData
+class ProxyInfo : public ScalarInfoBase
{
public:
- virtual void visit(Visit &visitor) { visitor.visit(*this); }
- 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() { }
+ std::string str() const { return to_string(value()); }
+ size_type size() const { return 1; }
+ bool check() const { return true; }
+ void prepare() { }
+ void reset() { }
+ bool zero() const { return value() == 0; }
+
+ void visit(Visit &visitor) { visitor.visit(*this); }
};
template <class T>
-class ValueProxy : public ProxyData
+class ValueProxy : public ProxyInfo
{
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; }
+ Counter value() const { return *scalar; }
+ Result result() const { return *scalar; }
+ Result total() const { return *scalar; }
};
template <class T>
-class FunctorProxy : public ProxyData
+class FunctorProxy : public ProxyInfo
{
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)(); }
+ Counter value() const { return (*functor)(); }
+ Result result() const { return (*functor)(); }
+ Result total() const { return (*functor)(); }
};
-class ValueBase : public DataAccess
+template <class Derived>
+class ValueBase : public DataWrap<Derived, ScalarInfo>
{
private:
- ProxyData *proxy;
+ ProxyInfo *proxy;
public:
ValueBase() : proxy(NULL) { }
~ValueBase() { if (proxy) delete proxy; }
template <class T>
- void scalar(T &value)
+ Derived &
+ scalar(T &value)
{
proxy = new ValueProxy<T>(value);
- setInit();
+ this->setInit();
+ return this->self();
}
template <class T>
- void functor(T &func)
+ Derived &
+ functor(T &func)
{
proxy = new FunctorProxy<T>(func);
- setInit();
+ this->setInit();
+ return this->self();
}
Counter value() { return proxy->value(); }
Result result() const { return proxy->result(); }
Result total() const { return proxy->total(); };
- size_t size() const { return proxy->size(); }
+ size_type size() const { return proxy->size(); }
std::string str() const { return proxy->str(); }
bool zero() const { return proxy->zero(); }
bool check() const { return proxy != NULL; }
+ void prepare() { }
void reset() { }
};
@@ -900,34 +951,32 @@ class ScalarProxy
{
private:
/** Pointer to the parent Vector. */
- Stat *stat;
+ Stat &stat;
/** The index to access in the parent VectorBase. */
- int index;
+ off_type index;
public:
/**
* Return the current value of this stat as its base type.
* @return The current value.
*/
- Counter value() const { return stat->data(index)->value(stat->params); }
+ Counter value() const { return stat.data(index)->value(); }
/**
* Return the current value of this statas a result type.
* @return The current value.
*/
- Result result() const { return stat->data(index)->result(stat->params); }
+ Result result() const { return stat.data(index)->result(); }
public:
/**
* Create and initialize this proxy, do not register it with the database.
- * @param p The params to use.
* @param i The index to access.
*/
- ScalarProxy(Stat *s, int i)
+ ScalarProxy(Stat &s, off_type i)
: stat(s), index(i)
{
- assert(stat);
}
/**
@@ -943,7 +992,9 @@ class ScalarProxy
* @param sp The proxy to copy.
* @return A reference to this proxy.
*/
- const ScalarProxy &operator=(const ScalarProxy &sp) {
+ const ScalarProxy &
+ operator=(const ScalarProxy &sp)
+ {
stat = sp.stat;
index = sp.index;
return *this;
@@ -955,12 +1006,12 @@ class ScalarProxy
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
- void operator++() { stat->data(index)->inc(1, stat->params); }
+ void operator++() { stat.data(index)->inc(1); }
/**
* Decrement the stat by 1. This calls the associated storage object dec
* function.
*/
- void operator--() { stat->data(index)->dec(1, stat->params); }
+ void operator--() { stat.data(index)->dec(1); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
@@ -973,7 +1024,11 @@ class ScalarProxy
* @param v The new value.
*/
template <typename U>
- void operator=(const U &v) { stat->data(index)->set(v, stat->params); }
+ void
+ operator=(const U &v)
+ {
+ stat.data(index)->set(v);
+ }
/**
* Increment the stat by the given value. This calls the associated
@@ -981,7 +1036,11 @@ class ScalarProxy
* @param v The value to add.
*/
template <typename U>
- void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); }
+ void
+ operator+=(const U &v)
+ {
+ stat.data(index)->inc(v);
+ }
/**
* Decrement the stat by the given value. This calls the associated
@@ -989,25 +1048,23 @@ class ScalarProxy
* @param v The value to substract.
*/
template <typename U>
- void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); }
+ void
+ operator-=(const U &v)
+ {
+ stat.data(index)->dec(v);
+ }
/**
* Return the number of elements, always 1 for a scalar.
* @return 1.
*/
- size_t size() const { return 1; }
-
- /**
- * This stat has no state. Nothing to reset
- */
- void reset() { }
+ size_type size() const { return 1; }
public:
std::string
str() const
{
- return csprintf("%s[%d]", stat->str(), index);
-
+ return csprintf("%s[%d]", stat.info()->name, index);
}
};
@@ -1015,27 +1072,22 @@ class ScalarProxy
* Implementation of a vector of stats. The type of stat is determined by the
* Storage class. @sa ScalarBase
*/
-template <class Stor>
-class VectorBase : public DataAccess
+template <class Derived, class Stor>
+class VectorBase : public DataWrapVec<Derived, VectorInfo>
{
public:
typedef Stor Storage;
-
- /** Define the params of the storage class. */
- typedef typename Storage::Params Params;
+ typedef typename Stor::Params Params;
/** Proxy type */
- typedef ScalarProxy<VectorBase<Storage> > Proxy;
-
- friend class ScalarProxy<VectorBase<Storage> >;
+ typedef ScalarProxy<Derived> Proxy;
+ friend class ScalarProxy<Derived>;
+ friend class DataWrapVec<Derived, VectorInfo>;
protected:
/** The storage of this stat. */
Storage *storage;
- size_t _size;
-
- /** The parameters for this stat. */
- Params params;
+ size_type _size;
protected:
/**
@@ -1043,17 +1095,17 @@ class VectorBase : public DataAccess
* @param index The vector index to access.
* @return The storage object at the given index.
*/
- Storage *data(int index) { return &storage[index]; }
+ Storage *data(off_type index) { return &storage[index]; }
/**
* Retrieve a const pointer to the storage.
* @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 { return &storage[index]; }
+ const Storage *data(off_type index) const { return &storage[index]; }
void
- doInit(int s)
+ doInit(size_type s)
{
assert(s > 0 && "size must be positive!");
assert(!storage && "already initialized");
@@ -1062,51 +1114,55 @@ class VectorBase : public DataAccess
char *ptr = new char[_size * sizeof(Storage)];
storage = reinterpret_cast<Storage *>(ptr);
- for (int i = 0; i < _size; ++i)
- new (&storage[i]) Storage(params);
+ for (off_type i = 0; i < _size; ++i)
+ new (&storage[i]) Storage(this->info());
- setInit();
+ this->setInit();
}
public:
- void value(VCounter &vec) const
+ void
+ value(VCounter &vec) const
{
vec.resize(size());
- for (int i = 0; i < size(); ++i)
- vec[i] = data(i)->value(params);
+ for (off_type i = 0; i < size(); ++i)
+ vec[i] = data(i)->value();
}
/**
* 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
+ void
+ result(VResult &vec) const
{
vec.resize(size());
- for (int i = 0; i < size(); ++i)
- vec[i] = data(i)->result(params);
+ for (off_type i = 0; i < size(); ++i)
+ vec[i] = data(i)->result();
}
/**
* Return a total of all entries in this vector.
* @return The total of all vector entries.
*/
- Result total() const {
+ Result
+ total() const
+ {
Result total = 0.0;
- for (int i = 0; i < size(); ++i)
- total += data(i)->result(params);
+ for (off_type i = 0; i < size(); ++i)
+ total += data(i)->result();
return total;
}
/**
* @return the number of elements in this vector.
*/
- size_t size() const { return _size; }
+ size_type size() const { return _size; }
bool
zero() const
{
- for (int i = 0; i < size(); ++i)
+ for (off_type i = 0; i < size(); ++i)
if (data(i)->zero())
return false;
return true;
@@ -1118,13 +1174,6 @@ class VectorBase : public DataAccess
return storage != NULL;
}
- void
- reset()
- {
- for (int i = 0; i < size(); ++i)
- data(i)->reset();
- }
-
public:
VectorBase()
: storage(NULL)
@@ -1135,49 +1184,60 @@ class VectorBase : public DataAccess
if (!storage)
return;
- for (int i = 0; i < _size; ++i)
+ for (off_type i = 0; i < _size; ++i)
data(i)->~Storage();
delete [] reinterpret_cast<char *>(storage);
}
/**
+ * Set this vector to have the given size.
+ * @param size The new size.
+ * @return A reference to this stat.
+ */
+ Derived &
+ init(size_type size)
+ {
+ Derived &self = this->self();
+ self.doInit(size);
+ return self;
+ }
+
+ /**
* Return a reference (ScalarProxy) to the stat at the given index.
* @param index The vector index to access.
* @return A reference of the stat.
*/
Proxy
- operator[](int index)
+ operator[](off_type index)
{
assert (index >= 0 && index < size());
- return Proxy(this, index);
+ return Proxy(this->self(), index);
}
-
- void update(StatData *data) {}
};
template <class Stat>
class VectorProxy
{
private:
- Stat *stat;
- int offset;
- int len;
+ Stat &stat;
+ off_type offset;
+ size_type len;
private:
mutable VResult vec;
typename Stat::Storage *
- data(int index)
+ data(off_type index)
{
assert(index < len);
- return stat->data(offset + index);
+ return stat.data(offset + index);
}
const typename Stat::Storage *
- data(int index) const
+ data(off_type index) const
{
assert(index < len);
- return const_cast<Stat *>(stat)->data(offset + index);
+ return stat.data(offset + index);
}
public:
@@ -1186,8 +1246,8 @@ class VectorProxy
{
vec.resize(size());
- for (int i = 0; i < size(); ++i)
- vec[i] = data(i)->result(stat->params);
+ for (off_type i = 0; i < size(); ++i)
+ vec[i] = data(i)->result();
return vec;
}
@@ -1195,14 +1255,14 @@ class VectorProxy
Result
total() const
{
- Result total = 0;
- for (int i = 0; i < size(); ++i)
- total += data(i)->result(stat->params);
+ Result total = 0.0;
+ for (off_type i = 0; i < size(); ++i)
+ total += data(i)->result();
return total;
}
public:
- VectorProxy(Stat *s, int o, int l)
+ VectorProxy(Stat &s, off_type o, size_type l)
: stat(s), offset(o), len(l)
{
}
@@ -1221,63 +1281,38 @@ class VectorProxy
return *this;
}
- ScalarProxy<Stat> operator[](int index)
+ ScalarProxy<Stat>
+ operator[](off_type index)
{
assert (index >= 0 && index < size());
return ScalarProxy<Stat>(stat, offset + index);
}
- size_t size() const { return len; }
-
- /**
- * This stat has no state. Nothing to reset.
- */
- void reset() { }
+ size_type size() const { return len; }
};
-template <class Stor>
-class Vector2dBase : public DataAccess
+template <class Derived, class Stor>
+class Vector2dBase : public DataWrapVec2d<Derived, Vector2dInfo>
{
public:
+ typedef Vector2dInfo<Derived> Info;
typedef Stor Storage;
- typedef typename Storage::Params Params;
- typedef VectorProxy<Vector2dBase<Storage> > Proxy;
- friend class ScalarProxy<Vector2dBase<Storage> >;
- friend class VectorProxy<Vector2dBase<Storage> >;
+ typedef typename Stor::Params Params;
+ typedef VectorProxy<Derived> Proxy;
+ friend class ScalarProxy<Derived>;
+ friend class VectorProxy<Derived>;
+ friend class DataWrapVec<Derived, Vector2dInfo>;
+ friend class DataWrapVec2d<Derived, Vector2dInfo>;
protected:
- size_t x;
- size_t y;
- size_t _size;
+ size_type x;
+ size_type y;
+ size_type _size;
Storage *storage;
- Params params;
protected:
- Storage *data(int index) { return &storage[index]; }
- const Storage *data(int index) const { return &storage[index]; }
-
- void
- doInit(int _x, int _y)
- {
- assert(_x > 0 && _y > 0 && "sizes must be positive!");
- assert(!storage && "already initialized");
-
- Vector2dData *statdata = dynamic_cast<Vector2dData *>(find());
-
- x = _x;
- y = _y;
- statdata->x = _x;
- statdata->y = _y;
- _size = x * y;
-
- char *ptr = new char[_size * sizeof(Storage)];
- storage = reinterpret_cast<Storage *>(ptr);
-
- for (int i = 0; i < _size; ++i)
- new (&storage[i]) Storage(params);
-
- setInit();
- }
+ Storage *data(off_type index) { return &storage[index]; }
+ const Storage *data(off_type index) const { return &storage[index]; }
public:
Vector2dBase()
@@ -1289,32 +1324,49 @@ class Vector2dBase : public DataAccess
if (!storage)
return;
- for (int i = 0; i < _size; ++i)
+ for (off_type i = 0; i < _size; ++i)
data(i)->~Storage();
delete [] reinterpret_cast<char *>(storage);
}
- void
- update(Vector2dData *newdata)
+ Derived &
+ init(size_type _x, size_type _y)
{
- int size = this->size();
- newdata->cvec.resize(size);
- for (int i = 0; i < size; ++i)
- newdata->cvec[i] = data(i)->value(params);
+ assert(_x > 0 && _y > 0 && "sizes must be positive!");
+ assert(!storage && "already initialized");
+
+ Derived &self = this->self();
+ Info *info = this->info();
+
+ x = _x;
+ y = _y;
+ info->x = _x;
+ info->y = _y;
+ _size = x * y;
+
+ char *ptr = new char[_size * sizeof(Storage)];
+ storage = reinterpret_cast<Storage *>(ptr);
+
+ for (off_type i = 0; i < _size; ++i)
+ new (&storage[i]) Storage(info);
+
+ this->setInit();
+
+ return self;
}
- std::string ysubname(int i) const { return (*this->y_subnames)[i]; }
+ std::string ysubname(off_type i) const { return (*this->y_subnames)[i]; }
Proxy
- operator[](int index)
+ operator[](off_type index)
{
- int offset = index * y;
+ off_type offset = index * y;
assert (index >= 0 && offset + index < size());
- return Proxy(this, offset, y);
+ return Proxy(this->self(), offset, y);
}
- size_t
+ size_type
size() const
{
return _size;
@@ -1325,25 +1377,41 @@ class Vector2dBase : public DataAccess
{
return data(0)->zero();
#if 0
- for (int i = 0; i < size(); ++i)
+ for (off_type i = 0; i < size(); ++i)
if (!data(i)->zero())
return false;
return true;
#endif
}
+ void
+ prepare()
+ {
+ Info *info = this->info();
+ size_type size = this->size();
+
+ for (off_type i = 0; i < size; ++i)
+ data(i)->prepare(info);
+
+ info->cvec.resize(size);
+ for (off_type i = 0; i < size; ++i)
+ info->cvec[i] = data(i)->value();
+ }
+
/**
* Reset stat value to default
*/
void
reset()
{
- for (int i = 0; i < size(); ++i)
- data(i)->reset();
+ Info *info = this->info();
+ size_type size = this->size();
+ for (off_type i = 0; i < size; ++i)
+ data(i)->reset(info);
}
bool
- check()
+ check() const
{
return storage != NULL;
}
@@ -1355,27 +1423,44 @@ class Vector2dBase : public DataAccess
//
//////////////////////////////////////////////////////////////////////
+struct DistParams : public StorageParams
+{
+ const bool fancy;
+
+ /** 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. */
+ size_type buckets;
+
+ explicit DistParams(bool f) : fancy(f) {}
+};
+
/**
* Templatized storage and interface for a distrbution stat.
*/
-struct DistStor
+class 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;
+ struct Params : public DistParams
+ {
+ Params() : DistParams(false) {}
};
- enum { fancy = false };
private:
+ /** The minimum value to track. */
+ Counter min_track;
+ /** The maximum value to track. */
+ Counter max_track;
+ /** The number of entries in each bucket. */
+ Counter bucket_size;
+ /** The number of buckets. Equal to (max-min)/bucket_size. */
+ size_type buckets;
+
/** The smallest value sampled. */
Counter min_val;
/** The largest value sampled. */
@@ -1394,27 +1479,28 @@ struct DistStor
VCounter cvec;
public:
- DistStor(const Params &params)
- : cvec(params.size)
+ DistStor(Info *info)
+ : cvec(safe_cast<const Params *>(info->storageParams)->buckets)
{
- reset();
+ reset(info);
}
/**
* 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 &params)
+ void
+ sample(Counter val, int number)
{
- if (val < params.min)
+ if (val < min_track)
underflow += number;
- else if (val > params.max)
+ else if (val > max_track)
overflow += number;
else {
- int index = (int)std::floor((val - params.min) / params.bucket_size);
- assert(index < size(params));
+ size_type index =
+ (size_type)std::floor((val - min_track) / bucket_size);
+ assert(index < size());
cvec[index] += number;
}
@@ -1433,52 +1519,57 @@ struct DistStor
/**
* 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(); }
+ size_type size() 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 &params) const
+ bool
+ zero() const
{
return samples == Counter();
}
- void update(DistDataData *data, const Params &params)
+ void
+ prepare(Info *info, DistData &data)
{
- data->min = params.min;
- data->max = params.max;
- data->bucket_size = params.bucket_size;
- data->size = params.size;
+ const Params *params = safe_cast<const Params *>(info->storageParams);
- 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.min_val = (min_val == CounterLimits::max()) ? 0 : min_val;
+ data.max_val = (max_val == CounterLimits::min()) ? 0 : max_val;
+ data.underflow = underflow;
+ data.overflow = overflow;
- data->sum = sum;
- data->squares = squares;
- data->samples = samples;
+ int buckets = params->buckets;
+ data.cvec.resize(buckets);
+ for (off_type i = 0; i < buckets; ++i)
+ data.cvec[i] = cvec[i];
+
+ data.sum = sum;
+ data.squares = squares;
+ data.samples = samples;
}
/**
* Reset stat value to default
*/
- void reset()
+ void
+ reset(Info *info)
{
- min_val = INT_MAX;
- max_val = INT_MIN;
+ const Params *params = safe_cast<const Params *>(info->storageParams);
+ min_track = params->min;
+ max_track = params->max;
+ bucket_size = params->bucket_size;
+
+ min_val = CounterLimits::max();
+ max_val = CounterLimits::min();
underflow = 0;
overflow = 0;
- int size = cvec.size();
- for (int i = 0; i < size; ++i)
+ size_type size = cvec.size();
+ for (off_type i = 0; i < size; ++i)
cvec[i] = Counter();
sum = Counter();
@@ -1491,14 +1582,13 @@ struct DistStor
* Templatized storage and interface for a distribution that calculates mean
* and variance.
*/
-struct FancyStor
+class FancyStor
{
public:
- /**
- * No paramters for this storage.
- */
- struct Params {};
- enum { fancy = true };
+ struct Params : public DistParams
+ {
+ Params() : DistParams(true) {}
+ };
private:
/** The current sum. */
@@ -1512,7 +1602,7 @@ struct FancyStor
/**
* Create and initialize this storage.
*/
- FancyStor(const Params &)
+ FancyStor(Info *info)
: sum(Counter()), squares(Counter()), samples(Counter())
{ }
@@ -1522,9 +1612,9 @@ struct FancyStor
* 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)
+ void
+ sample(Counter val, int number)
{
Counter value = val * number;
sum += value;
@@ -1532,29 +1622,31 @@ struct FancyStor
samples += number;
}
- void update(DistDataData *data, const Params &params)
- {
- 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; }
+ size_type size() 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(); }
+ bool zero() const { return samples == Counter(); }
+
+ void
+ prepare(Info *info, DistData &data)
+ {
+ data.sum = sum;
+ data.squares = squares;
+ data.samples = samples;
+ }
/**
* Reset stat value to default
*/
- void reset()
+ void
+ reset(Info *info)
{
sum = Counter();
squares = Counter();
@@ -1566,12 +1658,13 @@ struct FancyStor
* Templatized storage for distribution that calculates per tick mean and
* variance.
*/
-struct AvgFancy
+class AvgFancy
{
public:
- /** No parameters for this storage. */
- struct Params {};
- enum { fancy = true };
+ struct Params : public DistParams
+ {
+ Params() : DistParams(true) {}
+ };
private:
/** Current total. */
@@ -1583,43 +1676,49 @@ struct AvgFancy
/**
* Create and initialize this storage.
*/
- AvgFancy(const Params &) : sum(Counter()), squares(Counter()) {}
+ AvgFancy(Info *info)
+ : 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)
+ void
+ sample(Counter val, int number)
{
Counter value = val * number;
sum += value;
squares += value * value;
}
- void update(DistDataData *data, const Params &params)
- {
- 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 &params) const { return 1; }
+ size_type size() const { return 1; }
+
/**
* Return true if no samples have been added.
* @return True if the sum is zero.
*/
- bool zero(const Params &params) const { return sum == Counter(); }
+ bool zero() const { return sum == Counter(); }
+
+ void
+ prepare(Info *info, DistData &data)
+ {
+ data.sum = sum;
+ data.squares = squares;
+ data.samples = curTick;
+ }
+
/**
* Reset stat value to default
*/
- void reset()
+ void
+ reset(Info *info)
{
sum = Counter();
squares = Counter();
@@ -1630,27 +1729,25 @@ struct AvgFancy
* Implementation of a distribution stat. The type of distribution is
* determined by the Storage template. @sa ScalarBase
*/
-template <class Stor>
-class DistBase : public DataAccess
+template <class Derived, class Stor>
+class DistBase : public DataWrap<Derived, DistInfo>
{
public:
+ typedef DistInfo<Derived> Info;
typedef Stor Storage;
- /** Define the params of the storage class. */
- typedef typename Storage::Params Params;
+ typedef typename Stor::Params Params;
protected:
/** The storage for this stat. */
char storage[sizeof(Storage)] __attribute__ ((aligned (8)));
- /** The parameters for this stat. */
- Params params;
-
protected:
/**
* Retrieve the storage.
* @return The storage object for this stat.
*/
- Storage *data()
+ Storage *
+ data()
{
return reinterpret_cast<Storage *>(storage);
}
@@ -1668,8 +1765,8 @@ class DistBase : public DataAccess
void
doInit()
{
- new (storage) Storage(params);
- setInit();
+ new (storage) Storage(this->info());
+ this->setInit();
}
public:
@@ -1682,23 +1779,24 @@ class DistBase : public DataAccess
* @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); }
+ void sample(const U &v, int n = 1) { data()->sample(v, n); }
/**
* Return the number of entries in this stat.
* @return The number of entries.
*/
- size_t size() const { return data()->size(params); }
+ size_type size() const { return data()->size(); }
/**
* Return true if no samples have been added.
* @return True if there haven't been any samples.
*/
- bool zero() const { return data()->zero(params); }
+ bool zero() const { return data()->zero(); }
- void update(DistData *base)
+ void
+ prepare()
{
- base->data.fancy = Storage::fancy;
- data()->update(&(base->data), params);
+ Info *info = this->info();
+ data()->prepare(info, info->data);
}
/**
@@ -1707,48 +1805,43 @@ class DistBase : public DataAccess
void
reset()
{
- data()->reset();
- }
-
- bool
- check()
- {
- return true;
+ data()->reset(this->info());
}
};
template <class Stat>
class DistProxy;
-template <class Stor>
-class VectorDistBase : public DataAccess
+template <class Derived, class Stor>
+class VectorDistBase : public DataWrapVec<Derived, VectorDistInfo>
{
public:
+ typedef VectorDistInfo<Derived> Info;
typedef Stor Storage;
- typedef typename Storage::Params Params;
- typedef DistProxy<VectorDistBase<Storage> > Proxy;
- friend class DistProxy<VectorDistBase<Storage> >;
+ typedef typename Stor::Params Params;
+ typedef DistProxy<Derived> Proxy;
+ friend class DistProxy<Derived>;
+ friend class DataWrapVec<Derived, VectorDistInfo>;
protected:
Storage *storage;
- size_t _size;
- Params params;
+ size_type _size;
protected:
Storage *
- data(int index)
+ data(off_type index)
{
return &storage[index];
}
const Storage *
- data(int index) const
+ data(off_type index) const
{
return &storage[index];
}
void
- doInit(int s)
+ doInit(size_type s)
{
assert(s > 0 && "size must be positive!");
assert(!storage && "already initialized");
@@ -1757,10 +1850,11 @@ class VectorDistBase : public DataAccess
char *ptr = new char[_size * sizeof(Storage)];
storage = reinterpret_cast<Storage *>(ptr);
- for (int i = 0; i < _size; ++i)
- new (&storage[i]) Storage(params);
+ Info *info = this->info();
+ for (off_type i = 0; i < _size; ++i)
+ new (&storage[i]) Storage(info);
- setInit();
+ this->setInit();
}
public:
@@ -1773,14 +1867,14 @@ class VectorDistBase : public DataAccess
if (!storage)
return ;
- for (int i = 0; i < _size; ++i)
+ for (off_type i = 0; i < _size; ++i)
data(i)->~Storage();
delete [] reinterpret_cast<char *>(storage);
}
- Proxy operator[](int index);
+ Proxy operator[](off_type index);
- size_t
+ size_type
size() const
{
return _size;
@@ -1791,39 +1885,28 @@ class VectorDistBase : public DataAccess
{
return false;
#if 0
- for (int i = 0; i < size(); ++i)
- if (!data(i)->zero(params))
+ for (off_type i = 0; i < size(); ++i)
+ if (!data(i)->zero())
return false;
return true;
#endif
}
- /**
- * Reset stat value to default
- */
void
- reset()
+ prepare()
{
- for (int i = 0; i < size(); ++i)
- data(i)->reset();
+ Info *info = this->info();
+ size_type size = this->size();
+ info->data.resize(size);
+ for (off_type i = 0; i < size; ++i)
+ data(i)->prepare(info, info->data[i]);
}
bool
- check()
+ check() const
{
return storage != NULL;
}
-
- 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 Stat>
@@ -1831,14 +1914,14 @@ class DistProxy
{
private:
Stat *stat;
- int index;
+ off_type index;
protected:
typename Stat::Storage *data() { return stat->data(index); }
const typename Stat::Storage *data() const { return stat->data(index); }
public:
- DistProxy(Stat *s, int i)
+ DistProxy(Stat *s, off_type i)
: stat(s), index(i)
{}
@@ -1846,7 +1929,8 @@ class DistProxy
: stat(sp.stat), index(sp.index)
{}
- const DistProxy &operator=(const DistProxy &sp)
+ const DistProxy &
+ operator=(const DistProxy &sp)
{
stat = sp.stat;
index = sp.index;
@@ -1858,10 +1942,10 @@ class DistProxy
void
sample(const U &v, int n = 1)
{
- data()->sample(v, n, stat->params);
+ data()->sample(v, n);
}
- size_t
+ size_type
size() const
{
return 1;
@@ -1870,7 +1954,7 @@ class DistProxy
bool
zero() const
{
- return data()->zero(stat->params);
+ return data()->zero();
}
/**
@@ -1879,23 +1963,23 @@ class DistProxy
void reset() { }
};
-template <class Storage>
-inline typename VectorDistBase<Storage>::Proxy
-VectorDistBase<Storage>::operator[](int index)
+template <class Derived, class Stor>
+inline typename VectorDistBase<Derived, Stor>::Proxy
+VectorDistBase<Derived, Stor>::operator[](off_type index)
{
assert (index >= 0 && index < size());
- return typename VectorDistBase<Storage>::Proxy(this, index);
+ typedef typename VectorDistBase<Derived, Stor>::Proxy Proxy;
+ return Proxy(this, index);
}
#if 0
template <class Storage>
Result
-VectorDistBase<Storage>::total(int index) const
+VectorDistBase<Storage>::total(off_type index) const
{
- int total = 0;
- for (int i = 0; i < x_size(); ++i) {
- total += data(i)->result(stat->params);
- }
+ Result total = 0.0;
+ for (off_type i = 0; i < x_size(); ++i)
+ total += data(i)->result();
}
#endif
@@ -1916,7 +2000,7 @@ class Node : public RefCounted
* 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;
+ virtual size_type size() const = 0;
/**
* Return the result vector of this subtree.
* @return The result vector of this subtree.
@@ -1940,24 +2024,27 @@ typedef RefCountingPtr<Node> NodePtr;
class ScalarStatNode : public Node
{
private:
- const ScalarData *data;
+ const ScalarInfoBase *data;
mutable VResult vresult;
public:
- ScalarStatNode(const ScalarData *d) : data(d), vresult(1) {}
- virtual const VResult &result() const
+ ScalarStatNode(const ScalarInfoBase *d) : data(d), vresult(1) {}
+
+ const VResult &
+ result() const
{
vresult[0] = data->result();
return vresult;
}
- virtual Result total() const { return data->result(); };
- virtual size_t size() const { return 1; }
+ Result total() const { return data->result(); };
+
+ size_type size() const { return 1; }
/**
*
*/
- virtual std::string str() const { return data->name; }
+ std::string str() const { return data->name; }
};
template <class Stat>
@@ -1972,20 +2059,20 @@ class ScalarProxyNode : public Node
: proxy(p), vresult(1)
{ }
- virtual const VResult &
+ const VResult &
result() const
{
vresult[0] = proxy.result();
return vresult;
}
- virtual Result
+ Result
total() const
{
return proxy.result();
}
- virtual size_t
+ size_type
size() const
{
return 1;
@@ -1994,7 +2081,7 @@ class ScalarProxyNode : public Node
/**
*
*/
- virtual std::string
+ std::string
str() const
{
return proxy.str();
@@ -2004,16 +2091,16 @@ class ScalarProxyNode : public Node
class VectorStatNode : public Node
{
private:
- const VectorData *data;
+ const VectorInfoBase *data;
public:
- VectorStatNode(const VectorData *d) : data(d) { }
- virtual const VResult &result() const { return data->result(); }
- virtual Result total() const { return data->total(); };
+ VectorStatNode(const VectorInfoBase *d) : data(d) { }
+ const VResult &result() const { return data->result(); }
+ Result total() const { return data->total(); };
- virtual size_t size() const { return data->size(); }
+ size_type size() const { return data->size(); }
- virtual std::string str() const { return data->name; }
+ std::string str() const { return data->name; }
};
template <class T>
@@ -2025,9 +2112,9 @@ class ConstNode : public Node
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; }
- virtual std::string str() const { return to_string(vresult[0]); }
+ Result total() const { return vresult[0]; };
+ size_type size() const { return 1; }
+ std::string str() const { return to_string(vresult[0]); }
};
template <class T>
@@ -2039,25 +2126,25 @@ class ConstVectorNode : public Node
public:
ConstVectorNode(const T &s) : vresult(s.begin(), s.end()) {}
const VResult &result() const { return vresult; }
- virtual Result total() const
+
+ Result
+ total() const
{
- int size = this->size();
+ size_type size = this->size();
Result tmp = 0;
- for (int i = 0; i < size; i++)
- {
+ for (off_type i = 0; i < size; i++)
tmp += vresult[i];
- }
return tmp;
}
- virtual size_t size() const { return vresult.size(); }
- virtual std::string str() const
+
+ size_type size() const { return vresult.size(); }
+ std::string
+ str() const
{
- int size = this->size();
+ size_type size = this->size();
std::string tmp = "(";
- for (int i = 0; i < size; i++)
- {
+ for (off_type i = 0; i < size; i++)
tmp += csprintf("%s ",to_string(vresult[i]));
- }
tmp += ")";
return tmp;
}
@@ -2112,33 +2199,36 @@ class UnaryNode : public Node
public:
UnaryNode(NodePtr &p) : l(p) {}
- const VResult &result() const
+ const VResult &
+ result() const
{
const VResult &lvec = l->result();
- int size = lvec.size();
+ size_type size = lvec.size();
assert(size > 0);
vresult.resize(size);
Op op;
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult[i] = op(lvec[i]);
return vresult;
}
- Result total() const
+ Result
+ total() const
{
const VResult &vec = this->result();
- Result total = 0;
- for (int i = 0; i < size(); i++)
+ Result total = 0.0;
+ for (off_type i = 0; i < size(); i++)
total += vec[i];
return total;
}
- virtual size_t size() const { return l->size(); }
+ size_type size() const { return l->size(); }
- virtual std::string str() const
+ std::string
+ str() const
{
return OpString<Op>::str() + l->str();
}
@@ -2155,7 +2245,8 @@ class BinaryNode : public Node
public:
BinaryNode(NodePtr &a, NodePtr &b) : l(a), r(b) {}
- const VResult &result() const
+ const VResult &
+ result() const
{
Op op;
const VResult &lvec = l->result();
@@ -2167,48 +2258,52 @@ class BinaryNode : public Node
vresult.resize(1);
vresult[0] = op(lvec[0], rvec[0]);
} else if (lvec.size() == 1) {
- int size = rvec.size();
+ size_type size = rvec.size();
vresult.resize(size);
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult[i] = op(lvec[0], rvec[i]);
} else if (rvec.size() == 1) {
- int size = lvec.size();
+ size_type size = lvec.size();
vresult.resize(size);
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult[i] = op(lvec[i], rvec[0]);
} else if (rvec.size() == lvec.size()) {
- int size = rvec.size();
+ size_type size = rvec.size();
vresult.resize(size);
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult[i] = op(lvec[i], rvec[i]);
}
return vresult;
}
- Result total() const
+ Result
+ total() const
{
const VResult &vec = this->result();
- Result total = 0;
- for (int i = 0; i < size(); i++)
+ Result total = 0.0;
+ for (off_type i = 0; i < size(); i++)
total += vec[i];
return total;
}
- virtual size_t size() const {
- int ls = l->size();
- int rs = r->size();
- if (ls == 1)
+ size_type
+ size() const
+ {
+ size_type ls = l->size();
+ size_type rs = r->size();
+ if (ls == 1) {
return rs;
- else if (rs == 1)
+ } else if (rs == 1) {
return ls;
- else {
+ } else {
assert(ls == rs && "Node vector sizes are not equal");
return ls;
}
}
- virtual std::string str() const
+ std::string
+ str() const
{
return csprintf("(%s %s %s)", l->str(), OpString<Op>::str(), r->str());
}
@@ -2224,39 +2319,42 @@ class SumNode : public Node
public:
SumNode(NodePtr &p) : l(p), vresult(1) {}
- const VResult &result() const
+ const VResult &
+ result() const
{
const VResult &lvec = l->result();
- int size = lvec.size();
+ size_type size = lvec.size();
assert(size > 0);
vresult[0] = 0.0;
Op op;
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult[0] = op(vresult[0], lvec[i]);
return vresult;
}
- Result total() const
+ Result
+ total() const
{
const VResult &lvec = l->result();
- int size = lvec.size();
+ size_type size = lvec.size();
assert(size > 0);
Result vresult = 0.0;
Op op;
- for (int i = 0; i < size; ++i)
+ for (off_type i = 0; i < size; ++i)
vresult = op(vresult, lvec[i]);
return vresult;
}
- virtual size_t size() const { return 1; }
+ size_type size() const { return 1; }
- virtual std::string str() const
+ std::string
+ str() const
{
return csprintf("total(%s)", l->str());
}
@@ -2278,145 +2376,57 @@ class SumNode : public Node
* This is a simple scalar statistic, like a counter.
* @sa Stat, ScalarBase, StatStor
*/
-template<int N = 0>
-class Scalar : public Wrap<Scalar<N>, ScalarBase<StatStor>, ScalarStatData>
+class Scalar : public ScalarBase<Scalar, StatStor>
{
public:
- /** The base implementation. */
- typedef ScalarBase<StatStor> Base;
-
- Scalar()
- {
- this->doInit();
- }
-
- /**
- * 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;
- }
+ using ScalarBase<Scalar, StatStor>::operator=;
};
/**
* A stat that calculates the per tick average of a value.
* @sa Stat, ScalarBase, AvgStor
*/
-template<int N = 0>
-class Average : public Wrap<Average<N>, ScalarBase<AvgStor>, ScalarStatData>
+class Average : public ScalarBase<Average, AvgStor>
{
public:
- /** The base implementation. */
- typedef ScalarBase<AvgStor> Base;
-
- Average()
- {
- this->doInit();
- }
+ using ScalarBase<Average, AvgStor>::operator=;
+};
- /**
- * 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 ValueBase<Value>
+{
};
/**
* A vector of scalar stats.
* @sa Stat, VectorBase, StatStor
*/
-template<int N = 0>
-class Vector : public WrapVec<Vector<N>, VectorBase<StatStor>, VectorStatData>
+class Vector : public VectorBase<Vector, StatStor>
{
- public:
- /** The base implementation. */
- typedef ScalarBase<StatStor> 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->doInit(size);
- return *this;
- }
};
/**
* A vector of Average stats.
* @sa Stat, VectorBase, AvgStor
*/
-template<int N = 0>
-class AverageVector
- : public WrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorStatData>
+class AverageVector : public VectorBase<AverageVector, AvgStor>
{
- 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->doInit(size);
- return *this;
- }
};
/**
* A 2-Dimensional vecto of scalar stats.
* @sa Stat, Vector2dBase, StatStor
*/
-template<int N = 0>
-class Vector2d
- : public WrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dStatData>
+class Vector2d : public Vector2dBase<Vector2d, StatStor>
{
- public:
- Vector2d &init(size_t x, size_t y) {
- this->doInit(x, y);
- return *this;
- }
};
/**
* A simple distribution stat.
* @sa Stat, DistBase, DistStor
*/
-template<int N = 0>
-class Distribution
- : public Wrap<Distribution<N>, DistBase<DistStor>, DistStatData>
+class Distribution : public DistBase<Distribution, DistStor>
{
public:
- /** Base implementation. */
- typedef DistBase<DistStor> Base;
- /** The Parameter type. */
- typedef DistStor::Params Params;
-
- public:
/**
* Set the parameters of this distribution. @sa DistStor::Params
* @param min The minimum value of the distribution.
@@ -2424,13 +2434,17 @@ class 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);
+ Distribution &
+ init(Counter min, Counter max, Counter bkt)
+ {
+ DistStor::Params *params = new DistStor::Params;
+ params->min = min;
+ params->max = max;
+ params->bucket_size = bkt;
+ params->buckets = (size_type)rint((max - min) / bkt + 1.0);
+ this->setParams(params);
this->doInit();
- return *this;
+ return this->self();
}
};
@@ -2438,21 +2452,14 @@ class Distribution
* Calculates the mean and variance of all the samples.
* @sa Stat, DistBase, FancyStor
*/
-template<int N = 0>
-class StandardDeviation
- : public Wrap<StandardDeviation<N>, DistBase<FancyStor>, DistStatData>
+class StandardDeviation : public DistBase<StandardDeviation, FancyStor>
{
public:
- /** The base implementation */
- typedef DistBase<DistStor> Base;
- /** The parameter type. */
- typedef DistStor::Params Params;
-
- public:
/**
* Construct and initialize this distribution.
*/
- StandardDeviation() {
+ StandardDeviation()
+ {
this->doInit();
}
};
@@ -2461,17 +2468,9 @@ class StandardDeviation
* Calculates the per tick mean and variance of the samples.
* @sa Stat, DistBase, AvgFancy
*/
-template<int N = 0>
-class AverageDeviation
- : public Wrap<AverageDeviation<N>, DistBase<AvgFancy>, DistStatData>
+class AverageDeviation : public DistBase<AverageDeviation, AvgFancy>
{
public:
- /** The base implementation */
- typedef DistBase<DistStor> Base;
- /** The parameter type. */
- typedef DistStor::Params Params;
-
- public:
/**
* Construct and initialize this distribution.
*/
@@ -2485,19 +2484,9 @@ class AverageDeviation
* A vector of distributions.
* @sa Stat, VectorDistBase, DistStor
*/
-template<int N = 0>
-class VectorDistribution
- : public WrapVec<VectorDistribution<N>,
- VectorDistBase<DistStor>,
- VectorDistStatData>
+class VectorDistribution : public VectorDistBase<VectorDistribution, DistStor>
{
public:
- /** The base implementation */
- typedef VectorDistBase<DistStor> Base;
- /** The parameter type. */
- typedef DistStor::Params Params;
-
- public:
/**
* Initialize storage and parameters for this distribution.
* @param size The size of the vector (the number of distributions).
@@ -2506,13 +2495,17 @@ class VectorDistribution
* @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);
+ VectorDistribution &
+ init(size_type size, Counter min, Counter max, Counter bkt)
+ {
+ DistStor::Params *params = new DistStor::Params;
+ params->min = min;
+ params->max = max;
+ params->bucket_size = bkt;
+ params->buckets = (size_type)rint((max - min) / bkt + 1.0);
+ this->setParams(params);
this->doInit(size);
- return *this;
+ return this->self();
}
};
@@ -2520,27 +2513,20 @@ class VectorDistribution
* This is a vector of StandardDeviation stats.
* @sa Stat, VectorDistBase, FancyStor
*/
-template<int N = 0>
class VectorStandardDeviation
- : public WrapVec<VectorStandardDeviation<N>,
- VectorDistBase<FancyStor>,
- VectorDistStatData>
+ : public VectorDistBase<VectorStandardDeviation, FancyStor>
{
public:
- /** The base implementation */
- typedef VectorDistBase<FancyStor> Base;
- /** The parameter type. */
- typedef 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) {
+ VectorStandardDeviation &
+ init(size_type size)
+ {
this->doInit(size);
- return *this;
+ return this->self();
}
};
@@ -2548,36 +2534,60 @@ class VectorStandardDeviation
* This is a vector of AverageDeviation stats.
* @sa Stat, VectorDistBase, AvgFancy
*/
-template<int N = 0>
class VectorAverageDeviation
- : public WrapVec<VectorAverageDeviation<N>,
- VectorDistBase<AvgFancy>,
- VectorDistStatData>
+ : public VectorDistBase<VectorAverageDeviation, AvgFancy>
{
public:
- /** The base implementation */
- typedef VectorDistBase<AvgFancy> Base;
- /** The parameter type. */
- typedef 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) {
+ VectorAverageDeviation &
+ init(size_type size)
+ {
this->doInit(size);
- return *this;
+ return this->self();
+ }
+};
+
+class FormulaInfoBase : public VectorInfoBase
+{
+ public:
+ virtual std::string str() const = 0;
+};
+
+template <class Stat>
+class FormulaInfo : public InfoWrap<Stat, FormulaInfoBase>
+{
+ protected:
+ mutable VResult vec;
+ mutable VCounter cvec;
+
+ public:
+ FormulaInfo(Stat &stat) : InfoWrap<Stat, FormulaInfoBase>(stat) {}
+
+ size_type size() const { return this->s.size(); }
+
+ const VResult &
+ result() const
+ {
+ this->s.result(vec);
+ return vec;
}
+ Result total() const { return this->s.total(); }
+ VCounter &value() const { return cvec; }
+
+ std::string str() const { return this->s.str(); }
};
+class Temp;
/**
* 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
+class Formula : public DataWrapVec<Formula, FormulaInfo>
{
protected:
/** The root of the tree which represents the Formula */
@@ -2586,6 +2596,31 @@ class FormulaBase : public DataAccess
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);
+ /**
* 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
@@ -2609,9 +2644,9 @@ class FormulaBase : public DataAccess
/**
* Return the number of elements in the tree.
*/
- size_t size() const;
+ size_type size() const;
- bool check() const { return true; }
+ void prepare() { }
/**
* Formulas don't need to be reset
@@ -2623,86 +2658,9 @@ class FormulaBase : public DataAccess
*/
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 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:
@@ -2712,11 +2670,11 @@ class FormulaNode : public Node
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(); }
+ size_type size() const { return formula.size(); }
+ const VResult &result() const { formula.result(vec); return vec; }
+ Result total() const { return formula.total(); }
- virtual std::string str() const { return formula.str(); }
+ std::string str() const { return formula.str(); }
};
/**
@@ -2741,45 +2699,47 @@ class Temp
* Return the node pointer.
* @return the node pointer.
*/
- operator NodePtr&() { return node;}
+ operator NodePtr&() { return node; }
public:
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
- template <int N>
- Temp(const Scalar<N> &s)
- : node(new ScalarStatNode(s.statData())) { }
+ Temp(const Scalar &s)
+ : node(new ScalarStatNode(s.info()))
+ { }
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
Temp(const Value &s)
- : node(new ScalarStatNode(s.statData())) { }
+ : node(new ScalarStatNode(s.info()))
+ { }
/**
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
- template <int N>
- Temp(const Average<N> &s)
- : node(new ScalarStatNode(s.statData())) { }
+ Temp(const Average &s)
+ : node(new ScalarStatNode(s.info()))
+ { }
/**
* Create a new VectorStatNode.
* @param s The VectorStat to place in a node.
*/
- template <int N>
- Temp(const Vector<N> &s)
- : node(new VectorStatNode(s.statData())) { }
+ Temp(const Vector &s)
+ : node(new VectorStatNode(s.info()))
+ { }
/**
*
*/
Temp(const Formula &f)
- : node(new FormulaNode(f)) { }
+ : node(new FormulaNode(f))
+ { }
/**
* Create a new ScalarProxyNode.
@@ -2787,91 +2747,104 @@ class Temp
*/
template <class Stat>
Temp(const ScalarProxy<Stat> &p)
- : node(new ScalarProxyNode<Stat>(p)) { }
+ : node(new ScalarProxyNode<Stat>(p))
+ { }
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(signed char value)
- : node(new ConstNode<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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : 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)) {}
+ : node(new ConstNode<float>(value))
+ { }
/**
* Create a ConstNode
* @param value The value of the const node.
*/
Temp(double value)
- : node(new ConstNode<double>(value)) {}
+ : node(new ConstNode<double>(value))
+ { }
};
@@ -2879,11 +2852,6 @@ class Temp
* @}
*/
-void check();
-void dump();
-void reset();
-void registerResetCallback(Callback *cb);
-
inline Temp
operator+(Temp l, Temp r)
{
@@ -2934,6 +2902,36 @@ sum(Temp val)
return NodePtr(new SumNode<std::plus<Result> >(val));
}
+/**
+ * Enable the statistics package. Before the statistics package is
+ * enabled, all statistics must be created and initialized and once
+ * the package is enabled, no more statistics can be created.
+ */
+void enable();
+
+/**
+ * Prepare all stats for data access. This must be done before
+ * dumping and serialization.
+ */
+void prepare();
+
+/**
+ * Dump all statistics data to the registered outputs
+ */
+void dump();
+
+/**
+ * Reset all statistics to the base state
+ */
+void reset();
+/**
+ * Register a callback that should be called whenever statistics are
+ * reset
+ */
+void registerResetCallback(Callback *cb);
+
+std::list<Info *> &statsList();
+
/* namespace Stats */ }
#endif // __BASE_STATISTICS_HH__
diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc
index dc56fe75f..dcf52e6d8 100644
--- a/src/base/stats/events.cc
+++ b/src/base/stats/events.cc
@@ -38,7 +38,7 @@ using namespace std;
namespace Stats {
-Tick EventStart = ULL(0x7fffffffffffffff);
+Tick EventStart = MaxTick;
extern list<Output *> OutputList;
diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh
index 69f73f66a..77eedaee8 100644
--- a/src/base/stats/flags.hh
+++ b/src/base/stats/flags.hh
@@ -30,6 +30,7 @@
#ifndef __BASE_STATS_FLAGS_HH__
#define __BASE_STATS_FLAGS_HH__
+
namespace Stats {
/**
@@ -39,28 +40,28 @@ namespace Stats {
typedef uint32_t StatFlags;
/** Nothing extra to print. */
-const StatFlags none = 0x00000000;
+const StatFlags none = 0x00000000;
/** This Stat is Initialized */
-const StatFlags init = 0x00000001;
+const StatFlags init = 0x00000001;
/** Print this stat. */
-const StatFlags print = 0x00000002;
+const StatFlags print = 0x00000002;
/** Print the total. */
-const StatFlags total = 0x00000010;
+const StatFlags total = 0x00000010;
/** Print the percent of the total that this entry represents. */
-const StatFlags pdf = 0x00000020;
+const StatFlags pdf = 0x00000020;
/** Print the cumulative percentage of total upto this entry. */
-const StatFlags cdf = 0x00000040;
+const StatFlags cdf = 0x00000040;
/** Print the distribution. */
-const StatFlags dist = 0x00000080;
+const StatFlags dist = 0x00000080;
/** Don't print if this is zero. */
-const StatFlags nozero = 0x00000100;
+const StatFlags nozero = 0x00000100;
/** Don't print if this is NAN */
-const StatFlags nonan = 0x00000200;
+const StatFlags nonan = 0x00000200;
/** Used for SS compatability. */
-const StatFlags __substat = 0x80000000;
+const StatFlags __substat = 0x80000000;
/** Mask of flags that can't be set directly */
-const StatFlags __reserved = init | print | __substat;
+const StatFlags __reserved = init | print | __substat;
enum DisplayMode
{
diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc
index 39a687fff..1e0c923f1 100644
--- a/src/base/stats/mysql.cc
+++ b/src/base/stats/mysql.cc
@@ -40,7 +40,6 @@
#include "base/stats/flags.hh"
#include "base/stats/mysql.hh"
#include "base/stats/mysql_run.hh"
-#include "base/stats/statdb.hh"
#include "base/stats/types.hh"
#include "base/str.hh"
#include "base/userinfo.hh"
@@ -458,7 +457,7 @@ InsertSubData::setup(MySqlRun *run)
mysql.query(insert);
// if (mysql.error)
-// panic("could not insert subdata\n%s\n", mysql.error);
+// panic("could not insert subdata\n%s\n", mysql.error);
if (mysql.commit())
panic("could not commit transaction\n%s\n", mysql.error);
@@ -493,21 +492,19 @@ MySql::configure()
/*
* set up all stats!
*/
- using namespace Database;
-
MySQL::Connection &mysql = run->conn();
- stat_list_t::const_iterator i, end = stats().end();
- for (i = stats().begin(); i != end; ++i) {
+ list<Info *>::const_iterator i, end = statsList().end();
+ for (i = statsList().begin(); i != end; ++i) {
(*i)->visit(*this);
}
- for (i = stats().begin(); i != end; ++i) {
- StatData *data = *i;
- if (data->prereq) {
+ for (i = statsList().begin(); i != end; ++i) {
+ Info *info = *i;
+ if (info->prereq) {
// update the prerequisite
- uint16_t stat_id = find(data->id);
- uint16_t prereq_id = find(data->prereq->id);
+ uint16_t stat_id = find(info->id);
+ uint16_t prereq_id = find(info->prereq->id);
assert(stat_id && prereq_id);
stringstream update;
@@ -528,153 +525,156 @@ MySql::configure()
configured = true;
}
-
bool
-MySql::configure(const StatData &data, string type)
+MySql::configure(const Info &info, string type)
{
stat.init();
- stat.name = data.name;
- stat.descr = data.desc;
+ stat.name = info.name;
+ stat.descr = info.desc;
stat.type = type;
- stat.print = data.flags & print;
- stat.prec = data.precision;
- stat.nozero = data.flags & nozero;
- stat.nonan = data.flags & nonan;
- stat.total = data.flags & total;
- stat.pdf = data.flags & pdf;
- stat.cdf = data.flags & cdf;
+ stat.print = info.flags & print;
+ stat.prec = info.precision;
+ stat.nozero = info.flags & nozero;
+ stat.nonan = info.flags & nonan;
+ stat.total = info.flags & total;
+ stat.pdf = info.flags & pdf;
+ stat.cdf = info.flags & cdf;
return stat.print;
}
void
-MySql::configure(const ScalarData &data)
+MySql::configure(const ScalarInfoBase &info)
{
- if (!configure(data, "SCALAR"))
+ if (!configure(info, "SCALAR"))
return;
- insert(data.id, stat.setup(run));
+ insert(info.id, stat.setup(run));
}
void
-MySql::configure(const VectorData &data)
+MySql::configure(const VectorInfoBase &info)
{
- if (!configure(data, "VECTOR"))
+ if (!configure(info, "VECTOR"))
return;
uint16_t statid = stat.setup(run);
- if (!data.subnames.empty()) {
+ if (!info.subnames.empty()) {
InsertSubData subdata;
subdata.stat = statid;
subdata.y = 0;
- for (int i = 0; i < data.subnames.size(); ++i) {
+ for (off_type i = 0; i < info.subnames.size(); ++i) {
subdata.x = i;
- subdata.name = data.subnames[i];
- subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ subdata.name = info.subnames[i];
+ subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i];
if (!subdata.name.empty() || !subdata.descr.empty())
subdata.setup(run);
}
}
- insert(data.id, statid);
+ insert(info.id, statid);
}
void
-MySql::configure(const DistData &data)
+MySql::configure(const DistInfoBase &info)
{
- if (!configure(data, "DIST"))
+ if (!configure(info, "DIST"))
return;
- if (!data.data.fancy) {
- stat.size = data.data.size;
- stat.min = data.data.min;
- stat.max = data.data.max;
- stat.bktsize = data.data.bucket_size;
+ const DistParams *params =
+ safe_cast<const DistParams *>(info.storageParams);
+ if (!params->fancy) {
+ stat.size = params->buckets;
+ stat.min = params->min;
+ stat.max = params->max;
+ stat.bktsize = params->bucket_size;
}
- insert(data.id, stat.setup(run));
+ insert(info.id, stat.setup(run));
}
void
-MySql::configure(const VectorDistData &data)
+MySql::configure(const VectorDistInfoBase &info)
{
- if (!configure(data, "VECTORDIST"))
+ if (!configure(info, "VECTORDIST"))
return;
- if (!data.data[0].fancy) {
- stat.size = data.data[0].size;
- stat.min = data.data[0].min;
- stat.max = data.data[0].max;
- stat.bktsize = data.data[0].bucket_size;
+ const DistParams *params =
+ safe_cast<const DistParams *>(info.storageParams);
+ if (!params->fancy) {
+ stat.size = params->buckets;
+ stat.min = params->min;
+ stat.max = params->max;
+ stat.bktsize = params->bucket_size;
}
uint16_t statid = stat.setup(run);
- if (!data.subnames.empty()) {
+ if (!info.subnames.empty()) {
InsertSubData subdata;
subdata.stat = statid;
subdata.y = 0;
- for (int i = 0; i < data.subnames.size(); ++i) {
+ for (off_type i = 0; i < info.subnames.size(); ++i) {
subdata.x = i;
- subdata.name = data.subnames[i];
- subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ subdata.name = info.subnames[i];
+ subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i];
if (!subdata.name.empty() || !subdata.descr.empty())
subdata.setup(run);
}
}
- insert(data.id, statid);
+ insert(info.id, statid);
}
void
-MySql::configure(const Vector2dData &data)
+MySql::configure(const Vector2dInfoBase &info)
{
- if (!configure(data, "VECTOR2D"))
+ if (!configure(info, "VECTOR2D"))
return;
uint16_t statid = stat.setup(run);
- if (!data.subnames.empty()) {
+ if (!info.subnames.empty()) {
InsertSubData subdata;
subdata.stat = statid;
subdata.y = -1;
- for (int i = 0; i < data.subnames.size(); ++i) {
+ for (off_type i = 0; i < info.subnames.size(); ++i) {
subdata.x = i;
- subdata.name = data.subnames[i];
- subdata.descr = data.subdescs.empty() ? "" : data.subdescs[i];
+ subdata.name = info.subnames[i];
+ subdata.descr = info.subdescs.empty() ? "" : info.subdescs[i];
if (!subdata.name.empty() || !subdata.descr.empty())
subdata.setup(run);
}
}
- if (!data.y_subnames.empty()) {
+ if (!info.y_subnames.empty()) {
InsertSubData subdata;
subdata.stat = statid;
subdata.x = -1;
subdata.descr = "";
- for (int i = 0; i < data.y_subnames.size(); ++i) {
+ for (off_type i = 0; i < info.y_subnames.size(); ++i) {
subdata.y = i;
- subdata.name = data.y_subnames[i];
+ subdata.name = info.y_subnames[i];
if (!subdata.name.empty())
subdata.setup(run);
}
}
- insert(data.id, statid);
+ insert(info.id, statid);
}
void
-MySql::configure(const FormulaData &data)
+MySql::configure(const FormulaInfoBase &info)
{
MySQL::Connection &mysql = run->conn();
assert(mysql.connected());
- configure(data, "FORMULA");
- insert(data.id, stat.setup(run));
+ configure(info, "FORMULA");
+ insert(info.id, stat.setup(run));
- uint16_t stat = find(data.id);
- string formula = data.str();
+ uint16_t stat = find(info.id);
+ string formula = info.str();
stringstream insert_formula;
ccprintf(insert_formula,
@@ -683,7 +683,7 @@ MySql::configure(const FormulaData &data)
mysql.query(insert_formula);
// if (mysql.error)
-// panic("could not insert formula\n%s\n", mysql.error);
+// panic("could not insert formula\n%s\n", mysql.error);
stringstream insert_ref;
ccprintf(insert_ref,
@@ -692,7 +692,7 @@ MySql::configure(const FormulaData &data)
mysql.query(insert_ref);
// if (mysql.error)
-// panic("could not insert formula reference\n%s\n", mysql.error);
+// panic("could not insert formula reference\n%s\n", mysql.error);
if (mysql.commit())
panic("could not commit transaction\n%s\n", mysql.error);
@@ -707,7 +707,6 @@ MySql::valid() const
void
MySql::output()
{
- using namespace Database;
assert(valid());
if (!configured)
@@ -718,9 +717,9 @@ MySql::output()
MySQL::Connection &mysql = run->conn();
- Database::stat_list_t::const_iterator i, end = Database::stats().end();
- for (i = Database::stats().begin(); i != end; ++i) {
- StatData *stat = *i;
+ list<Info *>::const_iterator i, end = statsList().end();
+ for (i = statsList().begin(); i != end; ++i) {
+ Info *stat = *i;
stat->visit(*this);
if (mysql.commit())
panic("could not commit transaction\n%s\n", mysql.error);
@@ -735,33 +734,32 @@ MySql::event(const std::string &event)
newevent.insert(event);
}
-
void
-MySql::output(const ScalarData &data)
+MySql::output(const ScalarInfoBase &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return;
- newdata.stat = find(data.id);
+ newdata.stat = find(info.id);
newdata.x = 0;
newdata.y = 0;
- newdata.data = data.value();
+ newdata.data = info.value();
newdata.insert();
}
void
-MySql::output(const VectorData &data)
+MySql::output(const VectorInfoBase &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return;
- newdata.stat = find(data.id);
+ newdata.stat = find(info.id);
newdata.y = 0;
- const VCounter &cvec = data.value();
- int size = data.size();
- for (int x = 0; x < size; x++) {
+ const VCounter &cvec = info.value();
+ size_type size = info.size();
+ for (off_type x = 0; x < size; x++) {
newdata.x = x;
newdata.data = cvec[x];
newdata.insert();
@@ -769,7 +767,7 @@ MySql::output(const VectorData &data)
}
void
-MySql::output(const DistDataData &data)
+MySql::output(const DistData &data, const DistParams *params)
{
const int db_sum = -1;
const int db_squares = -2;
@@ -791,7 +789,7 @@ MySql::output(const DistDataData &data)
newdata.data = data.samples;
newdata.insert();
- if (data.samples && !data.fancy) {
+ if (data.samples && !params->fancy) {
newdata.x = db_min_val;
newdata.data = data.min_val;
newdata.insert();
@@ -808,8 +806,8 @@ MySql::output(const DistDataData &data)
newdata.data = data.overflow;
newdata.insert();
- int size = data.cvec.size();
- for (int x = 0; x < size; x++) {
+ size_type size = data.cvec.size();
+ for (off_type x = 0; x < size; x++) {
newdata.x = x;
newdata.data = data.cvec[x];
newdata.insert();
@@ -817,54 +815,54 @@ MySql::output(const DistDataData &data)
}
}
-
void
-MySql::output(const DistData &data)
+MySql::output(const DistInfoBase &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return;
- newdata.stat = find(data.id);
+ newdata.stat = find(info.id);
newdata.y = 0;
- output(data.data);
+ output(info.data, safe_cast<const DistParams *>(info.storageParams));
}
void
-MySql::output(const VectorDistData &data)
+MySql::output(const VectorDistInfoBase &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return;
- newdata.stat = find(data.id);
+ newdata.stat = find(info.id);
- int size = data.data.size();
- for (int y = 0; y < size; ++y) {
+ size_type size = info.data.size();
+ for (off_type y = 0; y < size; ++y) {
newdata.y = y;
- output(data.data[y]);
+ output(info.data[y],
+ safe_cast<const DistParams *>(info.storageParams));
}
}
void
-MySql::output(const Vector2dData &data)
+MySql::output(const Vector2dInfoBase &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return;
- newdata.stat = find(data.id);
+ newdata.stat = find(info.id);
- int index = 0;
- for (int x = 0; x < data.x; x++) {
+ off_type index = 0;
+ for (off_type x = 0; x < info.x; x++) {
newdata.x = x;
- for (int y = 0; y < data.y; y++) {
+ for (off_type y = 0; y < info.y; y++) {
newdata.y = y;
- newdata.data = data.cvec[index++];
+ newdata.data = info.cvec[index++];
newdata.insert();
}
}
}
void
-MySql::output(const FormulaData &data)
+MySql::output(const FormulaInfoBase &info)
{
}
@@ -872,65 +870,65 @@ MySql::output(const FormulaData &data)
* Implement the visitor
*/
void
-MySql::visit(const ScalarData &data)
+MySql::visit(const ScalarInfoBase &info)
{
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
void
-MySql::visit(const VectorData &data)
+MySql::visit(const VectorInfoBase &info)
{
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
void
-MySql::visit(const DistData &data)
+MySql::visit(const DistInfoBase &info)
{
return;
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
void
-MySql::visit(const VectorDistData &data)
+MySql::visit(const VectorDistInfoBase &info)
{
return;
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
void
-MySql::visit(const Vector2dData &data)
+MySql::visit(const Vector2dInfoBase &info)
{
return;
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
void
-MySql::visit(const FormulaData &data)
+MySql::visit(const FormulaInfoBase &info)
{
if (!configured)
- configure(data);
+ configure(info);
else
- output(data);
+ output(info);
}
bool
initMySQL(string host, string user, string password, string database,
- string project, string name, string sample)
+ string project, string name, string sample)
{
extern list<Output *> OutputList;
static MySql mysql;
diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh
index 0ce381c2f..86a4d6d23 100644
--- a/src/base/stats/mysql.hh
+++ b/src/base/stats/mysql.hh
@@ -40,7 +40,7 @@
namespace MySQL { class Connection; }
namespace Stats {
-class DistDataData;
+class DistInfoBase;
class MySqlRun;
struct SetupStat
@@ -56,6 +56,7 @@ struct SetupStat
bool total;
bool pdf;
bool cdf;
+
double min;
double max;
double bktsize;
@@ -69,9 +70,9 @@ class InsertData
{
private:
char *query;
- int size;
+ size_type size;
bool first;
- static const int maxsize = 1024*1024;
+ static const size_type maxsize = 1024*1024;
public:
MySqlRun *run;
@@ -95,9 +96,9 @@ class InsertEvent
{
private:
char *query;
- int size;
+ size_type size;
bool first;
- static const int maxsize = 1024*1024;
+ static const size_type maxsize = 1024*1024;
typedef std::map<std::string, uint32_t> event_map_t;
event_map_t events;
@@ -121,19 +122,21 @@ class MySql : public Output
SetupStat stat;
InsertData newdata;
InsertEvent newevent;
- std::list<FormulaData *> formulas;
+ std::list<FormulaInfoBase *> formulas;
bool configured;
protected:
std::map<int, int> idmap;
- void insert(int sim_id, int db_id)
+ void
+ insert(int sim_id, int db_id)
{
using namespace std;
idmap.insert(make_pair(sim_id, db_id));
}
- int find(int sim_id)
+ int
+ find(int sim_id)
{
using namespace std;
map<int,int>::const_iterator i = idmap.find(sim_id);
@@ -146,19 +149,19 @@ class MySql : public Output
~MySql();
void connect(const std::string &host, const std::string &user,
- const std::string &passwd, const std::string &db,
- const std::string &name, const std::string &sample,
- const std::string &project);
+ const std::string &passwd, const std::string &db,
+ const std::string &name, const std::string &sample,
+ const std::string &project);
bool connected() const;
public:
// Implement Visit
- virtual void visit(const ScalarData &data);
- virtual void visit(const VectorData &data);
- virtual void visit(const DistData &data);
- virtual void visit(const VectorDistData &data);
- virtual void visit(const Vector2dData &data);
- virtual void visit(const FormulaData &data);
+ virtual void visit(const ScalarInfoBase &info);
+ virtual void visit(const VectorInfoBase &info);
+ virtual void visit(const DistInfoBase &info);
+ virtual void visit(const VectorDistInfoBase &info);
+ virtual void visit(const Vector2dInfoBase &info);
+ virtual void visit(const FormulaInfoBase &info);
// Implement Output
virtual bool valid() const;
@@ -169,33 +172,33 @@ class MySql : public Output
protected:
// Output helper
- void output(const DistDataData &data);
- void output(const ScalarData &data);
- void output(const VectorData &data);
- void output(const DistData &data);
- void output(const VectorDistData &data);
- void output(const Vector2dData &data);
- void output(const FormulaData &data);
+ void output(const ScalarInfoBase &info);
+ void output(const VectorInfoBase &info);
+ void output(const DistInfoBase &info);
+ void output(const VectorDistInfoBase &info);
+ void output(const Vector2dInfoBase &info);
+ void output(const FormulaInfoBase &info);
+ void output(const DistData &data, const DistParams *params);
void configure();
- bool configure(const StatData &data, std::string type);
- void configure(const ScalarData &data);
- void configure(const VectorData &data);
- void configure(const DistData &data);
- void configure(const VectorDistData &data);
- void configure(const Vector2dData &data);
- void configure(const FormulaData &data);
+ bool configure(const Info &info, std::string type);
+ void configure(const ScalarInfoBase &info);
+ void configure(const VectorInfoBase &info);
+ void configure(const DistInfoBase &info);
+ void configure(const VectorDistInfoBase &info);
+ void configure(const Vector2dInfoBase &info);
+ void configure(const FormulaInfoBase &info);
};
bool initMySQL(std::string host, std::string database, std::string user,
- std::string passwd, std::string project, std::string name,
- std::string sample);
+ std::string passwd, std::string project, std::string name,
+ std::string sample);
#if !USE_MYSQL
inline bool
initMySQL(std::string host, std::string user, std::string password,
- std::string database, std::string project, std::string name,
- std::string sample)
+ std::string database, std::string project, std::string name,
+ std::string sample)
{
return false;
}
diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh
index 487224551..7c606370e 100644
--- a/src/base/stats/mysql_run.hh
+++ b/src/base/stats/mysql_run.hh
@@ -46,7 +46,7 @@ struct MySqlRun
protected:
void setup(const std::string &name, const std::string &sample,
- const std::string &user, const std::string &project);
+ const std::string &user, const std::string &project);
void remove(const std::string &name);
void cleanup();
@@ -54,9 +54,9 @@ struct MySqlRun
public:
bool connected() const { return mysql.connected(); }
void connect(const std::string &host, const std::string &user,
- const std::string &passwd, const std::string &db,
- const std::string &name, const std::string &sample,
- const std::string &project);
+ const std::string &passwd, const std::string &db,
+ const std::string &name, const std::string &sample,
+ const std::string &project);
MySQL::Connection &conn() { return mysql; }
uint16_t run() const { return run_id; }
diff --git a/src/base/stats/output.cc b/src/base/stats/output.cc
index 9f2b91c77..31aa21c45 100644
--- a/src/base/stats/output.cc
+++ b/src/base/stats/output.cc
@@ -30,6 +30,7 @@
#include <list>
+#include "base/statistics.hh"
#include "base/stats/output.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"
@@ -49,6 +50,8 @@ dump()
return;
lastDump = curTick;
+ prepare();
+
list<Output *>::iterator i = OutputList.begin();
list<Output *>::iterator end = OutputList.end();
for (; i != end; ++i) {
diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc
index a018c4837..c3e484cf4 100644
--- a/src/base/stats/text.cc
+++ b/src/base/stats/text.cc
@@ -43,7 +43,6 @@
#include "base/misc.hh"
#include "base/statistics.hh"
-#include "base/stats/statdb.hh"
#include "base/stats/text.hh"
#include "base/stats/visit.hh"
@@ -107,7 +106,8 @@ Text::open(std::ostream &_stream)
mystream = false;
stream = &_stream;
- assert(valid());
+ if (!valid())
+ fatal("Unable to open output stream for writing\n");
}
void
@@ -118,35 +118,34 @@ Text::open(const std::string &file)
mystream = true;
stream = new ofstream(file.c_str(), ios::trunc);
- assert(valid());
+ if (!valid())
+ fatal("Unable to open statistics file for writing\n");
}
bool
Text::valid() const
{
- return stream != NULL;
+ return stream != NULL && stream->good();
}
void
Text::output()
{
- using namespace Database;
-
ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
- stat_list_t::const_iterator i, end = stats().end();
- for (i = stats().begin(); i != end; ++i)
+ list<Info *>::const_iterator i, end = statsList().end();
+ for (i = statsList().begin(); i != end; ++i)
(*i)->visit(*this);
ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n");
stream->flush();
}
bool
-Text::noOutput(const StatData &data)
+Text::noOutput(const Info &info)
{
- if (!(data.flags & print))
+ if (!(info.flags & print))
return true;
- if (data.prereq && data.prereq->zero())
+ if (info.prereq && info.prereq->zero())
return true;
return false;
@@ -191,8 +190,8 @@ struct ScalarPrint
void
ScalarPrint::operator()(ostream &stream) const
{
- if (flags & nozero && value == 0.0 ||
- flags & nonan && isnan(value))
+ if ((flags & nozero && value == 0.0) ||
+ (flags & nonan && isnan(value)))
return;
stringstream pdfstr, cdfstr;
@@ -237,11 +236,11 @@ struct VectorPrint
void
VectorPrint::operator()(std::ostream &stream) const
{
- int _size = vec.size();
+ size_type _size = vec.size();
Result _total = 0.0;
if (flags & (pdf | cdf)) {
- for (int i = 0; i < _size; ++i) {
+ for (off_type i = 0; i < _size; ++i) {
_total += vec[i];
}
}
@@ -264,7 +263,7 @@ VectorPrint::operator()(std::ostream &stream) const
print.value = vec[0];
print(stream);
} else if (!compat) {
- for (int i = 0; i < _size; ++i) {
+ for (off_type i = 0; i < _size; ++i) {
if (havesub && (i >= subnames.size() || subnames[i].empty()))
continue;
@@ -296,7 +295,7 @@ VectorPrint::operator()(std::ostream &stream) const
Result _cdf = 0.0;
if (flags & dist) {
ccprintf(stream, "%s.start_dist\n", name);
- for (int i = 0; i < _size; ++i) {
+ for (off_type i = 0; i < _size; ++i) {
print.name = havesub ? subnames[i] : to_string(i);
print.desc = subdescs.empty() ? desc : subdescs[i];
print.flags |= __substat;
@@ -316,7 +315,7 @@ VectorPrint::operator()(std::ostream &stream) const
}
ccprintf(stream, "%s.end_dist\n", name);
} else {
- for (int i = 0; i < _size; ++i) {
+ for (off_type i = 0; i < _size; ++i) {
if (havesub && subnames[i].empty())
continue;
@@ -352,27 +351,63 @@ struct DistPrint
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;
+ size_type size;
bool fancy;
+ const DistData &data;
+
+ DistPrint(const DistInfoBase &info);
+ DistPrint(const VectorDistInfoBase &info, int i);
+ void init(const Info &info, const DistParams *params);
void operator()(ostream &stream) const;
};
+DistPrint::DistPrint(const DistInfoBase &info)
+ : data(info.data)
+{
+ init(info, safe_cast<const DistParams *>(info.storageParams));
+}
+
+DistPrint::DistPrint(const VectorDistInfoBase &info, int i)
+ : data(info.data[i])
+{
+ init(info, safe_cast<const DistParams *>(info.storageParams));
+
+ name = info.name + "_" +
+ (info.subnames[i].empty() ? (to_string(i)) : info.subnames[i]);
+
+ if (!info.subdescs[i].empty())
+ desc = info.subdescs[i];
+}
+
+void
+DistPrint::init(const Info &info, const DistParams *params)
+{
+ name = info.name;
+ desc = info.desc;
+ flags = info.flags;
+ compat = compat;
+ descriptions = descriptions;
+ precision = info.precision;
+
+ fancy = params->fancy;
+ min = params->min;
+ max = params->max;
+ bucket_size = params->bucket_size;
+ size = params->buckets;
+}
+
void
DistPrint::operator()(ostream &stream) const
{
+ Result stdev = NAN;
+ if (data.samples)
+ stdev = sqrt((data.samples * data.squares - data.sum * data.sum) /
+ (data.samples * (data.samples - 1.0)));
+
if (fancy) {
ScalarPrint print;
string base = name + (compat ? "_" : "::");
@@ -386,28 +421,27 @@ DistPrint::operator()(ostream &stream) const
print.cdf = NAN;
print.name = base + "mean";
- print.value = samples ? sum / samples : NAN;
+ print.value = data.samples ? data.sum / data.samples : NAN;
print(stream);
print.name = base + "stdev";
- print.value = samples ? sqrt((samples * squares - sum * sum) /
- (samples * (samples - 1.0))) : NAN;
+ print.value = stdev;
print(stream);
print.name = "**Ignore: " + base + "TOT";
- print.value = samples;
+ print.value = data.samples;
print(stream);
return;
}
- assert(size == vec.size());
+ assert(size == data.cvec.size());
Result total = 0.0;
- total += underflow;
- for (int i = 0; i < size; ++i)
- total += vec[i];
- total += overflow;
+ total += data.underflow;
+ for (off_type i = 0; i < size; ++i)
+ total += data.cvec[i];
+ total += data.overflow;
string base = name + (compat ? "." : "::");
@@ -428,28 +462,27 @@ DistPrint::operator()(ostream &stream) const
}
print.name = base + "samples";
- print.value = samples;
+ print.value = data.samples;
print(stream);
print.name = base + "min_value";
- print.value = min_val;
+ print.value = data.min_val;
print(stream);
- if (!compat || underflow > 0.0) {
+ if (!compat || data.underflow > 0.0) {
print.name = base + "underflows";
- print.value = underflow;
+ print.value = data.underflow;
if (!compat && total) {
- print.pdf = underflow / total;
+ print.pdf = data.underflow / total;
print.cdf += print.pdf;
}
print(stream);
}
-
if (!compat) {
- for (int i = 0; i < size; ++i) {
+ for (off_type i = 0; i < size; ++i) {
stringstream namestr;
- namestr << name;
+ namestr << base;
Counter low = i * bucket_size + min;
Counter high = ::min(low + bucket_size, max);
@@ -458,14 +491,13 @@ DistPrint::operator()(ostream &stream) const
namestr << "-" << high;
print.name = namestr.str();
- print.value = vec[i];
+ print.value = data.cvec[i];
if (total) {
- print.pdf = vec[i] / total;
+ print.pdf = data.cvec[i] / total;
print.cdf += print.pdf;
}
print(stream);
}
-
} else {
Counter _min;
Result _pdf;
@@ -473,18 +505,18 @@ DistPrint::operator()(ostream &stream) const
print.flags = flags | __substat;
- for (int i = 0; i < size; ++i) {
- if (flags & nozero && vec[i] == 0.0 ||
- flags & nonan && isnan(vec[i]))
+ for (off_type i = 0; i < size; ++i) {
+ if ((flags & nozero && data.cvec[i] == 0.0) ||
+ (flags & nonan && isnan(data.cvec[i])))
continue;
_min = i * bucket_size + min;
- _pdf = vec[i] / total * 100.0;
+ _pdf = data.cvec[i] / total * 100.0;
_cdf += _pdf;
print.name = ValueToString(_min, 0, compat);
- print.value = vec[i];
+ print.value = data.cvec[i];
print.pdf = (flags & pdf) ? _pdf : NAN;
print.cdf = (flags & cdf) ? _cdf : NAN;
print(stream);
@@ -493,11 +525,11 @@ DistPrint::operator()(ostream &stream) const
print.flags = flags;
}
- if (!compat || overflow > 0.0) {
+ if (!compat || data.overflow > 0.0) {
print.name = base + "overflows";
- print.value = overflow;
+ print.value = data.overflow;
if (!compat && total) {
- print.pdf = overflow / total;
+ print.pdf = data.overflow / total;
print.cdf += print.pdf;
} else {
print.pdf = NAN;
@@ -516,17 +548,16 @@ DistPrint::operator()(ostream &stream) const
}
print.name = base + "max_value";
- print.value = max_val;
+ print.value = data.max_val;
print(stream);
- if (!compat && samples != 0) {
+ if (!compat && data.samples != 0) {
print.name = base + "mean";
- print.value = sum / samples;
+ print.value = data.sum / data.samples;
print(stream);
print.name = base + "stdev";
- print.value = sqrt((samples * squares - sum * sum) /
- (samples * (samples - 1.0)));
+ print.value = stdev;
print(stream);
}
@@ -535,19 +566,19 @@ DistPrint::operator()(ostream &stream) const
}
void
-Text::visit(const ScalarData &data)
+Text::visit(const ScalarInfoBase &info)
{
- if (noOutput(data))
+ if (noOutput(info))
return;
ScalarPrint print;
- print.value = data.result();
- print.name = data.name;
- print.desc = data.desc;
- print.flags = data.flags;
+ print.value = info.result();
+ print.name = info.name;
+ print.desc = info.desc;
+ print.flags = info.flags;
print.compat = compat;
print.descriptions = descriptions;
- print.precision = data.precision;
+ print.precision = info.precision;
print.pdf = NAN;
print.cdf = NAN;
@@ -555,32 +586,32 @@ Text::visit(const ScalarData &data)
}
void
-Text::visit(const VectorData &data)
+Text::visit(const VectorInfoBase &info)
{
- if (noOutput(data))
+ if (noOutput(info))
return;
- int size = data.size();
+ size_type size = info.size();
VectorPrint print;
- print.name = data.name;
- print.desc = data.desc;
- print.flags = data.flags;
+ print.name = info.name;
+ print.desc = info.desc;
+ print.flags = info.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.precision = info.precision;
+ print.vec = info.result();
+ print.total = info.total();
+
+ if (!info.subnames.empty()) {
+ for (off_type i = 0; i < size; ++i) {
+ if (!info.subnames[i].empty()) {
+ print.subnames = info.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;
+ for (off_type i = 0; i < size; ++i) {
+ if (!info.subnames[i].empty() &&
+ !info.subdescs[i].empty()) {
+ print.subdescs = info.subdescs;
print.subdescs.resize(size);
break;
}
@@ -594,53 +625,54 @@ Text::visit(const VectorData &data)
}
void
-Text::visit(const Vector2dData &data)
+Text::visit(const Vector2dInfoBase &info)
{
- if (noOutput(data))
+ if (noOutput(info))
return;
bool havesub = false;
VectorPrint print;
- print.subnames = data.y_subnames;
- print.flags = data.flags;
+ print.subnames = info.y_subnames;
+ print.flags = info.flags;
print.compat = compat;
print.descriptions = descriptions;
- print.precision = data.precision;
+ print.precision = info.precision;
- if (!data.subnames.empty()) {
- for (int i = 0; i < data.x; ++i)
- if (!data.subnames[i].empty())
+ if (!info.subnames.empty()) {
+ for (off_type i = 0; i < info.x; ++i)
+ if (!info.subnames[i].empty())
havesub = true;
}
- VResult tot_vec(data.y);
+ VResult tot_vec(info.y);
Result super_total = 0.0;
- for (int i = 0; i < data.x; ++i) {
- if (havesub && (i >= data.subnames.size() || data.subnames[i].empty()))
+ for (off_type i = 0; i < info.x; ++i) {
+ if (havesub && (i >= info.subnames.size() || info.subnames[i].empty()))
continue;
- int iy = i * data.y;
- VResult yvec(data.y);
+ off_type iy = i * info.y;
+ VResult yvec(info.y);
Result total = 0.0;
- for (int j = 0; j < data.y; ++j) {
- yvec[j] = data.cvec[iy + j];
+ for (off_type j = 0; j < info.y; ++j) {
+ yvec[j] = info.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.name = info.name + "_" +
+ (havesub ? info.subnames[i] : to_string(i));
+ print.desc = info.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;
+ if ((info.flags & ::Stats::total) && (info.x > 1)) {
+ print.name = info.name;
+ print.desc = info.desc;
print.vec = tot_vec;
print.total = super_total;
print(*stream);
@@ -648,82 +680,31 @@ Text::visit(const Vector2dData &data)
}
void
-Text::visit(const DistData &data)
+Text::visit(const DistInfoBase &info)
{
- if (noOutput(data))
+ if (noOutput(info))
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;
-
+ DistPrint print(info);
print(*stream);
}
void
-Text::visit(const VectorDistData &data)
+Text::visit(const VectorDistInfoBase &info)
{
- if (noOutput(data))
+ if (noOutput(info))
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;
-
+ for (off_type i = 0; i < info.size(); ++i) {
+ DistPrint print(info, i);
print(*stream);
}
}
void
-Text::visit(const FormulaData &data)
+Text::visit(const FormulaInfoBase &info)
{
- visit((const VectorData &)data);
+ visit((const VectorInfoBase &)info);
}
bool
@@ -746,5 +727,4 @@ initText(const string &filename, bool desc, bool compat)
return true;
}
-
/* namespace Stats */ }
diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh
index 781d1083d..38e0202eb 100644
--- a/src/base/stats/text.hh
+++ b/src/base/stats/text.hh
@@ -46,7 +46,7 @@ class Text : public Output
std::ostream *stream;
protected:
- bool noOutput(const StatData &data);
+ bool noOutput(const Info &info);
public:
bool compat;
@@ -62,12 +62,12 @@ class Text : public Output
void open(const std::string &file);
// Implement Visit
- virtual void visit(const ScalarData &data);
- virtual void visit(const VectorData &data);
- virtual void visit(const DistData &data);
- virtual void visit(const VectorDistData &data);
- virtual void visit(const Vector2dData &data);
- virtual void visit(const FormulaData &data);
+ virtual void visit(const ScalarInfoBase &info);
+ virtual void visit(const VectorInfoBase &info);
+ virtual void visit(const DistInfoBase &info);
+ virtual void visit(const VectorDistInfoBase &info);
+ virtual void visit(const Vector2dInfoBase &info);
+ virtual void visit(const FormulaInfoBase &info);
// Implement Output
virtual bool valid() const;
diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh
index b64e8fb17..e561f94ad 100644
--- a/src/base/stats/types.hh
+++ b/src/base/stats/types.hh
@@ -31,7 +31,9 @@
#ifndef __BASE_STATS_TYPES_HH__
#define __BASE_STATS_TYPES_HH__
+#include <limits>
#include <vector>
+
#include "sim/host.hh"
namespace Stats {
@@ -41,11 +43,16 @@ typedef double Counter;
/** vector of counters. */
typedef std::vector<Counter> VCounter;
+typedef std::numeric_limits<Counter> CounterLimits;
+
/** All results are doubles. */
typedef double Result;
/** vector of results. */
typedef std::vector<Result> VResult;
+typedef unsigned int size_type;
+typedef unsigned int off_type;
+
/* namespace Stats */ }
#endif // __BASE_STATS_TYPES_HH__
diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh
index 0087c227c..9d6996689 100644
--- a/src/base/stats/visit.hh
+++ b/src/base/stats/visit.hh
@@ -38,26 +38,26 @@
namespace Stats {
-class StatData;
-class ScalarData;
-class VectorData;
-class DistDataData;
-class DistData;
-class VectorDistData;
-class Vector2dData;
-class FormulaData;
+class Info;
+class ScalarInfoBase;
+class VectorInfoBase;
+class DistInfoBase;
+class DistInfoBase;
+class VectorDistInfoBase;
+class Vector2dInfoBase;
+class FormulaInfoBase;
struct Visit
{
Visit();
virtual ~Visit();
- virtual void visit(const ScalarData &data) = 0;
- virtual void visit(const VectorData &data) = 0;
- virtual void visit(const DistData &data) = 0;
- virtual void visit(const VectorDistData &data) = 0;
- virtual void visit(const Vector2dData &data) = 0;
- virtual void visit(const FormulaData &data) = 0;
+ virtual void visit(const ScalarInfoBase &info) = 0;
+ virtual void visit(const VectorInfoBase &info) = 0;
+ virtual void visit(const DistInfoBase &info) = 0;
+ virtual void visit(const VectorDistInfoBase &info) = 0;
+ virtual void visit(const Vector2dInfoBase &info) = 0;
+ virtual void visit(const FormulaInfoBase &info) = 0;
};
/* namespace Stats */ }
diff --git a/src/base/str.cc b/src/base/str.cc
index 0a517dff5..2df1c103c 100644
--- a/src/base/str.cc
+++ b/src/base/str.cc
@@ -28,10 +28,10 @@
* Authors: Nathan Binkert
*/
-#include <ctype.h>
-
+#include <cctype>
#include <cstring>
#include <iostream>
+#include <limits>
#include <string>
#include <vector>
@@ -117,12 +117,11 @@ inline bool
__to_number(string value, T &retval)
{
static const T maxnum = ((T)-1);
- static const bool sign = maxnum < 0;
- static const int bits = sizeof(T) * 8;
- static const T hexmax = maxnum & (((T)1 << (bits - 4 - sign)) - 1);
- static const T octmax = maxnum & (((T)1 << (bits - 3 - sign)) - 1);
- static const T signmax =
- (sign) ? maxnum & (((T)1 << (bits - 1)) - 1) : maxnum;
+ static const bool sign = numeric_limits<T>::is_signed;
+ static const int bits = numeric_limits<T>::digits;
+ static const T hexmax = maxnum & (((T)1 << (bits - 4)) - 1);
+ static const T octmax = maxnum & (((T)1 << (bits - 3)) - 1);
+ static const T signmax = numeric_limits<T>::max();
static const T decmax = signmax / 10;
#if 0
diff --git a/src/base/time.cc b/src/base/time.cc
index 76ba355b7..a1732773e 100644
--- a/src/base/time.cc
+++ b/src/base/time.cc
@@ -28,9 +28,9 @@
* Authors: Nathan Binkert
*/
-#include <sys/types.h>
-#include <sys/time.h>
-#include <time.h>
+#include <cctype>
+#include <cstring>
+#include <ctime>
#include <iostream>
#include <string>
diff --git a/src/base/time.hh b/src/base/time.hh
index f10cc5d6c..565ea0aac 100644
--- a/src/base/time.hh
+++ b/src/base/time.hh
@@ -68,7 +68,7 @@ std::ostream &operator<<(std::ostream &out, const Time &time);
/*
* Copyright (c) 1982, 1986, 1993
- * The Regents of the University of California. All rights reserved.
+ * 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
@@ -94,7 +94,7 @@ std::ostream &operator<<(std::ostream &out, const Time &time);
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)time.h 8.2 (Berkeley) 7/10/94
+ * @(#)time.h 8.2 (Berkeley) 7/10/94
*/
#if defined(__sun)
diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh
index 348f7a673..9f9fc32b5 100644
--- a/src/base/timebuf.hh
+++ b/src/base/timebuf.hh
@@ -43,6 +43,7 @@ class TimeBuffer
int past;
int future;
int size;
+ int _id;
char *data;
std::vector<char *> index;
@@ -148,6 +149,8 @@ class TimeBuffer
new (ptr) T;
ptr += sizeof(T);
}
+
+ _id = -1;
}
TimeBuffer()
@@ -162,6 +165,16 @@ class TimeBuffer
delete [] data;
}
+ void id(int id)
+ {
+ _id = id;
+ }
+
+ int id()
+ {
+ return _id;
+ }
+
void
advance()
{
diff --git a/src/base/trace.hh b/src/base/trace.hh
index c1b506187..fa24e9c48 100644
--- a/src/base/trace.hh
+++ b/src/base/trace.hh
@@ -97,6 +97,12 @@ inline const std::string &name() { return Trace::DefaultName; }
Trace::dprintf(curTick, name(), __VA_ARGS__); \
} while (0)
+#define DPRINTFS(x,s, ...) do { \
+ if (DTRACE(x)) \
+ Trace::dprintf(curTick, s->name(), __VA_ARGS__); \
+} while (0)
+
+
#define DPRINTFR(x, ...) do { \
if (DTRACE(x)) \
Trace::dprintf((Tick)-1, std::string(), __VA_ARGS__); \
@@ -119,11 +125,12 @@ inline const std::string &name() { return Trace::DefaultName; }
#define DTRACE(x) (false)
#define DDUMP(x, data, count) do {} while (0)
#define DPRINTF(x, ...) do {} while (0)
+#define DPRINTFS(x, ...) do {} while (0)
#define DPRINTFR(...) do {} while (0)
#define DDUMPN(data, count) do {} while (0)
#define DPRINTFN(...) do {} while (0)
#define DPRINTFNR(...) do {} while (0)
-#endif // TRACING_ON
+#endif // TRACING_ON
#endif // __BASE_TRACE_HH__
diff --git a/src/base/varargs.hh b/src/base/varargs.hh
index 2ba8c240a..4328f2057 100644
--- a/src/base/varargs.hh
+++ b/src/base/varargs.hh
@@ -147,15 +147,31 @@ struct Any : public Base<RECV>
}
};
+template <typename T, class RECV>
+struct Any<T *, RECV> : public Base<RECV>
+{
+ const T *argument;
+
+ Any(const T *arg) : argument(arg) {}
+
+ virtual void
+ add_arg(RECV &receiver) const
+ {
+ receiver.add_arg(argument);
+ }
+};
+
template <class RECV>
struct Argument : public RefCountingPtr<Base<RECV> >
{
- typedef RefCountingPtr<Base<RECV> > Base;
+ typedef RefCountingPtr<VarArgs::Base<RECV> > Base;
Argument() { }
Argument(const Null &null) { }
template <typename T>
Argument(const T& arg) : Base(new Any<T, RECV>(arg)) { }
+ template <typename T>
+ Argument(const T* arg) : Base(new Any<T *, RECV>(arg)) { }
void
add_arg(RECV &receiver) const
@@ -169,7 +185,7 @@ template<class RECV>
class List
{
public:
- typedef Argument<RECV> Argument;
+ typedef VarArgs::Argument<RECV> Argument;
typedef std::list<Argument> list;
typedef typename list::iterator iterator;
typedef typename list::const_iterator const_iterator;
diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py
index c2a865113..f3688e991 100644
--- a/src/cpu/BaseCPU.py
+++ b/src/cpu/BaseCPU.py
@@ -26,7 +26,7 @@
#
# Authors: Nathan Binkert
-from m5.SimObject import SimObject
+from MemObject import MemObject
from m5.params import *
from m5.proxy import *
from m5 import build_env
@@ -39,50 +39,84 @@ default_tracer = ExeTracer()
if build_env['TARGET_ISA'] == 'alpha':
from AlphaTLB import AlphaDTB, AlphaITB
+ if build_env['FULL_SYSTEM']:
+ from AlphaInterrupts import AlphaInterrupts
elif build_env['TARGET_ISA'] == 'sparc':
from SparcTLB import SparcDTB, SparcITB
+ if build_env['FULL_SYSTEM']:
+ from SparcInterrupts import SparcInterrupts
elif build_env['TARGET_ISA'] == 'x86':
from X86TLB import X86DTB, X86ITB
+ if build_env['FULL_SYSTEM']:
+ from X86LocalApic import X86LocalApic
elif build_env['TARGET_ISA'] == 'mips':
from MipsTLB import MipsTLB,MipsDTB, MipsITB, MipsUTB
+ if build_env['FULL_SYSTEM']:
+ from MipsInterrupts import MipsInterrupts
elif build_env['TARGET_ISA'] == 'arm':
from ArmTLB import ArmTLB, ArmDTB, ArmITB, ArmUTB
+ if build_env['FULL_SYSTEM']:
+ from ArmInterrupts import ArmInterrupts
-class BaseCPU(SimObject):
+class BaseCPU(MemObject):
type = 'BaseCPU'
abstract = True
system = Param.System(Parent.any, "system object")
- cpu_id = Param.Int("CPU identifier")
+ cpu_id = Param.Int(-1, "CPU identifier")
+ numThreads = Param.Unsigned(1, "number of HW thread contexts")
+
+ function_trace = Param.Bool(False, "Enable function trace")
+ function_trace_start = Param.Tick(0, "Cycle to start function trace")
+
+ checker = Param.BaseCPU(NULL, "checker CPU")
+
+ do_checkpoint_insts = Param.Bool(True,
+ "enable checkpoint pseudo instructions")
+ do_statistics_insts = Param.Bool(True,
+ "enable statistics pseudo instructions")
if build_env['FULL_SYSTEM']:
+ profile = Param.Latency('0ns', "trace the kernel stack")
do_quiesce = Param.Bool(True, "enable quiesce instructions")
- do_checkpoint_insts = Param.Bool(True,
- "enable checkpoint pseudo instructions")
- do_statistics_insts = Param.Bool(True,
- "enable statistics pseudo instructions")
else:
workload = VectorParam.Process("processes to run")
if build_env['TARGET_ISA'] == 'sparc':
dtb = Param.SparcDTB(SparcDTB(), "Data TLB")
itb = Param.SparcITB(SparcITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.SparcInterrupts(
+ SparcInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'alpha':
dtb = Param.AlphaDTB(AlphaDTB(), "Data TLB")
itb = Param.AlphaITB(AlphaITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.AlphaInterrupts(
+ AlphaInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'x86':
dtb = Param.X86DTB(X86DTB(), "Data TLB")
itb = Param.X86ITB(X86ITB(), "Instruction TLB")
+ if build_env['FULL_SYSTEM']:
+ _localApic = X86LocalApic(pio_addr=0x2000000000000000)
+ interrupts = \
+ Param.X86LocalApic(_localApic, "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'mips':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.MipsDTB(MipsDTB(), "Data TLB")
itb = Param.MipsITB(MipsITB(), "Instruction TLB")
tlb = Param.MipsUTB(MipsUTB(), "Unified TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.MipsInterrupts(
+ MipsInterrupts(), "Interrupt Controller")
elif build_env['TARGET_ISA'] == 'arm':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.ArmDTB(ArmDTB(), "Data TLB")
itb = Param.ArmITB(ArmITB(), "Instruction TLB")
tlb = Param.ArmUTB(ArmUTB(), "Unified TLB")
+ if build_env['FULL_SYSTEM']:
+ interrupts = Param.ArmInterrupts(
+ ArmInterrupts(), "Interrupt Controller")
else:
print "Don't know what TLB to use for ISA %s" % \
build_env['TARGET_ISA']
@@ -109,7 +143,10 @@ class BaseCPU(SimObject):
_mem_ports = []
if build_env['TARGET_ISA'] == 'x86' and build_env['FULL_SYSTEM']:
- _mem_ports = ["itb.walker.port", "dtb.walker.port"]
+ _mem_ports = ["itb.walker.port",
+ "dtb.walker.port",
+ "interrupts.pio",
+ "interrupts.int_port"]
def connectMemPorts(self, bus):
for p in self._mem_ports:
diff --git a/src/cpu/CheckerCPU.py b/src/cpu/CheckerCPU.py
new file mode 100644
index 000000000..bff9af62d
--- /dev/null
+++ b/src/cpu/CheckerCPU.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5 import build_env
+from BaseCPU import BaseCPU
+
+class CheckerCPU(BaseCPU):
+ type = 'CheckerCPU'
+ abstract = True
+ exitOnError = Param.Bool(False, "Exit on an error")
+ updateOnError = Param.Bool(False,
+ "Update the checker with the main CPU's state on an error")
+ warnOnlyOnLoadError = Param.Bool(False,
+ "If a load result is incorrect, only print a warning and do not exit")
+ function_trace = Param.Bool(False, "Enable function trace")
+ function_trace_start = Param.Tick(0, "Cycle to start function trace")
diff --git a/src/cpu/ExeTracer.py b/src/cpu/ExeTracer.py
index e904f9e7d..5754f5d5b 100644
--- a/src/cpu/ExeTracer.py
+++ b/src/cpu/ExeTracer.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class ExeTracer(InstTracer):
type = 'ExeTracer'
- cxx_namespace = 'Trace'
- cxx_class = 'ExeTracer'
+ cxx_class = 'Trace::ExeTracer'
diff --git a/src/cpu/IntelTrace.py b/src/cpu/IntelTrace.py
index 6e8f567b3..3642f3174 100644
--- a/src/cpu/IntelTrace.py
+++ b/src/cpu/IntelTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class IntelTrace(InstTracer):
type = 'IntelTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'IntelTrace'
+ cxx_class = 'Trace::IntelTrace'
diff --git a/src/cpu/LegionTrace.py b/src/cpu/LegionTrace.py
index f9b6470a6..d450dd00e 100644
--- a/src/cpu/LegionTrace.py
+++ b/src/cpu/LegionTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class LegionTrace(InstTracer):
type = 'LegionTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'LegionTrace'
+ cxx_class = 'Trace::LegionTrace'
diff --git a/src/cpu/NativeTrace.py b/src/cpu/NativeTrace.py
index 96b4e991b..f410b5473 100644
--- a/src/cpu/NativeTrace.py
+++ b/src/cpu/NativeTrace.py
@@ -32,5 +32,4 @@ from InstTracer import InstTracer
class NativeTrace(InstTracer):
type = 'NativeTrace'
- cxx_namespace = 'Trace'
- cxx_class = 'NativeTrace'
+ cxx_class = 'Trace::NativeTrace'
diff --git a/src/cpu/SConscript b/src/cpu/SConscript
index c7d0c33bd..eee8edca4 100644
--- a/src/cpu/SConscript
+++ b/src/cpu/SConscript
@@ -48,12 +48,14 @@ 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
+virtual Fault execute(%(type)s *xc, Trace::InstRecord *traceData) const = 0;
+virtual Fault initiateAcc(%(type)s *xc, Trace::InstRecord *traceData) const
{ panic("initiateAcc not defined!"); M5_DUMMY_RETURN };
-virtual Fault completeAcc(Packet *pkt, %s *xc,
+virtual Fault completeAcc(Packet *pkt, %(type)s *xc,
Trace::InstRecord *traceData) const
{ panic("completeAcc not defined!"); M5_DUMMY_RETURN };
+virtual int memAccSize(%(type)s *xc)
+{ panic("memAccSize not defined!"); M5_DUMMY_RETURN };
'''
mem_ini_sig_template = '''
@@ -71,6 +73,7 @@ temp_cpu_list = env['CPU_MODELS'][:]
if env['USE_CHECKER']:
temp_cpu_list.append('CheckerCPU')
+ SimObject('CheckerCPU.py')
# Generate header.
def gen_cpu_exec_signatures(target, source, env):
@@ -81,7 +84,7 @@ def gen_cpu_exec_signatures(target, source, env):
'''
for cpu in temp_cpu_list:
xc_type = CpuModel.dict[cpu].strings['CPU_exec_context']
- print >> f, exec_sig_template % (xc_type, xc_type, xc_type)
+ print >> f, exec_sig_template % { 'type' : xc_type }
print >> f, '''
#endif // __CPU_STATIC_INST_EXEC_SIGS_HH__
'''
@@ -165,10 +168,12 @@ TraceFlag('ExecSpeculative')
TraceFlag('ExecSymbol')
TraceFlag('ExecThread')
TraceFlag('ExecTicks')
+TraceFlag('ExecMicro')
+TraceFlag('ExecMacro')
TraceFlag('Fetch')
TraceFlag('IntrControl')
TraceFlag('PCEvent')
TraceFlag('Quiesce')
CompoundFlag('Exec', [ 'ExecEnable', 'ExecTicks', 'ExecOpClass', 'ExecThread',
- 'ExecEffAddr', 'ExecResult', 'ExecSymbol' ])
+ 'ExecEffAddr', 'ExecResult', 'ExecSymbol', 'ExecMicro' ])
diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc
index 15e0556ad..a2a34edf9 100644
--- a/src/cpu/activity.cc
+++ b/src/cpu/activity.cc
@@ -28,15 +28,18 @@
* Authors: Kevin Lim
*/
-#include <cstring>
+#include <string>
#include "base/timebuf.hh"
#include "cpu/activity.hh"
-ActivityRecorder::ActivityRecorder(int num_stages, int longest_latency,
- int activity)
- : activityBuffer(longest_latency, 0), longestLatency(longest_latency),
- activityCount(activity), numStages(num_stages)
+using namespace std;
+
+ActivityRecorder::ActivityRecorder(const string &name, int num_stages,
+ int longest_latency, int activity)
+ : _name(name), activityBuffer(longest_latency, 0),
+ longestLatency(longest_latency), activityCount(activity),
+ numStages(num_stages)
{
stageActive = new bool[numStages];
std::memset(stageActive, 0, numStages);
diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh
index e99927339..d75ff150e 100644
--- a/src/cpu/activity.hh
+++ b/src/cpu/activity.hh
@@ -49,9 +49,11 @@
* idle. If count is zero, then the CPU can safely idle as it has no
* more outstanding work to do.
*/
-class ActivityRecorder {
+class ActivityRecorder
+{
public:
- ActivityRecorder(int num_stages, int longest_latency, int count);
+ ActivityRecorder(const std::string &name, int num_stages,
+ int longest_latency, int count);
/** Records that there is activity this cycle. */
void activity();
@@ -92,6 +94,10 @@ class ActivityRecorder {
void validate();
private:
+ // provide name() for DPRINTF.
+ std::string _name;
+ const std::string &name() { return _name; }
+
/** Time buffer that tracks if any cycles has active communication
* in them. It should be as long as the longest communication
* latency in the system. Each time any time buffer is written,
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index 23195f720..0ef206d90 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -37,17 +37,17 @@
#include "base/loader/symtab.hh"
#include "base/misc.hh"
#include "base/output.hh"
+#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/cpuevent.hh"
#include "cpu/thread_context.hh"
#include "cpu/profile.hh"
+#include "params/BaseCPU.hh"
#include "sim/sim_exit.hh"
#include "sim/process.hh"
#include "sim/sim_events.hh"
#include "sim/system.hh"
-#include "base/trace.hh"
-
// Hack
#include "sim/stat_control.hh"
@@ -60,13 +60,12 @@ vector<BaseCPU *> BaseCPU::cpuList;
// been initialized
int maxThreadsPerCPU = 1;
-CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival,
- BaseCPU *_cpu)
- : Event(q, Event::Progress_Event_Pri), interval(ival),
- lastNumInst(0), cpu(_cpu)
+CPUProgressEvent::CPUProgressEvent(BaseCPU *_cpu, Tick ival)
+ : Event(Event::Progress_Event_Pri), interval(ival), lastNumInst(0),
+ cpu(_cpu)
{
if (interval)
- schedule(curTick + interval);
+ cpu->schedule(this, curTick + interval);
}
void
@@ -84,7 +83,7 @@ CPUProgressEvent::process()
curTick, cpu->name(), temp - lastNumInst);
#endif
lastNumInst = temp;
- schedule(curTick + interval);
+ cpu->schedule(this, curTick + interval);
}
const char *
@@ -95,21 +94,29 @@ CPUProgressEvent::description() const
#if FULL_SYSTEM
BaseCPU::BaseCPU(Params *p)
- : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0),
- params(p), number_of_threads(p->numberOfThreads), system(p->system),
+ : MemObject(p), clock(p->clock), instCnt(0), _cpuId(p->cpu_id),
+ interrupts(p->interrupts),
+ number_of_threads(p->numThreads), system(p->system),
phase(p->phase)
#else
BaseCPU::BaseCPU(Params *p)
- : MemObject(makeParams(p->name)), clock(p->clock), params(p),
- number_of_threads(p->numberOfThreads), system(p->system),
+ : MemObject(p), clock(p->clock), _cpuId(p->cpu_id),
+ number_of_threads(p->numThreads), system(p->system),
phase(p->phase)
#endif
{
// currentTick = curTick;
+ // if Python did not provide a valid ID, do it here
+ if (_cpuId == -1 ) {
+ _cpuId = cpuList.size();
+ }
+
// add self to global list of CPUs
cpuList.push_back(this);
+ DPRINTF(SyscallVerbose, "Constructing CPU with id %d\n", _cpuId);
+
if (number_of_threads > maxThreadsPerCPU)
maxThreadsPerCPU = number_of_threads;
@@ -121,22 +128,26 @@ BaseCPU::BaseCPU(Params *p)
//
// 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)
- schedExitSimLoop("a thread reached the max instruction count",
- p->max_insts_any_thread, 0,
- comInstEventQueue[i]);
+ if (p->max_insts_any_thread != 0) {
+ const char *cause = "a thread reached the max instruction count";
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new SimLoopExitEvent(cause, 0);
+ comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
+ }
+ }
if (p->max_insts_all_threads != 0) {
+ const char *cause = "all threads reached the max instruction count";
+
// 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);
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new CountedExitEvent(cause, *counter);
+ comInstEventQueue[i]->schedule(event, p->max_insts_any_thread);
+ }
}
// allocate per-thread load-based event queues
@@ -147,53 +158,49 @@ BaseCPU::BaseCPU(Params *p)
//
// 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)
- schedExitSimLoop("a thread reached the max load count",
- p->max_loads_any_thread, 0,
- comLoadEventQueue[i]);
+ if (p->max_loads_any_thread != 0) {
+ const char *cause = "a thread reached the max load count";
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new SimLoopExitEvent(cause, 0);
+ comLoadEventQueue[i]->schedule(event, p->max_loads_any_thread);
+ }
+ }
if (p->max_loads_all_threads != 0) {
+ const char *cause = "all threads reached the max load count";
// 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);
+ for (int i = 0; i < number_of_threads; ++i) {
+ Event *event = new CountedExitEvent(cause, *counter);
+ comLoadEventQueue[i]->schedule(event, p->max_loads_all_threads);
+ }
}
functionTracingEnabled = false;
- if (p->functionTrace) {
+ if (p->function_trace) {
functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
currentFunctionStart = currentFunctionEnd = 0;
- functionEntryTick = p->functionTraceStart;
+ functionEntryTick = p->function_trace_start;
- if (p->functionTraceStart == 0) {
+ if (p->function_trace_start == 0) {
functionTracingEnabled = true;
} else {
- new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,
- p->functionTraceStart,
- true);
+ typedef EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace> wrap;
+ Event *event = new wrap(this, true);
+ schedule(event, p->function_trace_start);
}
}
#if FULL_SYSTEM
- profileEvent = NULL;
- if (params->profile)
- profileEvent = new ProfileEvent(this, params->profile);
-#endif
- tracer = params->tracer;
-}
+ interrupts->setCPU(this);
-BaseCPU::Params::Params()
-{
-#if FULL_SYSTEM
- profile = false;
+ profileEvent = NULL;
+ if (params()->profile)
+ profileEvent = new ProfileEvent(this, params()->profile);
#endif
- checker = NULL;
- tracer = NULL;
+ tracer = params()->tracer;
}
void
@@ -209,7 +216,7 @@ BaseCPU::~BaseCPU()
void
BaseCPU::init()
{
- if (!params->deferRegistration)
+ if (!params()->defer_registration)
registerThreadContexts();
}
@@ -217,14 +224,14 @@ void
BaseCPU::startup()
{
#if FULL_SYSTEM
- if (!params->deferRegistration && profileEvent)
- profileEvent->schedule(curTick);
+ if (!params()->defer_registration && profileEvent)
+ schedule(profileEvent, curTick);
#endif
- if (params->progress_interval) {
- new CPUProgressEvent(&mainEventQueue,
- ticks(params->progress_interval),
- this);
+ if (params()->progress_interval) {
+ Tick num_ticks = ticks(params()->progress_interval);
+ Event *event = new CPUProgressEvent(this, num_ticks);
+ schedule(event, curTick + num_ticks);
}
}
@@ -280,14 +287,19 @@ BaseCPU::registerThreadContexts()
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
-#if FULL_SYSTEM
- int id = params->cpu_id;
- if (id != -1)
- id += i;
-
- tc->setCpuId(system->registerThreadContext(tc, id));
-#else
- tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc));
+ /** This is so that contextId and cpuId match where there is a
+ * 1cpu:1context relationship. Otherwise, the order of registration
+ * could affect the assignment and cpu 1 could have context id 3, for
+ * example. We may even want to do something like this for SMT so that
+ * cpu 0 has the lowest thread contexts and cpu N has the highest, but
+ * I'll just do this for now
+ */
+ if (number_of_threads == 1)
+ tc->setContextId(system->registerThreadContext(tc, _cpuId));
+ else
+ tc->setContextId(system->registerThreadContext(tc));
+#if !FULL_SYSTEM
+ tc->getProcessPtr()->assignThreadContext(tc->contextId());
#endif
}
}
@@ -309,7 +321,7 @@ BaseCPU::switchOut()
// panic("This CPU doesn't support sampling!");
#if FULL_SYSTEM
if (profileEvent && profileEvent->scheduled())
- profileEvent->deschedule();
+ deschedule(profileEvent);
#endif
}
@@ -318,6 +330,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
{
assert(threadContexts.size() == oldCPU->threadContexts.size());
+ _cpuId = oldCPU->cpuId();
+
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *newTC = threadContexts[i];
ThreadContext *oldTC = oldCPU->threadContexts[i];
@@ -326,53 +340,49 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc)
CpuEvent::replaceThreadContext(oldTC, newTC);
- assert(newTC->readCpuId() == oldTC->readCpuId());
-#if FULL_SYSTEM
- system->replaceThreadContext(newTC, newTC->readCpuId());
-#else
- assert(newTC->getProcessPtr() == oldTC->getProcessPtr());
- newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId());
-#endif
+ assert(newTC->contextId() == oldTC->contextId());
+ assert(newTC->threadId() == oldTC->threadId());
+ system->replaceThreadContext(newTC, newTC->contextId());
- if (DTRACE(Context))
+ /* This code no longer works since the zero register (e.g.,
+ * r31 on Alpha) doesn't necessarily contain zero at this
+ * point.
+ if (DTRACE(Context))
ThreadContext::compare(oldTC, newTC);
+ */
}
#if FULL_SYSTEM
interrupts = oldCPU->interrupts;
+ interrupts->setCPU(this);
for (int i = 0; i < threadContexts.size(); ++i)
threadContexts[i]->profileClear();
if (profileEvent)
- profileEvent->schedule(curTick);
+ schedule(profileEvent, curTick);
#endif
// Connect new CPU to old CPU's memory only if new CPU isn't
// connected to anything. Also connect old CPU's memory to new
// CPU.
- Port *peer;
- if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) {
- peer = oldCPU->getPort("icache_port")->getPeer();
+ if (!ic->isConnected()) {
+ Port *peer = oldCPU->getPort("icache_port")->getPeer();
ic->setPeer(peer);
- } else {
- peer = ic->getPeer();
+ peer->setPeer(ic);
}
- peer->setPeer(ic);
- if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) {
- peer = oldCPU->getPort("dcache_port")->getPeer();
+ if (!dc->isConnected()) {
+ Port *peer = oldCPU->getPort("dcache_port")->getPeer();
dc->setPeer(peer);
- } else {
- peer = dc->getPeer();
+ peer->setPeer(dc);
}
- peer->setPeer(dc);
}
#if FULL_SYSTEM
-BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
- : Event(&mainEventQueue), cpu(_cpu), interval(_interval)
+BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, Tick _interval)
+ : cpu(_cpu), interval(_interval)
{ }
void
@@ -383,45 +393,21 @@ BaseCPU::ProfileEvent::process()
tc->profileSample();
}
- schedule(curTick + interval);
-}
-
-void
-BaseCPU::post_interrupt(int int_num, int index)
-{
- interrupts.post(int_num, index);
-}
-
-void
-BaseCPU::clear_interrupt(int int_num, int index)
-{
- interrupts.clear(int_num, index);
-}
-
-void
-BaseCPU::clear_interrupts()
-{
- interrupts.clear_all();
-}
-
-uint64_t
-BaseCPU::get_interrupts(int int_num)
-{
- return interrupts.get_vec(int_num);
+ cpu->schedule(this, curTick + interval);
}
void
BaseCPU::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(instCnt);
- interrupts.serialize(os);
+ interrupts->serialize(os);
}
void
BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(instCnt);
- interrupts.unserialize(cp, section);
+ interrupts->unserialize(cp, section);
}
#endif // FULL_SYSTEM
diff --git a/src/cpu/base.hh b/src/cpu/base.hh
index bdc7d7c8b..8af3295eb 100644
--- a/src/cpu/base.hh
+++ b/src/cpu/base.hh
@@ -35,6 +35,7 @@
#include <vector>
#include "arch/isa_traits.hh"
+#include "arch/microcode_rom.hh"
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "sim/eventq.hh"
@@ -45,6 +46,7 @@
#include "arch/interrupts.hh"
#endif
+class BaseCPUParams;
class BranchPred;
class CheckerCPU;
class ThreadContext;
@@ -64,7 +66,7 @@ class CPUProgressEvent : public Event
BaseCPU *cpu;
public:
- CPUProgressEvent(EventQueue *q, Tick ival, BaseCPU *_cpu);
+ CPUProgressEvent(BaseCPU *_cpu, Tick ival);
void process();
@@ -78,8 +80,16 @@ class BaseCPU : public MemObject
Tick clock;
// @todo remove me after debugging with legion done
Tick instCnt;
+ // every cpu has an id, put it in the base cpu
+ // Set at initialization, only time a cpuId might change is during a
+ // takeover (which should be done from within the BaseCPU anyway,
+ // therefore no setCpuId() method is provided
+ int _cpuId;
public:
+ /** Reads this CPU's ID. */
+ int cpuId() { return _cpuId; }
+
// Tick currentTick;
inline Tick frequency() const { return Clock::Frequency / clock; }
inline Tick ticks(int numCycles) const { return clock * numCycles; }
@@ -102,29 +112,54 @@ class BaseCPU : public MemObject
*/
Tick nextCycle(Tick begin_tick);
+ TheISA::MicrocodeRom microcodeRom;
+
#if FULL_SYSTEM
protected:
-// uint64_t interrupts[TheISA::NumInterruptLevels];
-// uint64_t intstatus;
- TheISA::Interrupts interrupts;
+ TheISA::Interrupts *interrupts;
public:
- virtual void post_interrupt(int int_num, int index);
- virtual void clear_interrupt(int int_num, int index);
- virtual void clear_interrupts();
- virtual uint64_t get_interrupts(int int_num);
+ TheISA::Interrupts *
+ getInterruptController()
+ {
+ return interrupts;
+ }
+
+ virtual void wakeup() = 0;
+
+ void
+ postInterrupt(int int_num, int index)
+ {
+ interrupts->post(int_num, index);
+ wakeup();
+ }
+
+ void
+ clearInterrupt(int int_num, int index)
+ {
+ interrupts->clear(int_num, index);
+ }
+
+ void
+ clearInterrupts()
+ {
+ interrupts->clearAll();
+ }
- bool check_interrupts(ThreadContext * tc) const
- { return interrupts.check_interrupts(tc); }
+ bool
+ checkInterrupts(ThreadContext *tc) const
+ {
+ return interrupts->checkInterrupts(tc);
+ }
class ProfileEvent : public Event
{
private:
BaseCPU *cpu;
- int interval;
+ Tick interval;
public:
- ProfileEvent(BaseCPU *cpu, int interval);
+ ProfileEvent(BaseCPU *cpu, Tick interval);
void process();
};
ProfileEvent *profileEvent;
@@ -162,40 +197,9 @@ class BaseCPU : public MemObject
ThreadContext *getContext(int tn) { return threadContexts[tn]; }
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;
- int cpu_id;
- Trace::InstTracer * tracer;
-
- Tick phase;
-#if FULL_SYSTEM
- Tick profile;
-
- bool do_statistics_insts;
- bool do_checkpoint_insts;
- bool do_quiesce;
-#endif
- Tick progress_interval;
- BaseCPU *checker;
-
- TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core
-
- Params();
- };
-
- const Params *params;
-
+ typedef BaseCPUParams Params;
+ const Params *params() const
+ { return reinterpret_cast<const Params *>(_params); }
BaseCPU(Params *params);
virtual ~BaseCPU();
@@ -221,6 +225,8 @@ class BaseCPU : public MemObject
*/
int number_of_threads;
+ TheISA::CoreSpecific coreParams; //ISA-Specific Params That Set Up State in Core
+
/**
* Vector of per-thread instruction-based event queues. Used for
* scheduling events based on number of instructions committed by
@@ -298,7 +304,7 @@ class BaseCPU : public MemObject
public:
// Number of CPU cycles simulated
- Stats::Scalar<> numCycles;
+ Stats::Scalar numCycles;
};
#endif // __CPU_BASE_HH__
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
index bea680fac..41c57cf39 100644
--- a/src/cpu/base_dyn_inst.hh
+++ b/src/cpu/base_dyn_inst.hh
@@ -77,8 +77,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
typedef typename std::list<DynInstPtr>::iterator ListIt;
enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
};
/** The StaticInst used by this BaseDynInst. */
@@ -115,9 +115,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
/**
* Does a write to a given address.
* @param data The data to be written.
@@ -130,9 +127,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
Fault write(T data, Addr addr, unsigned flags,
uint64_t *res);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
void prefetch(Addr addr, unsigned flags);
void writeHint(Addr addr, int size, unsigned flags);
Fault copySrcTranslate(Addr src);
@@ -258,9 +252,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
public:
- /** Count of total number of dynamic instructions. */
- static int instcount;
-
#ifdef DEBUG
void dumpSNList();
#endif
@@ -412,7 +403,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
void dump(std::string &outstring);
/** Read this CPU's ID. */
- int readCpuId() { return cpu->readCpuId(); }
+ int cpuId() { return cpu->cpuId(); }
+
+ /** Read this context's system-wide ID **/
+ int contextId() { return thread->contextId(); }
/** Returns the fault type. */
Fault getFault() { return fault; }
@@ -486,24 +480,24 @@ class BaseDynInst : public FastAlloc, public RefCounted
//
// Instruction types. Forward checks to StaticInst object.
//
- bool isNop() const { return staticInst->isNop(); }
- bool isMemRef() const { return staticInst->isMemRef(); }
- bool isLoad() const { return staticInst->isLoad(); }
- bool isStore() const { return staticInst->isStore(); }
+ bool isNop() const { return staticInst->isNop(); }
+ bool isMemRef() const { return staticInst->isMemRef(); }
+ bool isLoad() const { return staticInst->isLoad(); }
+ bool isStore() const { return staticInst->isStore(); }
bool isStoreConditional() const
{ return staticInst->isStoreConditional(); }
bool isInstPrefetch() const { return staticInst->isInstPrefetch(); }
bool isDataPrefetch() const { return staticInst->isDataPrefetch(); }
bool isCopy() const { return staticInst->isCopy(); }
- bool isInteger() const { return staticInst->isInteger(); }
- bool isFloating() const { return staticInst->isFloating(); }
- bool isControl() const { return staticInst->isControl(); }
- bool isCall() const { return staticInst->isCall(); }
- bool isReturn() const { return staticInst->isReturn(); }
- bool isDirectCtrl() const { return staticInst->isDirectCtrl(); }
+ bool isInteger() const { return staticInst->isInteger(); }
+ bool isFloating() const { return staticInst->isFloating(); }
+ bool isControl() const { return staticInst->isControl(); }
+ bool isCall() const { return staticInst->isCall(); }
+ bool isReturn() const { return staticInst->isReturn(); }
+ bool isDirectCtrl() const { return staticInst->isDirectCtrl(); }
bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); }
- bool isCondCtrl() const { return staticInst->isCondCtrl(); }
- bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
+ bool isCondCtrl() const { return staticInst->isCondCtrl(); }
+ bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); }
bool isThreadSync() const { return staticInst->isThreadSync(); }
bool isSerializing() const { return staticInst->isSerializing(); }
@@ -560,7 +554,7 @@ class BaseDynInst : public FastAlloc, public RefCounted
Addr branchTarget() const { return staticInst->branchTarget(PC); }
/** Returns the number of source registers. */
- int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
+ int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
/** Returns the number of destination registers. */
int8_t numDestRegs() const { return staticInst->numDestRegs(); }
@@ -857,29 +851,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
};
template<class Impl>
-Fault
-BaseDynInst<Impl>::translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, vaddr, size, flags, PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
-
- fault = cpu->translateDataReadReq(req, thread);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
-}
-
-template<class Impl>
template<class T>
inline Fault
BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
@@ -887,9 +858,9 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
reqMade = true;
Request *req = new Request();
req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
+ req->setThreadContext(thread->contextId(), threadNumber);
- fault = cpu->translateDataReadReq(req, thread);
+ fault = cpu->dtb->translateAtomic(req, thread->getTC(), false);
if (req->isUncacheable())
isUncacheable = true;
@@ -931,29 +902,6 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
}
template<class Impl>
-Fault
-BaseDynInst<Impl>::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- reqMade = true;
- Request *req = new Request();
- req->setVirt(asid, vaddr, size, flags, PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
-
- fault = cpu->translateDataWriteReq(req, thread);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
-}
-
-template<class Impl>
template<class T>
inline Fault
BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
@@ -966,9 +914,9 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
reqMade = true;
Request *req = new Request();
req->setVirt(asid, addr, sizeof(T), flags, this->PC);
- req->setThreadContext(thread->readCpuId(), threadNumber);
+ req->setThreadContext(thread->contextId(), threadNumber);
- fault = cpu->translateDataWriteReq(req, thread);
+ fault = cpu->dtb->translateAtomic(req, thread->getTC(), true);
if (req->isUncacheable())
isUncacheable = true;
diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh
index 5c18ae694..4ee7d2f2c 100644
--- a/src/cpu/base_dyn_inst_impl.hh
+++ b/src/cpu/base_dyn_inst_impl.hh
@@ -168,18 +168,21 @@ BaseDynInst<Impl>::initVars()
// Initialize the fault to be NoFault.
fault = NoFault;
- ++instcount;
+#ifndef NDEBUG
+ ++cpu->instcount;
- if (instcount > 1500) {
- cpu->dumpInsts();
+ if (cpu->instcount > 1500) {
#ifdef DEBUG
+ cpu->dumpInsts();
dumpSNList();
#endif
- assert(instcount <= 1500);
+ assert(cpu->instcount <= 1500);
}
- DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n",
- seqNum, instcount);
+ DPRINTF(DynInst,
+ "DynInst: [sn:%lli] Instruction created. Instcount for %s = %i\n",
+ seqNum, cpu->name(), cpu->instcount);
+#endif
#ifdef DEBUG
cpu->snList.insert(seqNum);
@@ -199,10 +202,13 @@ BaseDynInst<Impl>::~BaseDynInst()
fault = NoFault;
- --instcount;
+#ifndef NDEBUG
+ --cpu->instcount;
- DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n",
- seqNum, instcount);
+ DPRINTF(DynInst,
+ "DynInst: [sn:%lli] Instruction destroyed. Instcount for %s = %i\n",
+ seqNum, cpu->name(), cpu->instcount);
+#endif
#ifdef DEBUG
cpu->snList.erase(seqNum);
#endif
diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc
index a6af98d66..14777bc12 100644
--- a/src/cpu/checker/cpu.cc
+++ b/src/cpu/checker/cpu.cc
@@ -159,7 +159,7 @@ CheckerCPU::read(Addr addr, T &data, unsigned flags)
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
// translate to physical address
- translateDataReadReq(memReq);
+ dtb->translateAtomic(memReq, tc, false);
PacketPtr pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
@@ -229,7 +229,7 @@ CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
// translate to physical address
- thread->translateDataWriteReq(memReq);
+ dtb->translateAtomic(memReq, tc, true);
// Can compare the write data and result only if it's cacheable,
// not a store conditional, or is a store conditional that
@@ -325,57 +325,6 @@ CheckerCPU::dbg_vtophys(Addr addr)
#endif // FULL_SYSTEM
bool
-CheckerCPU::translateInstReq(Request *req)
-{
-#if FULL_SYSTEM
- return (thread->translateInstReq(req) == NoFault);
-#else
- thread->translateInstReq(req);
- return true;
-#endif
-}
-
-void
-CheckerCPU::translateDataReadReq(Request *req)
-{
- thread->translateDataReadReq(req);
-
- if (req->getVaddr() != unverifiedReq->getVaddr()) {
- warn("%lli: Request virtual addresses do not match! Inst: %#x, "
- "checker: %#x",
- curTick, unverifiedReq->getVaddr(), req->getVaddr());
- handleError();
- }
- req->setPaddr(unverifiedReq->getPaddr());
-
- if (checkFlags(req)) {
- warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
- curTick, unverifiedReq->getFlags(), req->getFlags());
- handleError();
- }
-}
-
-void
-CheckerCPU::translateDataWriteReq(Request *req)
-{
- thread->translateDataWriteReq(req);
-
- if (req->getVaddr() != unverifiedReq->getVaddr()) {
- warn("%lli: Request virtual addresses do not match! Inst: %#x, "
- "checker: %#x",
- curTick, unverifiedReq->getVaddr(), req->getVaddr());
- handleError();
- }
- req->setPaddr(unverifiedReq->getPaddr());
-
- if (checkFlags(req)) {
- warn("%lli: Request flags do not match! Inst: %#x, checker: %#x",
- curTick, unverifiedReq->getFlags(), req->getFlags());
- handleError();
- }
-}
-
-bool
CheckerCPU::checkFlags(Request *req)
{
// Remove any dynamic flags that don't have to do with the request itself.
diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh
index 35dc59ff4..0d3dddded 100644
--- a/src/cpu/checker/cpu.hh
+++ b/src/cpu/checker/cpu.hh
@@ -65,6 +65,7 @@ class Process;
#endif // FULL_SYSTEM
template <class>
class BaseDynInst;
+class CheckerCPUParams;
class ThreadContext;
class MemInterface;
class Checkpoint;
@@ -96,20 +97,10 @@ class CheckerCPU : public BaseCPU
public:
virtual void init();
- struct Params : public BaseCPU::Params
- {
-#if FULL_SYSTEM
- TheISA::ITB *itb;
- TheISA::DTB *dtb;
-#else
- Process *process;
-#endif
- bool exitOnError;
- bool updateOnError;
- bool warnOnlyOnLoadError;
- };
-
public:
+ typedef CheckerCPUParams Params;
+ const Params *params() const
+ { return reinterpret_cast<const Params *>(_params); }
CheckerCPU(Params *p);
virtual ~CheckerCPU();
@@ -189,7 +180,7 @@ class CheckerCPU : public BaseCPU
// 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"); }
+ Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
void prefetch(Addr addr, unsigned flags)
{
@@ -340,10 +331,6 @@ class CheckerCPU : public BaseCPU
this->dtb->demapPage(vaddr, asn);
}
- bool translateInstReq(Request *req);
- void translateDataWriteReq(Request *req);
- void translateDataReadReq(Request *req);
-
#if FULL_SYSTEM
Fault hwrei() { return thread->hwrei(); }
void ev5_trap(Fault fault) { fault->invoke(tc); }
diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh
index f3f8a0bb3..26571ed68 100644
--- a/src/cpu/checker/cpu_impl.hh
+++ b/src/cpu/checker/cpu_impl.hh
@@ -141,9 +141,9 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
// Try to fetch the instruction
#if FULL_SYSTEM
-#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
#else
-#define IFETCH_FLAGS(pc) 0
+#define IFETCH_FLAGS(pc) 0
#endif
uint64_t fetch_PC = thread->readPC() & ~3;
@@ -152,9 +152,10 @@ Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
memReq = new Request(inst->threadNumber, fetch_PC,
sizeof(uint32_t),
IFETCH_FLAGS(thread->readPC()),
- fetch_PC, thread->readCpuId(), inst->threadNumber);
+ fetch_PC, thread->contextId(),
+ inst->threadNumber);
- bool succeeded = translateInstReq(memReq);
+ bool succeeded = itb->translateAtomic(memReq, thread);
if (!succeeded) {
if (inst->getFault() == NoFault) {
diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh
index 15454c3fe..3c87f841f 100644
--- a/src/cpu/checker/thread_context.hh
+++ b/src/cpu/checker/thread_context.hh
@@ -82,7 +82,7 @@ class CheckerThreadContext : public ThreadContext
checkerTC->setCpuId(id);
}
- int readCpuId() { return actualTC->readCpuId(); }
+ int cpuId() { return actualTC->cpuId(); }
TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); }
@@ -98,10 +98,8 @@ class CheckerThreadContext : public ThreadContext
FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL)
+ VirtualPort *getVirtPort()
{ return actualTC->getVirtPort(); }
-
- void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); }
#else
TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
@@ -155,7 +153,7 @@ class CheckerThreadContext : public ThreadContext
void profileSample() { return actualTC->profileSample(); }
#endif
- int getThreadNum() { return actualTC->getThreadNum(); }
+ int threadId() { return actualTC->threadId(); }
// @todo: Do I need this?
MachInst getInst() { return actualTC->getInst(); }
@@ -279,29 +277,8 @@ class CheckerThreadContext : public ThreadContext
bool misspeculating() { return actualTC->misspeculating(); }
#if !FULL_SYSTEM
- IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- {
- checkerTC->setSyscallArg(i, val);
- actualTC->setSyscallArg(i, val);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- {
- checkerTC->setSyscallReturn(return_value);
- actualTC->setSyscallReturn(return_value);
- }
-
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
#endif
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- actualTC->changeRegFileContext(param, val);
- checkerTC->changeRegFileContext(param, val);
- }
};
#endif // __CPU_CHECKER_EXEC_CONTEXT_HH__
diff --git a/src/cpu/cpu_models.py b/src/cpu/cpu_models.py
index 5b0c6c4da..793f8c646 100644
--- a/src/cpu/cpu_models.py
+++ b/src/cpu/cpu_models.py
@@ -82,3 +82,6 @@ CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
CpuModel('O3CPU', 'o3_cpu_exec.cc',
'#include "cpu/o3/isa_specific.hh"',
{ 'CPU_exec_context': 'O3DynInst' })
+CpuModel('InOrderCPU', 'inorder_cpu_exec.cc',
+ '#include "cpu/inorder/inorder_dyn_inst.hh"',
+ { 'CPU_exec_context': 'InOrderDynInst' })
diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh
index 5816c6ca1..65f0e87e1 100644
--- a/src/cpu/cpuevent.hh
+++ b/src/cpu/cpuevent.hh
@@ -58,8 +58,8 @@ class CpuEvent : public Event
ThreadContext *tc;
public:
- CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri)
- : Event(q, p), tc(_tc)
+ CpuEvent(ThreadContext *_tc, Priority p = Default_Pri)
+ : Event(p), tc(_tc)
{ cpuEventList.push_back(this); }
/** delete the cpu event from the global list. */
@@ -81,9 +81,8 @@ class CpuEventWrapper : public CpuEvent
T *object;
public:
- CpuEventWrapper(T *obj, ThreadContext *_tc,
- EventQueue *q = &mainEventQueue, Priority p = Default_Pri)
- : CpuEvent(q, _tc, p), object(obj)
+ CpuEventWrapper(T *obj, ThreadContext *_tc, Priority p = Default_Pri)
+ : CpuEvent(_tc, p), object(obj)
{ }
void process() { (object->*F)(tc); }
};
diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc
index 0118dbde1..ea53fb6f5 100644
--- a/src/cpu/exetrace.cc
+++ b/src/cpu/exetrace.cc
@@ -46,12 +46,18 @@ using namespace TheISA;
namespace Trace {
void
-Trace::ExeTracerRecord::dump()
+ExeTracerRecord::dumpTicks(ostream &outs)
+{
+ ccprintf(outs, "%7d: ", when);
+}
+
+void
+Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran)
{
ostream &outs = Trace::output();
if (IsOn(ExecTicks))
- ccprintf(outs, "%7d: ", when);
+ dumpTicks(outs);
outs << thread->getCpuPtr()->name() << " ";
@@ -59,46 +65,59 @@ Trace::ExeTracerRecord::dump()
outs << (misspeculating ? "-" : "+") << " ";
if (IsOn(ExecThread))
- outs << "T" << thread->getThreadNum() << " : ";
-
+ outs << "T" << thread->threadId() << " : ";
std::string sym_str;
Addr sym_addr;
if (debugSymbolTable
&& IsOn(ExecSymbol)
+#if FULL_SYSTEM
+ && !inUserMode(thread)
+#endif
&& debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) {
if (PC != sym_addr)
sym_str += csprintf("+%d", PC - sym_addr);
- outs << "@" << sym_str << " : ";
+ outs << "@" << sym_str;
}
else {
- outs << "0x" << hex << PC << " : ";
+ outs << "0x" << hex << PC;
}
+ if (inst->isMicroop()) {
+ outs << "." << setw(2) << dec << upc;
+ } else {
+ outs << " ";
+ }
+
+ outs << " : ";
+
//
// Print decoded instruction
//
outs << setw(26) << left;
- outs << staticInst->disassemble(PC, debugSymbolTable);
- outs << " : ";
+ outs << inst->disassemble(PC, debugSymbolTable);
- if (IsOn(ExecOpClass)) {
- outs << Enums::OpClassStrings[staticInst->opClass()] << " : ";
- }
+ if (ran) {
+ outs << " : ";
- if (IsOn(ExecResult) && data_status != DataInvalid) {
- ccprintf(outs, " D=%#018x", data.as_int);
- }
+ if (IsOn(ExecOpClass)) {
+ outs << Enums::OpClassStrings[inst->opClass()] << " : ";
+ }
+
+ if (IsOn(ExecResult) && data_status != DataInvalid) {
+ ccprintf(outs, " D=%#018x", data.as_int);
+ }
- if (IsOn(ExecEffAddr) && addr_valid)
- outs << " A=0x" << hex << addr;
+ if (IsOn(ExecEffAddr) && addr_valid)
+ outs << " A=0x" << hex << addr;
- if (IsOn(ExecFetchSeq) && fetch_seq_valid)
- outs << " FetchSeq=" << dec << fetch_seq;
+ if (IsOn(ExecFetchSeq) && fetch_seq_valid)
+ outs << " FetchSeq=" << dec << fetch_seq;
- if (IsOn(ExecCPSeq) && cp_seq_valid)
- outs << " CPSeq=" << dec << cp_seq;
+ if (IsOn(ExecCPSeq) && cp_seq_valid)
+ outs << " CPSeq=" << dec << cp_seq;
+ }
//
// End of line...
@@ -106,6 +125,29 @@ Trace::ExeTracerRecord::dump()
outs << endl;
}
+void
+Trace::ExeTracerRecord::dump()
+{
+ /*
+ * The behavior this check tries to achieve is that if ExecMacro is on,
+ * the macroop will be printed. If it's on and microops are also on, it's
+ * printed before the microops start printing to give context. If the
+ * microops aren't printed, then it's printed only when the final microop
+ * finishes. Macroops then behave like regular instructions and don't
+ * complete/print when they fault.
+ */
+ if (IsOn(ExecMacro) && staticInst->isMicroop() &&
+ ((IsOn(ExecMicro) &&
+ macroStaticInst && staticInst->isFirstMicroop()) ||
+ (!IsOn(ExecMicro) &&
+ macroStaticInst && staticInst->isLastMicroop()))) {
+ traceInst(macroStaticInst, false);
+ }
+ if (IsOn(ExecMicro) || !staticInst->isMicroop()) {
+ traceInst(staticInst, true);
+ }
+}
+
/* namespace Trace */ }
////////////////////////////////////////////////////////////////////////
diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh
index 84660432b..e49a2bb59 100644
--- a/src/cpu/exetrace.hh
+++ b/src/cpu/exetrace.hh
@@ -47,12 +47,17 @@ class ExeTracerRecord : public InstRecord
{
public:
ExeTracerRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
+ void traceInst(StaticInstPtr inst, bool ran);
+
void dump();
+ virtual void dumpTicks(std::ostream &outs);
};
class ExeTracer : public InstTracer
@@ -64,7 +69,8 @@ class ExeTracer : public InstTracer
InstRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (!IsOn(ExecEnable))
return NULL;
@@ -76,7 +82,7 @@ class ExeTracer : public InstTracer
return NULL;
return new ExeTracerRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/inorder/InOrderCPU.py b/src/cpu/inorder/InOrderCPU.py
new file mode 100644
index 000000000..9faadc68c
--- /dev/null
+++ b/src/cpu/inorder/InOrderCPU.py
@@ -0,0 +1,79 @@
+# Copyright (c) 2007 MIPS Technologies, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from m5 import build_env
+from BaseCPU import BaseCPU
+
+class InOrderCPU(BaseCPU):
+ type = 'InOrderCPU'
+ activity = Param.Unsigned(0, "Initial count")
+
+ cachePorts = Param.Unsigned(2, "Cache Ports")
+ stageWidth = Param.Unsigned(1, "Stage width")
+
+ fetchMemPort = Param.String("icache_port" , "Name of Memory Port to get instructions from")
+ dataMemPort = Param.String("dcache_port" , "Name of Memory Port to get data from")
+ icache_port = Port("Instruction Port")
+ dcache_port = Port("Data Port")
+ _mem_ports = ['icache_port', 'dcache_port']
+
+ predType = Param.String("tournament", "Branch predictor type ('local', 'tournament')")
+ localPredictorSize = Param.Unsigned(2048, "Size of local predictor")
+ localCtrBits = Param.Unsigned(2, "Bits per counter")
+ localHistoryTableSize = Param.Unsigned(2048, "Size of local history table")
+ localHistoryBits = Param.Unsigned(11, "Bits for the local history")
+ globalPredictorSize = Param.Unsigned(8192, "Size of global predictor")
+ globalCtrBits = Param.Unsigned(2, "Bits per counter")
+ globalHistoryBits = Param.Unsigned(13, "Bits of history")
+ choicePredictorSize = Param.Unsigned(8192, "Size of choice predictor")
+ choiceCtrBits = Param.Unsigned(2, "Bits of choice counters")
+
+ BTBEntries = Param.Unsigned(4096, "Number of BTB entries")
+ BTBTagSize = Param.Unsigned(16, "Size of the BTB tags, in bits")
+
+ RASSize = Param.Unsigned(16, "RAS size")
+
+ instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
+ functionTrace = Param.Bool(False, "Enable function trace")
+ functionTraceStart = Param.Tick(0, "Cycle to start function trace")
+ stageTracing = Param.Bool(False, "Enable tracing of each stage in CPU")
+
+ memBlockSize = Param.Unsigned(64, "Memory Block Size")
+
+ multLatency = Param.Unsigned(1, "Latency for Multiply Operations")
+ multRepeatRate = Param.Unsigned(1, "Repeat Rate for Multiply Operations")
+ div8Latency = Param.Unsigned(1, "Latency for 8-bit Divide Operations")
+ div8RepeatRate = Param.Unsigned(1, "Repeat Rate for 8-bit Divide Operations")
+ div16Latency = Param.Unsigned(1, "Latency for 16-bit Divide Operations")
+ div16RepeatRate = Param.Unsigned(1, "Repeat Rate for 16-bit Divide Operations")
+ div24Latency = Param.Unsigned(1, "Latency for 24-bit Divide Operations")
+ div24RepeatRate = Param.Unsigned(1, "Repeat Rate for 24-bit Divide Operations")
+ div32Latency = Param.Unsigned(1, "Latency for 32-bit Divide Operations")
+ div32RepeatRate = Param.Unsigned(1, "Repeat Rate for 32-bit Divide Operations")
diff --git a/src/cpu/inorder/InOrderTrace.py b/src/cpu/inorder/InOrderTrace.py
new file mode 100644
index 000000000..3453fa675
--- /dev/null
+++ b/src/cpu/inorder/InOrderTrace.py
@@ -0,0 +1,35 @@
+# Copyright (c) 2007 MIPS Technologies, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+from m5.params import *
+from InstTracer import InstTracer
+
+class InOrderTrace(InstTracer):
+ type = 'InOrderTrace'
+ cxx_class = 'Trace::InOrderTrace'
diff --git a/src/cpu/inorder/SConscript b/src/cpu/inorder/SConscript
new file mode 100644
index 000000000..af237a777
--- /dev/null
+++ b/src/cpu/inorder/SConscript
@@ -0,0 +1,90 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2007 MIPS Technologies, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+Import('*')
+
+if 'InOrderCPU' in env['CPU_MODELS']:
+ SimObject('InOrderCPU.py')
+ SimObject('InOrderTrace.py')
+
+ TraceFlag('ResReqCount')
+ TraceFlag('FreeList')
+ TraceFlag('InOrderStage')
+ TraceFlag('InOrderStall')
+ TraceFlag('InOrderCPU')
+ TraceFlag('RegDepMap')
+ TraceFlag('InOrderDynInst')
+ TraceFlag('Resource')
+ TraceFlag('InOrderAGEN')
+ TraceFlag('InOrderFetchSeq')
+ TraceFlag('InOrderTLB')
+ TraceFlag('InOrderCachePort')
+ TraceFlag('InOrderBPred')
+ TraceFlag('InOrderDecode')
+ TraceFlag('InOrderExecute')
+ TraceFlag('InOrderInstBuffer')
+ TraceFlag('InOrderUseDef')
+ TraceFlag('InOrderMDU')
+ TraceFlag('InOrderGraduation')
+ TraceFlag('RefCount')
+
+ CompoundFlag('InOrderCPUAll', [ 'InOrderStage', 'InOrderStall', 'InOrderCPU',
+ 'InOrderMDU', 'InOrderAGEN', 'InOrderFetchSeq', 'InOrderTLB', 'InOrderBPred',
+ 'InOrderDecode', 'InOrderExecute', 'InOrderInstBuffer', 'InOrderUseDef',
+ 'InOrderGraduation', 'InOrderCachePort', 'RegDepMap', 'Resource'])
+
+ Source('pipeline_traits.cc')
+ Source('inorder_dyn_inst.cc')
+ Source('inorder_cpu_builder.cc')
+ Source('inorder_trace.cc')
+ Source('pipeline_stage.cc')
+ Source('first_stage.cc')
+ Source('resource.cc')
+ Source('resources/agen_unit.cc')
+ Source('resources/execution_unit.cc')
+ Source('resources/bpred_unit.cc')
+ Source('resources/branch_predictor.cc')
+ Source('resources/cache_unit.cc')
+ Source('resources/use_def.cc')
+ Source('resources/decode_unit.cc')
+ Source('resources/inst_buffer.cc')
+ Source('resources/graduation_unit.cc')
+ Source('resources/tlb_unit.cc')
+ Source('resources/fetch_seq_unit.cc')
+ Source('resources/mult_div_unit.cc')
+ Source('resource_pool.cc')
+ Source('reg_dep_map.cc')
+ Source('../o3/btb.cc')
+ Source('../o3/tournament_pred.cc')
+ Source('../o3/2bit_local_pred.cc')
+ Source('../o3/ras.cc')
+ Source('thread_context.cc')
+ Source('cpu.cc')
+
diff --git a/src/cpu/inorder/SConsopts b/src/cpu/inorder/SConsopts
new file mode 100644
index 000000000..82ebd18ea
--- /dev/null
+++ b/src/cpu/inorder/SConsopts
@@ -0,0 +1,33 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2007 MIPS Technologies, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+Import('*')
+
+all_cpu_list.append('InOrderCPU')
diff --git a/src/cpu/inorder/comm.hh b/src/cpu/inorder/comm.hh
new file mode 100644
index 000000000..18bb24169
--- /dev/null
+++ b/src/cpu/inorder/comm.hh
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_COMM_HH__
+#define __CPU_INORDER_COMM_HH__
+
+#include <vector>
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inst_seq.hh"
+#include "sim/host.hh"
+
+/** Struct that defines the information passed from in between stages */
+/** This information mainly goes forward through the pipeline. */
+struct InterStageStruct {
+ int size;
+ ThePipeline::DynInstPtr insts[ThePipeline::StageWidth];
+ bool squash;
+ bool branchMispredict;
+ bool branchTaken;
+ uint64_t mispredPC;
+ uint64_t nextPC;
+ InstSeqNum squashedSeqNum;
+ bool includeSquashInst;
+
+ InterStageStruct()
+ :size(0), squash(false),
+ branchMispredict(false), branchTaken(false),
+ mispredPC(0), nextPC(0),
+ squashedSeqNum(0), includeSquashInst(false)
+ { }
+
+};
+
+/** Turn This into a Class */
+/** Struct that defines all backwards communication. */
+struct TimeStruct {
+ struct stageComm {
+ bool squash;
+ bool predIncorrect;
+ uint64_t branchAddr;
+
+ // @todo: Might want to package this kind of branch stuff into a single
+ // struct as it is used pretty frequently.
+ bool branchMispredict;
+ bool branchTaken;
+ uint64_t mispredPC;
+ uint64_t nextPC;
+
+ unsigned branchCount;
+
+ // Represents the instruction that has either been retired or
+ // squashed. Similar to having a single bus that broadcasts the
+ // retired or squashed sequence number.
+ InstSeqNum doneSeqNum;
+ InstSeqNum bdelayDoneSeqNum;
+ bool squashDelaySlot;
+
+ //Just in case we want to do a commit/squash on a cycle
+ //(necessary for multiple ROBs?)
+ bool commitInsts;
+ InstSeqNum squashSeqNum;
+
+ // Communication specifically to the IQ to tell the IQ that it can
+ // schedule a non-speculative instruction.
+ InstSeqNum nonSpecSeqNum;
+
+ bool uncached;
+ ThePipeline::DynInstPtr uncachedLoad;
+
+ bool interruptPending;
+ bool clearInterrupt;
+ };
+
+ stageComm stageInfo[ThePipeline::NumStages][ThePipeline::MaxThreads];
+
+ bool stageBlock[ThePipeline::NumStages][ThePipeline::MaxThreads];
+ bool stageUnblock[ThePipeline::NumStages][ThePipeline::MaxThreads];
+};
+
+#endif //__CPU_INORDER_COMM_HH__
diff --git a/src/cpu/inorder/cpu.cc b/src/cpu/inorder/cpu.cc
new file mode 100644
index 000000000..70877aae4
--- /dev/null
+++ b/src/cpu/inorder/cpu.cc
@@ -0,0 +1,1253 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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/utility.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/activity.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/thread_context.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/cpu.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "mem/translating_port.hh"
+#include "sim/process.hh"
+#include "sim/stat_control.hh"
+#include <algorithm>
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InOrderCPU::TickEvent::TickEvent(InOrderCPU *c)
+ : Event(CPU_Tick_Pri), cpu(c)
+{ }
+
+
+void
+InOrderCPU::TickEvent::process()
+{
+ cpu->tick();
+}
+
+
+const char *
+InOrderCPU::TickEvent::description()
+{
+ return "InOrderCPU tick event";
+}
+
+InOrderCPU::CPUEvent::CPUEvent(InOrderCPU *_cpu, CPUEventType e_type,
+ Fault fault, unsigned _tid, unsigned _vpe)
+ : Event(CPU_Tick_Pri), cpu(_cpu)
+{
+ setEvent(e_type, fault, _tid, _vpe);
+}
+
+void
+InOrderCPU::CPUEvent::process()
+{
+ switch (cpuEventType)
+ {
+ case ActivateThread:
+ cpu->activateThread(tid);
+ break;
+
+ //@TODO: Consider Implementing "Suspend Thread" as Separate from Deallocate
+ case SuspendThread: // Suspend & Deallocate are same for now.
+ //cpu->suspendThread(tid);
+ //break;
+ case DeallocateThread:
+ cpu->deallocateThread(tid);
+ break;
+
+ case EnableVPEs:
+ cpu->enableVPEs(vpe);
+ break;
+
+ case DisableVPEs:
+ cpu->disableVPEs(tid, vpe);
+ break;
+
+ case EnableThreads:
+ cpu->enableThreads(vpe);
+ break;
+
+ case DisableThreads:
+ cpu->disableThreads(tid, vpe);
+ break;
+
+ case Trap:
+ cpu->trapCPU(fault, tid);
+ break;
+
+ default:
+ fatal("Unrecognized Event Type %d", cpuEventType);
+ }
+
+ cpu->cpuEventRemoveList.push(this);
+}
+
+const char *
+InOrderCPU::CPUEvent::description()
+{
+ return "InOrderCPU event";
+}
+
+void
+InOrderCPU::CPUEvent::scheduleEvent(int delay)
+{
+ if (squashed())
+ mainEventQueue.reschedule(this,curTick + cpu->ticks(delay));
+ else if (!scheduled())
+ mainEventQueue.schedule(this,curTick + cpu->ticks(delay));
+}
+
+void
+InOrderCPU::CPUEvent::unscheduleEvent()
+{
+ if (scheduled())
+ squash();
+}
+
+InOrderCPU::InOrderCPU(Params *params)
+ : BaseCPU(params),
+ cpu_id(params->cpu_id),
+ coreType("default"),
+ _status(Idle),
+ tickEvent(this),
+ miscRegFile(this),
+ timeBuffer(2 , 2),
+ removeInstsThisCycle(false),
+ activityRec(params->name, NumStages, 10, params->activity),
+ switchCount(0),
+ deferRegistration(false/*params->deferRegistration*/),
+ stageTracing(params->stageTracing),
+ numThreads(params->numThreads),
+ numVirtProcs(1)
+{
+ cpu_params = params;
+
+ resPool = new ResourcePool(this, params);
+
+ // Resize for Multithreading CPUs
+ thread.resize(numThreads);
+
+ int active_threads = params->workload.size();
+
+ if (active_threads > MaxThreads) {
+ panic("Workload Size too large. Increase the 'MaxThreads'"
+ "in your InOrder implementation or "
+ "edit your workload size.");
+ }
+
+ // Bind the fetch & data ports from the resource pool.
+ fetchPortIdx = resPool->getPortIdx(params->fetchMemPort);
+ if (fetchPortIdx == 0) {
+ warn("Unable to find port to fetch instructions from.\n");
+ }
+
+ dataPortIdx = resPool->getPortIdx(params->dataMemPort);
+ if (dataPortIdx == 0) {
+ warn("Unable to find port for data.\n");
+ }
+
+
+ for (int i = 0; i < numThreads; ++i) {
+ if (i < params->workload.size()) {
+ DPRINTF(InOrderCPU, "Workload[%i] process is %#x\n",
+ i, this->thread[i]);
+ this->thread[i] = new Thread(this, i, params->workload[i],
+ i);
+
+ // Start thread's off in "Suspended" status
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+
+ } else {
+ //Allocate Empty thread so M5 can use later
+ //when scheduling threads to CPU
+ Process* dummy_proc = params->workload[0];
+ this->thread[i] = new Thread(this, i, dummy_proc, i);
+ }
+
+ // Setup the TC that will serve as the interface to the threads/CPU.
+ InOrderThreadContext *tc = new InOrderThreadContext;
+ tc->cpu = this;
+ tc->thread = this->thread[i];
+
+ // Give the thread the TC.
+ thread[i]->tc = tc;
+ thread[i]->setFuncExeInst(0);
+ globalSeqNum[i] = 1;
+
+ // Add the TC to the CPU's list of TC's.
+ this->threadContexts.push_back(tc);
+ }
+
+ // Initialize TimeBuffer Stage Queues
+ for (int stNum=0; stNum < NumStages - 1; stNum++) {
+ stageQueue[stNum] = new StageQueue(NumStages, NumStages);
+ stageQueue[stNum]->id(stNum);
+ }
+
+
+ // Set Up Pipeline Stages
+ for (int stNum=0; stNum < NumStages; stNum++) {
+ if (stNum == 0)
+ pipelineStage[stNum] = new FirstStage(params, stNum);
+ else
+ pipelineStage[stNum] = new PipelineStage(params, stNum);
+
+ pipelineStage[stNum]->setCPU(this);
+ pipelineStage[stNum]->setActiveThreads(&activeThreads);
+ pipelineStage[stNum]->setTimeBuffer(&timeBuffer);
+
+ // Take Care of 1st/Nth stages
+ if (stNum > 0)
+ pipelineStage[stNum]->setPrevStageQueue(stageQueue[stNum - 1]);
+ if (stNum < NumStages - 1)
+ pipelineStage[stNum]->setNextStageQueue(stageQueue[stNum]);
+ }
+
+ // Initialize thread specific variables
+ for (int tid=0; tid < numThreads; tid++) {
+ archRegDepMap[tid].setCPU(this);
+
+ nonSpecInstActive[tid] = false;
+ nonSpecSeqNum[tid] = 0;
+
+ squashSeqNum[tid] = MaxAddr;
+ lastSquashCycle[tid] = 0;
+
+ intRegFile[tid].clear();
+ floatRegFile[tid].clear();
+ }
+
+ // Update miscRegFile if necessary
+ if (numThreads > 1) {
+ miscRegFile.expandForMultithreading(numThreads, numVirtProcs);
+ }
+
+ miscRegFile.clear();
+
+ lastRunningCycle = curTick;
+ contextSwitch = false;
+
+ // Define dummy instructions and resource requests to be used.
+ DynInstPtr dummyBufferInst = new InOrderDynInst(this, NULL, 0, 0);
+ dummyReq = new ResourceRequest(NULL, NULL, 0, 0, 0, 0);
+
+ // Reset CPU to reset state.
+#if FULL_SYSTEM
+ Fault resetFault = new ResetFault();
+ resetFault->invoke(tcBase());
+#else
+ reset();
+#endif
+
+ // Schedule First Tick Event, CPU will reschedule itself from here on out.
+ scheduleTickEvent(0);
+}
+
+
+void
+InOrderCPU::regStats()
+{
+ /* Register the Resource Pool's stats here.*/
+ resPool->regStats();
+
+ /* Register any of the InOrderCPU'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);
+
+ threadCycles
+ .init(numThreads)
+ .name(name() + ".threadCycles")
+ .desc("Total Number of Cycles A Thread Was Active in CPU (Per-Thread)");
+
+ smtCycles
+ .name(name() + ".smtCycles")
+ .desc("Total number of cycles that the CPU was simultaneous multithreading.(SMT)");
+
+ committedInsts
+ .init(numThreads)
+ .name(name() + ".committedInsts")
+ .desc("Number of Instructions Simulated (Per-Thread)");
+
+ smtCommittedInsts
+ .init(numThreads)
+ .name(name() + ".smtCommittedInsts")
+ .desc("Number of SMT Instructions Simulated (Per-Thread)");
+
+ totalCommittedInsts
+ .name(name() + ".committedInsts_total")
+ .desc("Number of Instructions Simulated (Total)");
+
+ cpi
+ .name(name() + ".cpi")
+ .desc("CPI: Cycles Per Instruction (Per-Thread)")
+ .precision(6);
+ cpi = threadCycles / committedInsts;
+
+ smtCpi
+ .name(name() + ".smt_cpi")
+ .desc("CPI: Total SMT-CPI")
+ .precision(6);
+ smtCpi = smtCycles / smtCommittedInsts;
+
+ totalCpi
+ .name(name() + ".cpi_total")
+ .desc("CPI: Total CPI of All Threads")
+ .precision(6);
+ totalCpi = numCycles / totalCommittedInsts;
+
+ ipc
+ .name(name() + ".ipc")
+ .desc("IPC: Instructions Per Cycle (Per-Thread)")
+ .precision(6);
+ ipc = committedInsts / threadCycles;
+
+ smtIpc
+ .name(name() + ".smt_ipc")
+ .desc("IPC: Total SMT-IPC")
+ .precision(6);
+ smtIpc = smtCommittedInsts / smtCycles;
+
+ totalIpc
+ .name(name() + ".ipc_total")
+ .desc("IPC: Total IPC of All Threads")
+ .precision(6);
+ totalIpc = totalCommittedInsts / numCycles;
+
+ BaseCPU::regStats();
+}
+
+
+void
+InOrderCPU::tick()
+{
+ DPRINTF(InOrderCPU, "\n\nInOrderCPU: Ticking main, InOrderCPU.\n");
+
+ ++numCycles;
+
+ //Tick each of the stages
+ for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
+ pipelineStage[stNum]->tick();
+ }
+
+ // Now advance the time buffers one tick
+ timeBuffer.advance();
+ for (int sqNum=0; sqNum < NumStages - 1; sqNum++) {
+ stageQueue[sqNum]->advance();
+ }
+ activityRec.advance();
+
+ // Any squashed requests, events, or insts then remove them now
+ cleanUpRemovedReqs();
+ cleanUpRemovedEvents();
+ cleanUpRemovedInsts();
+
+ // Re-schedule CPU for this cycle
+ if (!tickEvent.scheduled()) {
+ if (_status == SwitchedOut) {
+ // increment stat
+ lastRunningCycle = curTick;
+ } else if (!activityRec.active()) {
+ DPRINTF(InOrderCPU, "sleeping CPU.\n");
+ lastRunningCycle = curTick;
+ timesIdled++;
+ } else {
+ //Tick next_tick = curTick + cycles(1);
+ //tickEvent.schedule(next_tick);
+ mainEventQueue.schedule(&tickEvent, nextCycle(curTick + 1));
+ DPRINTF(InOrderCPU, "Scheduled CPU for next tick @ %i.\n", nextCycle() + curTick);
+ }
+ }
+
+ tickThreadStats();
+ updateThreadPriority();
+}
+
+
+void
+InOrderCPU::init()
+{
+ if (!deferRegistration) {
+ registerThreadContexts();
+ }
+
+ // 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++) {
+
+ ThreadContext *src_tc = thread[tid]->getTC();
+
+ // Threads start in the Suspended State
+ if (src_tc->status() != ThreadContext::Suspended) {
+ continue;
+ }
+
+ }
+
+ // Clear inSyscall.
+ for (int i = 0; i < number_of_threads; ++i)
+ thread[i]->inSyscall = false;
+
+ // Call Initializiation Routine for Resource Pool
+ resPool->init();
+}
+
+void
+InOrderCPU::readFunctional(Addr addr, uint32_t &buffer)
+{
+ tcBase()->getMemPort()->readBlob(addr, (uint8_t*)&buffer, sizeof(uint32_t));
+ buffer = gtoh(buffer);
+}
+
+void
+InOrderCPU::reset()
+{
+ miscRegFile.reset(coreType, numThreads, numVirtProcs, dynamic_cast<BaseCPU*>(this));
+}
+
+Port*
+InOrderCPU::getPort(const std::string &if_name, int idx)
+{
+ return resPool->getPort(if_name, idx);
+}
+
+void
+InOrderCPU::trap(Fault fault, unsigned tid, int delay)
+{
+ scheduleCpuEvent(Trap, fault, tid, 0/*vpe*/, delay);
+}
+
+void
+InOrderCPU::trapCPU(Fault fault, unsigned tid)
+{
+ fault->invoke(tcBase(tid));
+}
+
+void
+InOrderCPU::scheduleCpuEvent(CPUEventType c_event, Fault fault,
+ unsigned tid, unsigned vpe, unsigned delay)
+{
+ CPUEvent *cpu_event = new CPUEvent(this, c_event, fault, tid, vpe);
+
+ if (delay >= 0) {
+ DPRINTF(InOrderCPU, "Scheduling CPU Event Type #%i for cycle %i.\n",
+ c_event, curTick + delay);
+ mainEventQueue.schedule(cpu_event,curTick + delay);
+ } else {
+ cpu_event->process();
+ cpuEventRemoveList.push(cpu_event);
+ }
+
+ // Broadcast event to the Resource Pool
+ DynInstPtr dummy_inst = new InOrderDynInst(this, NULL, getNextEventNum(), tid);
+ resPool->scheduleEvent(c_event, dummy_inst, 0, 0, tid);
+}
+
+inline bool
+InOrderCPU::isThreadActive(unsigned tid)
+{
+ list<unsigned>::iterator isActive = std::find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ return (isActive != activeThreads.end());
+}
+
+
+void
+InOrderCPU::activateThread(unsigned tid)
+{
+ if (!isThreadActive(tid)) {
+ DPRINTF(InOrderCPU, "Adding Thread %i to active threads list in CPU.\n",
+ tid);
+ activeThreads.push_back(tid);
+
+ wakeCPU();
+ }
+}
+
+void
+InOrderCPU::deactivateThread(unsigned tid)
+{
+ DPRINTF(InOrderCPU, "[tid:%i]: Calling deactivate thread.\n", tid);
+
+ if (isThreadActive(tid)) {
+ DPRINTF(InOrderCPU,"[tid:%i]: Removing from active threads list\n",
+ tid);
+ list<unsigned>::iterator thread_it = std::find(activeThreads.begin(),
+ activeThreads.end(), tid);
+
+ removePipelineStalls(*thread_it);
+
+ //@TODO: change stage status' to Idle?
+
+ activeThreads.erase(thread_it);
+ }
+}
+
+void
+InOrderCPU::removePipelineStalls(unsigned tid)
+{
+ DPRINTF(InOrderCPU,"[tid:%i]: Removing all pipeline stalls\n",
+ tid);
+
+ for (int stNum = 0; stNum < NumStages ; stNum++) {
+ pipelineStage[stNum]->removeStalls(tid);
+ }
+
+}
+bool
+InOrderCPU::isThreadInCPU(unsigned tid)
+{
+ list<unsigned>::iterator isCurrent = std::find(
+ currentThreads.begin(), currentThreads.end(), tid);
+
+ return (isCurrent != currentThreads.end());
+}
+
+void
+InOrderCPU::addToCurrentThreads(unsigned tid)
+{
+ if (!isThreadInCPU(tid)) {
+ DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n",
+ tid);
+ currentThreads.push_back(tid);
+ }
+}
+
+void
+InOrderCPU::removeFromCurrentThreads(unsigned tid)
+{
+ if (isThreadInCPU(tid)) {
+ DPRINTF(InOrderCPU, "Adding Thread %i to current threads list in CPU.\n",
+ tid);
+ list<unsigned>::iterator isCurrent = std::find(
+ currentThreads.begin(), currentThreads.end(), tid);
+ currentThreads.erase(isCurrent);
+ }
+}
+
+bool
+InOrderCPU::isThreadSuspended(unsigned tid)
+{
+ list<unsigned>::iterator isSuspended = std::find(
+ suspendedThreads.begin(), suspendedThreads.end(), tid);
+
+ return (isSuspended!= suspendedThreads.end());
+}
+
+void
+InOrderCPU::enableVirtProcElement(unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling "
+ "Enabling of concurrent virtual processor execution",
+ vpe);
+
+ scheduleCpuEvent(EnableVPEs, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::enableVPEs(unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Concurrent Execution "
+ "virtual processors %i", vpe);
+
+ list<unsigned>::iterator thread_it = currentThreads.begin();
+
+ while (thread_it != currentThreads.end()) {
+ if (!isThreadSuspended(*thread_it)) {
+ activateThread(*thread_it);
+ }
+ thread_it++;
+ }
+}
+
+void
+InOrderCPU::disableVirtProcElement(unsigned tid, unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling "
+ "Disabling of concurrent virtual processor execution",
+ vpe);
+
+ scheduleCpuEvent(DisableVPEs, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::disableVPEs(unsigned tid, unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[vpe:%i]: Disabling Concurrent Execution of "
+ "virtual processors %i", vpe);
+
+ unsigned base_vpe = TheISA::getVirtProcNum(tcBase(tid));
+
+ list<unsigned>::iterator thread_it = activeThreads.begin();
+
+ std::vector<list<unsigned>::iterator> removeList;
+
+ while (thread_it != activeThreads.end()) {
+ if (base_vpe != vpe) {
+ removeList.push_back(thread_it);
+ }
+ thread_it++;
+ }
+
+ for (int i = 0; i < removeList.size(); i++) {
+ activeThreads.erase(removeList[i]);
+ }
+}
+
+void
+InOrderCPU::enableMultiThreading(unsigned vpe)
+{
+ // Schedule event to take place at end of cycle
+ DPRINTF(InOrderCPU, "[vpe:%i]: Scheduling Enable Multithreading on "
+ "virtual processor %i", vpe);
+
+ scheduleCpuEvent(EnableThreads, NoFault, 0/*tid*/, vpe);
+}
+
+void
+InOrderCPU::enableThreads(unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[vpe:%i]: Enabling Multithreading on "
+ "virtual processor %i", vpe);
+
+ list<unsigned>::iterator thread_it = currentThreads.begin();
+
+ while (thread_it != currentThreads.end()) {
+ if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
+ if (!isThreadSuspended(*thread_it)) {
+ activateThread(*thread_it);
+ }
+ }
+ thread_it++;
+ }
+}
+void
+InOrderCPU::disableMultiThreading(unsigned tid, unsigned vpe)
+{
+ // Schedule event to take place at end of cycle
+ DPRINTF(InOrderCPU, "[tid:%i]: Scheduling Disable Multithreading on "
+ "virtual processor %i", tid, vpe);
+
+ scheduleCpuEvent(DisableThreads, NoFault, tid, vpe);
+}
+
+void
+InOrderCPU::disableThreads(unsigned tid, unsigned vpe)
+{
+ DPRINTF(InOrderCPU, "[tid:%i]: Disabling Multithreading on "
+ "virtual processor %i", tid, vpe);
+
+ list<unsigned>::iterator thread_it = activeThreads.begin();
+
+ std::vector<list<unsigned>::iterator> removeList;
+
+ while (thread_it != activeThreads.end()) {
+ if (TheISA::getVirtProcNum(tcBase(*thread_it)) == vpe) {
+ removeList.push_back(thread_it);
+ }
+ thread_it++;
+ }
+
+ for (int i = 0; i < removeList.size(); i++) {
+ activeThreads.erase(removeList[i]);
+ }
+}
+
+void
+InOrderCPU::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);
+ }
+}
+
+inline void
+InOrderCPU::tickThreadStats()
+{
+ /** Keep track of cycles that each thread is active */
+ list<unsigned>::iterator thread_it = activeThreads.begin();
+ while (thread_it != activeThreads.end()) {
+ threadCycles[*thread_it]++;
+ thread_it++;
+ }
+
+ // Keep track of cycles where SMT is active
+ if (activeThreads.size() > 1) {
+ smtCycles++;
+ }
+}
+
+void
+InOrderCPU::activateContext(unsigned tid, int delay)
+{
+ DPRINTF(InOrderCPU,"[tid:%i]: Activating ...\n", tid);
+
+ scheduleCpuEvent(ActivateThread, NoFault, tid, 0/*vpe*/, delay);
+
+ // Be sure to signal that there's some activity so the CPU doesn't
+ // deschedule itself.
+ activityRec.activity();
+
+ _status = Running;
+}
+
+
+void
+InOrderCPU::suspendContext(unsigned tid, int delay)
+{
+ scheduleCpuEvent(SuspendThread, NoFault, tid, 0/*vpe*/, delay);
+ //_status = Idle;
+}
+
+void
+InOrderCPU::suspendThread(unsigned tid)
+{
+ DPRINTF(InOrderCPU,"[tid: %i]: Suspended ...\n", tid);
+ deactivateThread(tid);
+}
+
+void
+InOrderCPU::deallocateContext(unsigned tid, int delay)
+{
+ scheduleCpuEvent(DeallocateThread, NoFault, tid, 0/*vpe*/, delay);
+}
+
+void
+InOrderCPU::deallocateThread(unsigned tid)
+{
+ DPRINTF(InOrderCPU,"[tid:%i]: Deallocating ...", tid);
+
+ removeFromCurrentThreads(tid);
+
+ deactivateThread(tid);
+
+ squashThreadInPipeline(tid);
+}
+
+void
+InOrderCPU::squashThreadInPipeline(unsigned tid)
+{
+ //Squash all instructions in each stage
+ for (int stNum=NumStages - 1; stNum >= 0 ; stNum--) {
+ pipelineStage[stNum]->squash(0 /*seq_num*/, tid);
+ }
+}
+
+void
+InOrderCPU::haltContext(unsigned tid, int delay)
+{
+ DPRINTF(InOrderCPU, "[tid:%i]: Halt context called.\n", tid);
+
+ // Halt is same thing as deallocate for now
+ // @TODO: Differentiate between halt & deallocate in the CPU
+ // model
+ deallocateContext(tid, delay);
+}
+
+void
+InOrderCPU::insertThread(unsigned tid)
+{
+ panic("Unimplemented Function\n.");
+}
+
+void
+InOrderCPU::removeThread(unsigned tid)
+{
+ DPRINTF(InOrderCPU, "Removing Thread %i from CPU.\n", tid);
+
+ /** Broadcast to CPU resources*/
+}
+
+void
+InOrderCPU::activateWhenReady(int tid)
+{
+ panic("Unimplemented Function\n.");
+}
+
+
+uint64_t
+InOrderCPU::readPC(unsigned tid)
+{
+ return PC[tid];
+}
+
+
+void
+InOrderCPU::setPC(Addr new_PC, unsigned tid)
+{
+ PC[tid] = new_PC;
+}
+
+
+uint64_t
+InOrderCPU::readNextPC(unsigned tid)
+{
+ return nextPC[tid];
+}
+
+
+void
+InOrderCPU::setNextPC(uint64_t new_NPC, unsigned tid)
+{
+ nextPC[tid] = new_NPC;
+}
+
+
+uint64_t
+InOrderCPU::readNextNPC(unsigned tid)
+{
+ return nextNPC[tid];
+}
+
+
+void
+InOrderCPU::setNextNPC(uint64_t new_NNPC, unsigned tid)
+{
+ nextNPC[tid] = new_NNPC;
+}
+
+uint64_t
+InOrderCPU::readIntReg(int reg_idx, unsigned tid)
+{
+ return intRegFile[tid].readReg(reg_idx);
+}
+
+FloatReg
+InOrderCPU::readFloatReg(int reg_idx, unsigned tid, int width)
+{
+
+ return floatRegFile[tid].readReg(reg_idx, width);
+}
+
+FloatRegBits
+InOrderCPU::readFloatRegBits(int reg_idx, unsigned tid, int width)
+{;
+ return floatRegFile[tid].readRegBits(reg_idx, width);
+}
+
+void
+InOrderCPU::setIntReg(int reg_idx, uint64_t val, unsigned tid)
+{
+ intRegFile[tid].setReg(reg_idx, val);
+}
+
+
+void
+InOrderCPU::setFloatReg(int reg_idx, FloatReg val, unsigned tid, int width)
+{
+ floatRegFile[tid].setReg(reg_idx, val, width);
+}
+
+
+void
+InOrderCPU::setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid, int width)
+{
+ floatRegFile[tid].setRegBits(reg_idx, val, width);
+}
+
+uint64_t
+InOrderCPU::readRegOtherThread(unsigned reg_idx, unsigned tid)
+{
+ // If Default value is set, then retrieve target thread
+ if (tid == -1) {
+ tid = TheISA::getTargetThread(tcBase(tid));
+ }
+
+ if (reg_idx < FP_Base_DepTag) { // Integer Register File
+ return readIntReg(reg_idx, tid);
+ } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
+ reg_idx -= FP_Base_DepTag;
+ return readFloatRegBits(reg_idx, tid);
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ return readMiscReg(reg_idx, tid); // Misc. Register File
+ }
+}
+void
+InOrderCPU::setRegOtherThread(unsigned reg_idx, const MiscReg &val, unsigned tid)
+{
+ // If Default value is set, then retrieve target thread
+ if (tid == -1) {
+ tid = TheISA::getTargetThread(tcBase(tid));
+ }
+
+ if (reg_idx < FP_Base_DepTag) { // Integer Register File
+ setIntReg(reg_idx, val, tid);
+ } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
+ reg_idx -= FP_Base_DepTag;
+ setFloatRegBits(reg_idx, val, tid);
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ setMiscReg(reg_idx, val, tid); // Misc. Register File
+ }
+}
+
+MiscReg
+InOrderCPU::readMiscRegNoEffect(int misc_reg, unsigned tid)
+{
+ return miscRegFile.readRegNoEffect(misc_reg, tid);
+}
+
+MiscReg
+InOrderCPU::readMiscReg(int misc_reg, unsigned tid)
+{
+ return miscRegFile.readReg(misc_reg, tcBase(tid), tid);
+}
+
+void
+InOrderCPU::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid)
+{
+ miscRegFile.setRegNoEffect(misc_reg, val, tid);
+}
+
+void
+InOrderCPU::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
+{
+ miscRegFile.setReg(misc_reg, val, tcBase(tid), tid);
+}
+
+
+InOrderCPU::ListIt
+InOrderCPU::addInst(DynInstPtr &inst)
+{
+ int tid = inst->readTid();
+
+ instList[tid].push_back(inst);
+
+ return --(instList[tid].end());
+}
+
+void
+InOrderCPU::instDone(DynInstPtr inst, unsigned tid)
+{
+ // Set the CPU's PCs - This contributes to the precise state of the CPU which can be used
+ // when restoring a thread to the CPU after a fork or after an exception
+ // @TODO: Set-Up Grad-Info/Committed-Info to let ThreadState know if it's a branch or not
+ setPC(inst->readPC(), tid);
+ setNextPC(inst->readNextPC(), tid);
+ setNextNPC(inst->readNextNPC(), tid);
+
+ // Finalize Trace Data For Instruction
+ if (inst->traceData) {
+ //inst->traceData->setCycle(curTick);
+ inst->traceData->setFetchSeq(inst->seqNum);
+ //inst->traceData->setCPSeq(cpu->tcBase(tid)->numInst);
+ inst->traceData->dump();
+ delete inst->traceData;
+ inst->traceData = NULL;
+ }
+
+ // Set Last Graduated Instruction In Thread State
+ //thread[tid]->lastGradInst = inst;
+
+ // Increment thread-state's instruction count
+ thread[tid]->numInst++;
+
+ // Increment thread-state's instruction stats
+ thread[tid]->numInsts++;
+
+ // Count committed insts per thread stats
+ committedInsts[tid]++;
+
+ // Count total insts committed stat
+ totalCommittedInsts++;
+
+ // Count SMT-committed insts per thread stat
+ if (numActiveThreads() > 1) {
+ smtCommittedInsts[tid]++;
+ }
+
+ // Check for instruction-count-based events.
+ comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
+
+ // Broadcast to other resources an instruction
+ // has been completed
+ resPool->scheduleEvent((CPUEventType)ResourcePool::InstGraduated, inst, tid);
+
+ // Finally, remove instruction from CPU
+ removeInst(inst);
+}
+
+void
+InOrderCPU::addToRemoveList(DynInstPtr &inst)
+{
+ removeInstsThisCycle = true;
+
+ removeList.push(inst->getInstListIt());
+}
+
+void
+InOrderCPU::removeInst(DynInstPtr &inst)
+{
+ DPRINTF(InOrderCPU, "Removing graduated instruction [tid:%i] PC %#x "
+ "[sn:%lli]\n",
+ inst->threadNumber, inst->readPC(), inst->seqNum);
+
+ removeInstsThisCycle = true;
+
+ // Remove the instruction.
+ removeList.push(inst->getInstListIt());
+}
+
+void
+InOrderCPU::removeInstsUntil(const InstSeqNum &seq_num,
+ unsigned tid)
+{
+ //assert(!instList[tid].empty());
+
+ removeInstsThisCycle = true;
+
+ ListIt inst_iter = instList[tid].end();
+
+ inst_iter--;
+
+ DPRINTF(InOrderCPU, "Deleting instructions from CPU 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[tid].begin());
+
+ squashInstIt(inst_iter, tid);
+
+ inst_iter--;
+
+ if (break_loop)
+ break;
+ }
+}
+
+
+inline void
+InOrderCPU::squashInstIt(const ListIt &instIt, const unsigned &tid)
+{
+ if ((*instIt)->threadNumber == tid) {
+ DPRINTF(InOrderCPU, "Squashing instruction, "
+ "[tid:%i] [sn:%lli] PC %#x\n",
+ (*instIt)->threadNumber,
+ (*instIt)->seqNum,
+ (*instIt)->readPC());
+
+ (*instIt)->setSquashed();
+
+ removeList.push(instIt);
+ }
+}
+
+
+void
+InOrderCPU::cleanUpRemovedInsts()
+{
+ while (!removeList.empty()) {
+ DPRINTF(InOrderCPU, "Removing instruction, "
+ "[tid:%i] [sn:%lli] PC %#x\n",
+ (*removeList.front())->threadNumber,
+ (*removeList.front())->seqNum,
+ (*removeList.front())->readPC());
+
+ DynInstPtr inst = *removeList.front();
+ int tid = inst->threadNumber;
+
+ // Make Sure Resource Schedule Is Emptied Out
+ ThePipeline::ResSchedule *inst_sched = &inst->resSched;
+ while (!inst_sched->empty()) {
+ ThePipeline::ScheduleEntry* sch_entry = inst_sched->top();
+ inst_sched->pop();
+ delete sch_entry;
+ }
+
+ // Remove From Register Dependency Map, If Necessary
+ archRegDepMap[(*removeList.front())->threadNumber].
+ remove((*removeList.front()));
+
+
+ // Clear if Non-Speculative
+ if (inst->staticInst &&
+ inst->seqNum == nonSpecSeqNum[tid] &&
+ nonSpecInstActive[tid] == true) {
+ nonSpecInstActive[tid] = false;
+ }
+
+ instList[tid].erase(removeList.front());
+
+ removeList.pop();
+
+ DPRINTF(RefCount, "pop from remove list: [sn:%i]: Refcount = %i.\n",
+ inst->seqNum,
+ 0/*inst->curCount()*/);
+
+ }
+
+ removeInstsThisCycle = false;
+}
+
+void
+InOrderCPU::cleanUpRemovedReqs()
+{
+ while (!reqRemoveList.empty()) {
+ ResourceRequest *res_req = reqRemoveList.front();
+
+ DPRINTF(RefCount, "[tid:%i]: Removing Request, "
+ "[sn:%lli] [slot:%i] [stage_num:%i] [res:%s] [refcount:%i].\n",
+ res_req->inst->threadNumber,
+ res_req->inst->seqNum,
+ res_req->getSlot(),
+ res_req->getStageNum(),
+ res_req->res->name(),
+ 0/*res_req->inst->curCount()*/);
+
+ reqRemoveList.pop();
+
+ delete res_req;
+
+ DPRINTF(RefCount, "after remove request: [sn:%i]: Refcount = %i.\n",
+ res_req->inst->seqNum,
+ 0/*res_req->inst->curCount()*/);
+ }
+}
+
+void
+InOrderCPU::cleanUpRemovedEvents()
+{
+ while (!cpuEventRemoveList.empty()) {
+ Event *cpu_event = cpuEventRemoveList.front();
+ cpuEventRemoveList.pop();
+ delete cpu_event;
+ }
+}
+
+
+void
+InOrderCPU::dumpInsts()
+{
+ int num = 0;
+
+ ListIt inst_list_it = instList[0].begin();
+
+ cprintf("Dumping Instruction List\n");
+
+ while (inst_list_it != instList[0].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;
+ }
+}
+
+void
+InOrderCPU::wakeCPU()
+{
+ if (/*activityRec.active() || */tickEvent.scheduled()) {
+ DPRINTF(Activity, "CPU already running.\n");
+ return;
+ }
+
+ DPRINTF(Activity, "Waking up CPU\n");
+
+ //@todo: figure out how to count idleCycles correctly
+ //idleCycles += (curTick - 1) - lastRunningCycle;
+
+ mainEventQueue.schedule(&tickEvent, curTick);
+}
+
+void
+InOrderCPU::syscall(int64_t callnum, int tid)
+{
+ DPRINTF(InOrderCPU, "[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(callnum);
+
+ // Decrease funcExeInst by one as the normal commit will handle
+ // incrementing it.
+ --(this->thread[tid]->funcExeInst);
+
+ // Clear Non-Speculative Block Variable
+ nonSpecInstActive[tid] = false;
+}
+
+Fault
+InOrderCPU::read(DynInstPtr inst)
+{
+ Resource *mem_res = resPool->getResource(dataPortIdx);
+ return mem_res->doDataAccess(inst);
+}
+
+Fault
+InOrderCPU::write(DynInstPtr inst)
+{
+ Resource *mem_res = resPool->getResource(dataPortIdx);
+ return mem_res->doDataAccess(inst);
+}
diff --git a/src/cpu/inorder/cpu.hh b/src/cpu/inorder/cpu.hh
new file mode 100644
index 000000000..adcd28019
--- /dev/null
+++ b/src/cpu/inorder/cpu.hh
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_CPU_HH__
+#define __CPU_INORDER_CPU_HH__
+
+#include <iostream>
+#include <list>
+#include <queue>
+#include <set>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "config/full_system.hh"
+#include "cpu/activity.hh"
+#include "cpu/base.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+#include "cpu/o3/dep_graph.hh"
+#include "cpu/o3/rename_map.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+#include "sim/process.hh"
+
+class ThreadContext;
+class MemInterface;
+class MemObject;
+class Process;
+class ResourcePool;
+
+class InOrderCPU : public BaseCPU
+{
+
+ protected:
+ typedef ThePipeline::Params Params;
+ typedef InOrderThreadState Thread;
+
+ //ISA TypeDefs
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+ typedef TheISA::RegFile RegFile;
+
+ //DynInstPtr TypeDefs
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+ typedef std::list<DynInstPtr>::iterator ListIt;
+
+ //TimeBuffer TypeDefs
+ typedef TimeBuffer<InterStageStruct> StageQueue;
+
+ friend class Resource;
+
+ public:
+ /** Constructs a CPU with the given parameters. */
+ InOrderCPU(Params *params);
+
+ /** CPU ID */
+ int cpu_id;
+
+ /** Type of core that this is */
+ std::string coreType;
+
+ int readCpuId() { return cpu_id; }
+
+ void setCpuId(int val) { cpu_id = val; }
+
+ Params *cpu_params;
+
+ TheISA::ITB * itb;
+ TheISA::DTB * dtb;
+
+ public:
+ enum Status {
+ Running,
+ Idle,
+ Halted,
+ Blocked,
+ SwitchedOut
+ };
+
+ /** Overall CPU status. */
+ Status _status;
+
+ private:
+ /** Define TickEvent for the CPU */
+ class TickEvent : public Event
+ {
+ private:
+ /** Pointer to the CPU. */
+ InOrderCPU *cpu;
+
+ public:
+ /** Constructs a tick event. */
+ TickEvent(InOrderCPU *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())
+ mainEventQueue.reschedule(&tickEvent, nextCycle(curTick + ticks(delay)));
+ else if (!tickEvent.scheduled())
+ mainEventQueue.schedule(&tickEvent, nextCycle(curTick + ticks(delay)));
+ }
+
+ /** Unschedule tick event, regardless of its current state. */
+ void unscheduleTickEvent()
+ {
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ }
+
+ public:
+ // List of Events That can be scheduled from
+ // within the CPU.
+ // NOTE(1): The Resource Pool also uses this event list
+ // to schedule events broadcast to all resources interfaces
+ // NOTE(2): CPU Events usually need to schedule a corresponding resource
+ // pool event.
+ enum CPUEventType {
+ ActivateThread,
+ DeallocateThread,
+ SuspendThread,
+ DisableThreads,
+ EnableThreads,
+ DisableVPEs,
+ EnableVPEs,
+ Trap,
+ InstGraduated,
+ SquashAll,
+ UpdatePCs,
+ NumCPUEvents
+ };
+
+ /** Define CPU Event */
+ class CPUEvent : public Event
+ {
+ protected:
+ InOrderCPU *cpu;
+
+ public:
+ CPUEventType cpuEventType;
+ unsigned tid;
+ unsigned vpe;
+ Fault fault;
+
+ public:
+ /** Constructs a CPU event. */
+ CPUEvent(InOrderCPU *_cpu, CPUEventType e_type, Fault fault,
+ unsigned _tid, unsigned _vpe);
+
+ /** Set Type of Event To Be Scheduled */
+ void setEvent(CPUEventType e_type, Fault _fault, unsigned _tid, unsigned _vpe)
+ {
+ fault = _fault;
+ cpuEventType = e_type;
+ tid = _tid;
+ vpe = _vpe;
+ }
+
+ /** Processes a resource event. */
+ virtual void process();
+
+ /** Returns the description of the resource event. */
+ const char *description();
+
+ /** Schedule Event */
+ void scheduleEvent(int delay);
+
+ /** Unschedule This Event */
+ void unscheduleEvent();
+ };
+
+ /** Schedule a CPU Event */
+ void scheduleCpuEvent(CPUEventType cpu_event, Fault fault, unsigned tid,
+ unsigned vpe, unsigned delay = 0);
+
+ public:
+ /** Interface between the CPU and CPU resources. */
+ ResourcePool *resPool;
+
+ /** Instruction used to signify that there is no *real* instruction in buffer slot */
+ DynInstPtr dummyBufferInst;
+
+ /** Used by resources to signify a denied access to a resource. */
+ ResourceRequest *dummyReq;
+
+ /** Identifies the resource id that identifies a fetch
+ * access unit.
+ */
+ unsigned fetchPortIdx;
+
+ /** Identifies the resource id that identifies a data
+ * access unit.
+ */
+ unsigned dataPortIdx;
+
+ /** The Pipeline Stages for the CPU */
+ PipelineStage *pipelineStage[ThePipeline::NumStages];
+
+ TheISA::IntReg PC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextPC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+
+ /** The Register File for the CPU */
+ TheISA::IntRegFile intRegFile[ThePipeline::MaxThreads];;
+ TheISA::FloatRegFile floatRegFile[ThePipeline::MaxThreads];;
+ TheISA::MiscRegFile miscRegFile;
+
+ /** Dependency Tracker for Integer & Floating Point Regs */
+ RegDepMap archRegDepMap[ThePipeline::MaxThreads];
+
+ /** Global communication structure */
+ TimeBuffer<TimeStruct> timeBuffer;
+
+ /** Communication structure that sits in between pipeline stages */
+ StageQueue *stageQueue[ThePipeline::NumStages-1];
+
+ public:
+
+ /** Registers statistics. */
+ void regStats();
+
+ /** 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();
+
+ /** Reset State in the CPU */
+ void reset();
+
+ /** Get a Memory Port */
+ Port* getPort(const std::string &if_name, int idx = 0);
+
+ /** trap() - sets up a trap event on the cpuTraps to handle given fault.
+ * trapCPU() - Traps to handle given fault
+ */
+ void trap(Fault fault, unsigned tid, int delay = 0);
+ void trapCPU(Fault fault, unsigned tid);
+
+ /** 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);
+
+ /** Add Thread to Active Threads List. */
+ void activateContext(unsigned tid, int delay = 0);
+ void activateThread(unsigned tid);
+
+ /** Remove Thread from Active Threads List */
+ void suspendContext(unsigned tid, int delay = 0);
+ void suspendThread(unsigned tid);
+
+ /** Remove Thread from Active Threads List &&
+ * Remove Thread Context from CPU.
+ */
+ void deallocateContext(unsigned tid, int delay = 0);
+ void deallocateThread(unsigned tid);
+ void deactivateThread(unsigned tid);
+
+ int
+ contextId()
+ {
+ hack_once("return a bogus context id");
+ return 0;
+ }
+
+ /** Remove Thread from Active Threads List &&
+ * Remove Thread Context from CPU.
+ */
+ void haltContext(unsigned tid, int delay = 0);
+
+ void removePipelineStalls(unsigned tid);
+
+ void squashThreadInPipeline(unsigned tid);
+
+ /// Notify the CPU to enable a virtual processor element.
+ virtual void enableVirtProcElement(unsigned vpe);
+ void enableVPEs(unsigned vpe);
+
+ /// Notify the CPU to disable a virtual processor element.
+ virtual void disableVirtProcElement(unsigned tid, unsigned vpe);
+ void disableVPEs(unsigned tid, unsigned vpe);
+
+ /// Notify the CPU that multithreading is enabled.
+ virtual void enableMultiThreading(unsigned vpe);
+ void enableThreads(unsigned vpe);
+
+ /// Notify the CPU that multithreading is disabled.
+ virtual void disableMultiThreading(unsigned tid, unsigned vpe);
+ void disableThreads(unsigned tid, unsigned vpe);
+
+ // Sets a thread-rescheduling condition.
+ void setThreadRescheduleCondition(uint32_t tid)
+ {
+ //@TODO: IMPLEMENT ME
+ }
+
+ /** 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();
+
+ /** Switches a Pipeline Stage to Active. (Unused currently) */
+ void switchToActive(int stage_idx)
+ { /*pipelineStage[stage_idx]->switchToActive();*/ }
+
+ /** Get the current instruction sequence number, and increment it. */
+ InstSeqNum getAndIncrementInstSeq(unsigned tid)
+ { return globalSeqNum[tid]++; }
+
+ /** Get the current instruction sequence number, and increment it. */
+ InstSeqNum nextInstSeqNum(unsigned tid)
+ { return globalSeqNum[tid]; }
+
+ /** Increment Instruction Sequence Number */
+ void incrInstSeqNum(unsigned tid)
+ { globalSeqNum[tid]++; }
+
+ /** Set Instruction Sequence Number */
+ void setInstSeqNum(unsigned tid, InstSeqNum seq_num)
+ {
+ globalSeqNum[tid] = seq_num;
+ }
+
+ /** Get & Update Next Event Number */
+ InstSeqNum getNextEventNum()
+ {
+ return cpuEventNum++;
+ }
+
+ /** Get instruction asid. */
+ int getInstAsid(unsigned tid)
+ { return thread[tid]->getInstAsid(); }
+
+ /** Get data asid. */
+ int getDataAsid(unsigned tid)
+ { return thread[tid]->getDataAsid(); }
+
+ /** Register file accessors */
+ uint64_t readIntReg(int reg_idx, unsigned tid);
+
+ FloatReg readFloatReg(int reg_idx, unsigned tid,
+ int width = TheISA::SingleWidth);
+
+ FloatRegBits readFloatRegBits(int reg_idx, unsigned tid,
+ int width = TheISA::SingleWidth);
+
+ void setIntReg(int reg_idx, uint64_t val, unsigned tid);
+
+ void setFloatReg(int reg_idx, FloatReg val, unsigned tid,
+ int width = TheISA::SingleWidth);
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, unsigned tid,
+ int width = TheISA::SingleWidth);
+
+ /** Reads a miscellaneous register. */
+ MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0);
+
+ /** Reads a misc. register, including any side effects the read
+ * might have as defined by the architecture.
+ */
+ MiscReg readMiscReg(int misc_reg, unsigned tid = 0);
+
+ /** Sets a miscellaneous register. */
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0);
+
+ /** Sets a misc. register, including any side effects the write
+ * might have as defined by the architecture.
+ */
+ void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0);
+
+ /** Reads a int/fp/misc reg. from another thread depending on ISA-defined
+ * target thread
+ */
+ uint64_t readRegOtherThread(unsigned misc_reg, unsigned tid = -1);
+
+ /** Sets a int/fp/misc reg. from another thread depending on an ISA-defined
+ * target thread
+ */
+ void setRegOtherThread(unsigned misc_reg, const MiscReg &val, unsigned tid);
+
+ /** Reads the commit PC of a specific thread. */
+ uint64_t readPC(unsigned tid);
+
+ /** Sets the commit PC of a specific thread. */
+ void setPC(Addr new_PC, unsigned tid);
+
+ /** Reads the next PC of a specific thread. */
+ uint64_t readNextPC(unsigned tid);
+
+ /** Sets the next PC of a specific thread. */
+ void setNextPC(uint64_t val, unsigned tid);
+
+ /** Reads the next NPC of a specific thread. */
+ uint64_t readNextNPC(unsigned tid);
+
+ /** Sets the next NPC of a specific thread. */
+ void setNextNPC(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(DynInstPtr inst, unsigned tid);
+
+ /** Add Instructions to the CPU Remove List*/
+ void addToRemoveList(DynInstPtr &inst);
+
+ /** Remove an instruction from CPU */
+ void removeInst(DynInstPtr &inst);
+
+ /** Remove all instructions younger than the given sequence number. */
+ void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid);
+
+ /** Removes the instruction pointed to by the iterator. */
+ inline void squashInstIt(const ListIt &instIt, const unsigned &tid);
+
+ /** Cleans up all instructions on the instruction remove list. */
+ void cleanUpRemovedInsts();
+
+ /** Cleans up all instructions on the request remove list. */
+ void cleanUpRemovedReqs();
+
+ /** Cleans up all instructions on the CPU event remove list. */
+ void cleanUpRemovedEvents();
+
+ /** Debug function to print all instructions on the list. */
+ void dumpInsts();
+
+ /** Forwards an instruction read to the appropriate data
+ * resource (indexes into Resource Pool thru "dataPortIdx")
+ */
+ Fault read(DynInstPtr inst);
+
+ /** Forwards an instruction write. to the appropriate data
+ * resource (indexes into Resource Pool thru "dataPortIdx")
+ */
+ Fault write(DynInstPtr inst);
+
+ /** Executes a syscall.*/
+ void syscall(int64_t callnum, int tid);
+
+ public:
+ /** Per-Thread List of all the instructions in flight. */
+ std::list<DynInstPtr> instList[ThePipeline::MaxThreads];
+
+ /** List of all the instructions that will be removed at the end of this
+ * cycle.
+ */
+ std::queue<ListIt> removeList;
+
+ /** List of all the resource requests that will be removed at the end of this
+ * cycle.
+ */
+ std::queue<ResourceRequest*> reqRemoveList;
+
+ /** List of all the cpu event requests that will be removed at the end of
+ * the current cycle.
+ */
+ std::queue<Event*> cpuEventRemoveList;
+
+ /** Records if instructions need to be removed this cycle due to
+ * being retired or squashed.
+ */
+ bool removeInstsThisCycle;
+
+ /** True if there is non-speculative Inst Active In Pipeline. Lets any
+ * execution unit know, NOT to execute while the instruction is active.
+ */
+ bool nonSpecInstActive[ThePipeline::MaxThreads];
+
+ /** Instruction Seq. Num of current non-speculative instruction. */
+ InstSeqNum nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** Instruction Seq. Num of last instruction squashed in pipeline */
+ InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
+
+ /** Last Cycle that the CPU squashed instruction end. */
+ Tick lastSquashCycle[ThePipeline::MaxThreads];
+
+ std::list<unsigned> fetchPriorityList;
+
+ protected:
+ /** Active Threads List */
+ std::list<unsigned> activeThreads;
+
+ /** Current Threads List */
+ std::list<unsigned> currentThreads;
+
+ /** Suspended Threads List */
+ std::list<unsigned> suspendedThreads;
+
+ /** Thread Status Functions (Unused Currently) */
+ bool isThreadInCPU(unsigned tid);
+ bool isThreadActive(unsigned tid);
+ bool isThreadSuspended(unsigned tid);
+ void addToCurrentThreads(unsigned tid);
+ void removeFromCurrentThreads(unsigned tid);
+
+ private:
+ /** The activity recorder; used to tell if the CPU has any
+ * activity remaining or if it can go to idle and deschedule
+ * itself.
+ */
+ ActivityRecorder activityRec;
+
+ public:
+ void readFunctional(Addr addr, uint32_t &buffer);
+
+ /** Number of Active Threads in the CPU */
+ int numActiveThreads() { return activeThreads.size(); }
+
+ /** Records that there was time buffer activity this cycle. */
+ void activityThisCycle() { activityRec.activity(); }
+
+ /** Changes a stage's status to active within the activity recorder. */
+ void activateStage(const int idx)
+ { activityRec.activateStage(idx); }
+
+ /** Changes a stage's status to inactive within the activity recorder. */
+ void deactivateStage(const int 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();
+
+ // LL/SC debug functionality
+ unsigned stCondFails;
+ unsigned readStCondFailures() { return stCondFails; }
+ unsigned setStCondFailures(unsigned st_fails) { return stCondFails = st_fails; }
+
+ /** Returns a pointer to a thread context. */
+ ThreadContext *tcBase(unsigned tid = 0)
+ {
+ return thread[tid]->getTC();
+ }
+
+ /** The global sequence number counter. */
+ InstSeqNum globalSeqNum[ThePipeline::MaxThreads];
+
+ /** The global event number counter. */
+ InstSeqNum cpuEventNum;
+
+ /** Counter of how many stages have completed switching out. */
+ int switchCount;
+
+ /** Pointers to all of the threads in the CPU. */
+ std::vector<Thread *> thread;
+
+ /** 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;
+
+ /** Per-Stage Instruction Tracing */
+ bool stageTracing;
+
+ /** 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 the CPU can process */
+ unsigned numThreads;
+
+ /** Number of Virtual Processors the CPU can process */
+ unsigned numVirtProcs;
+
+ /** Update Thread , used for statistic purposes*/
+ inline void tickThreadStats();
+
+ /** Per-Thread Tick */
+ Stats::Vector threadCycles;
+
+ /** Tick for SMT */
+ Stats::Scalar smtCycles;
+
+ /** 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 number of committed instructions per thread. */
+ Stats::Vector smtCommittedInsts;
+
+ /** Stat for the total number of committed instructions. */
+ Stats::Scalar totalCommittedInsts;
+
+ /** Stat for the CPI per thread. */
+ Stats::Formula cpi;
+
+ /** Stat for the SMT-CPI per thread. */
+ Stats::Formula smtCpi;
+
+ /** Stat for the total CPI. */
+ Stats::Formula totalCpi;
+
+ /** Stat for the IPC per thread. */
+ Stats::Formula ipc;
+
+ /** Stat for the total IPC. */
+ Stats::Formula smtIpc;
+
+ /** Stat for the total IPC. */
+ Stats::Formula totalIpc;
+};
+
+#endif // __CPU_O3_CPU_HH__
diff --git a/src/cpu/inorder/first_stage.cc b/src/cpu/inorder/first_stage.cc
new file mode 100644
index 000000000..5e389b256
--- /dev/null
+++ b/src/cpu/inorder/first_stage.cc
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "base/str.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+#include "params/InOrderTrace.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+FirstStage::FirstStage(Params *params, unsigned stage_num)
+ : PipelineStage(params, stage_num), numFetchingThreads(1),
+ fetchPolicy(FirstStage::RoundRobin)
+{
+ for(int tid=0; tid < this->numThreads; tid++) {
+ stageStatus[tid] = Running;
+ }
+}
+
+void
+FirstStage::setCPU(InOrderCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ fetchPriorityList = &cpu->fetchPriorityList;
+
+ DPRINTF(InOrderStage, "Set CPU pointer.\n");
+}
+
+
+void
+FirstStage::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ // Set status to squashing.
+ //stageStatus[tid] = Squashing;
+
+ // Clear the instruction list and skid buffer in case they have any
+ // insts in them.
+ DPRINTF(InOrderStage, "Removing instructions from stage instruction list.\n");
+ while (!insts[tid].empty()) {
+ if (insts[tid].front()->seqNum <= squash_seq_num) {
+ DPRINTF(InOrderStage,"[tid:%i]: Cannot remove [sn:%i] because it's <= "
+ "squashing seqNum %i.\n",
+ tid,
+ insts[tid].front()->seqNum,
+ squash_seq_num);
+
+ DPRINTF(InOrderStage, "[tid:%i]: Cannot remove incoming "
+ "instructions before delay slot [sn:%i]. %i insts"
+ "left.\n", tid, squash_seq_num,
+ insts[tid].size());
+ break;
+ }
+ DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
+ tid, insts[tid].front()->seqNum, insts[tid].front()->PC);
+ insts[tid].pop();
+ }
+
+ // Now that squash has propagated to the first stage,
+ // Alert CPU to remove instructions from the CPU instruction list.
+ // @todo: Move this to the CPU object.
+ cpu->removeInstsUntil(squash_seq_num, tid);
+}
+
+void
+FirstStage::processStage(bool &status_change)
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ //Check stall and squash signals.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+ status_change = checkSignalsAndUpdate(tid) || status_change;
+ }
+
+ for (int threadFetched = 0; threadFetched < numFetchingThreads;
+ threadFetched++) {
+ int tid = getFetchingThread(fetchPolicy);
+
+ if (tid >= 0) {
+ DPRINTF(InOrderStage, "Processing [tid:%i]\n",tid);
+ processThread(status_change, tid);
+ } else {
+ DPRINTF(InOrderStage, "No more threads to fetch from.\n");
+ }
+ }
+}
+
+//@TODO: Note in documentation, that when you make a pipeline stage change, then
+//make sure you change the first stage too
+void
+FirstStage::processInsts(unsigned tid)
+{
+ bool all_reqs_completed = true;
+
+ for (int insts_fetched = 0; insts_fetched < stageWidth && canSendInstToStage(1); insts_fetched++) {
+ DynInstPtr inst;
+ bool new_inst = false;
+
+ if (!insts[tid].empty()) {
+ inst = insts[tid].front();
+ } else {
+ // Get new instruction.
+ new_inst = true;
+
+ inst = new InOrderDynInst(cpu,
+ cpu->thread[tid],
+ cpu->nextInstSeqNum(tid),
+ tid);
+
+#if TRACING_ON
+ inst->traceData =
+ tracer->getInstRecord(ThePipeline::NumStages,
+ cpu->stageTracing,
+ cpu->thread[tid]->getTC());
+
+#endif // TRACING_ON
+
+ DPRINTF(RefCount, "creation: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+ inst->readTid(),
+ inst->seqNum,
+ 0/*inst->curCount()*/);
+
+ // Add instruction to the CPU's list of instructions.
+ inst->setInstListIt(cpu->addInst(inst));
+
+ DPRINTF(RefCount, "after add to CPU List: [tid:%i]: [sn:%i]: Refcount = %i.\n",
+ inst->readTid(),
+ inst->seqNum,
+ 0/*inst->curCount()*/);
+
+ // Create Front-End Resource Schedule For Instruction
+ ThePipeline::createFrontEndSchedule(inst);
+ }
+
+ // Don't let instruction pass to next stage if it hasnt completed
+ // all of it's requests for this stage.
+ all_reqs_completed = processInstSchedule(inst);
+
+ if (!all_reqs_completed) {
+ if (new_inst) {
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%u] Did not finish all "
+ "requests for this stage. Keep in stage inst. "
+ "list.\n", tid, inst->seqNum);
+ insts[tid].push(inst);
+ }
+ break;
+ } else if (!insts[tid].empty()){
+ insts[tid].pop();
+ }
+
+ sendInstToNextStage(inst);
+ //++stageProcessedInsts;
+ }
+
+ // Record that stage has written to the time buffer for activity
+ // tracking.
+ if (toNextStageIndex) {
+ wroteToTimeBuffer = true;
+ }
+}
+
+int
+FirstStage::getFetchingThread(FetchPriority &fetch_priority)
+{
+ if (numThreads > 1) {
+ switch (fetch_priority) {
+
+ case SingleThread:
+ return 0;
+
+ case RoundRobin:
+ return roundRobin();
+
+ default:
+ return -1;
+ }
+ } else {
+ int tid = *((*activeThreads).begin());
+
+ if (stageStatus[tid] == Running ||
+ stageStatus[tid] == Idle) {
+ return tid;
+ } else {
+ return -1;
+ }
+ }
+
+}
+
+int
+FirstStage::roundRobin()
+{
+ list<unsigned>::iterator pri_iter = (*fetchPriorityList).begin();
+ list<unsigned>::iterator end = (*fetchPriorityList).end();
+
+ int high_pri;
+
+ while (pri_iter != end) {
+ high_pri = *pri_iter;
+
+ assert(high_pri <= numThreads);
+
+ if (stageStatus[high_pri] == Running ||
+ stageStatus[high_pri] == Idle) {
+
+ (*fetchPriorityList).erase(pri_iter);
+ (*fetchPriorityList).push_back(high_pri);
+
+ return high_pri;
+ }
+
+ pri_iter++;
+ }
+
+ return -1;
+}
diff --git a/src/cpu/inorder/first_stage.hh b/src/cpu/inorder/first_stage.hh
new file mode 100644
index 000000000..55914c85c
--- /dev/null
+++ b/src/cpu/inorder/first_stage.hh
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_FIRST_STAGE_HH__
+#define __CPU_INORDER_FIRST_STAGE_HH__
+
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/comm.hh"
+#include "cpu/inorder/params.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+
+class InOrderCPU;
+
+class FirstStage : public PipelineStage {
+ public:
+ FirstStage(ThePipeline::Params *params, unsigned stage_num);
+
+ /** Set Pointer to CPU */
+ void setCPU(InOrderCPU *cpu_ptr);
+
+ /** Evaluate Stage Info. & Execute Stage */
+ void processStage(bool &status_change);
+
+ /** Process All Instructions Available */
+ void processInsts(unsigned tid);
+
+ /** Squash Instructions Above a Seq. Num */
+ void squash(InstSeqNum squash_seq_num, unsigned tid);
+
+ /** There are no insts. coming from previous stages, so there is
+ * no need to sort insts here
+ */
+ void sortInsts() {}
+
+ /** There are no skidBuffers for the first stage. So
+ * just use an empty function.
+ */
+ void skidInsert(unsigned tid) { }
+
+ /** The number of fetching threads in the CPU */
+ int numFetchingThreads;
+
+ //@TODO: Add fetch priority information to a resource class...
+ /** Fetching Policy, Add new policies here.*/
+ enum FetchPriority {
+ SingleThread,
+ RoundRobin
+ };
+
+ /** Fetch policy. */
+ FetchPriority fetchPolicy;
+
+ /** List that has the threads organized by priority. */
+ std::list<unsigned> *fetchPriorityList;
+
+ /** Return the next fetching thread */
+ int getFetchingThread(FetchPriority &fetch_priority);
+
+ /** Return next thred given Round Robin Policy for Thread Fetching */
+ int roundRobin();
+};
+
+#endif // __CPU_INORDER_FIRST_STAGE_HH__
diff --git a/src/cpu/inorder/inorder_cpu_builder.cc b/src/cpu/inorder/inorder_cpu_builder.cc
new file mode 100644
index 000000000..0088a3bd9
--- /dev/null
+++ b/src/cpu/inorder/inorder_cpu_builder.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <string>
+
+#include "cpu/base.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "params/InOrderCPU.hh"
+
+InOrderCPU *
+InOrderCPUParams::create()
+{
+ int actual_num_threads =
+ (numThreads >= workload.size()) ? numThreads : workload.size();
+
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
+ }
+
+ numThreads = actual_num_threads;
+
+ instShiftAmt = 2;
+
+ return new InOrderCPU(this);
+}
+
+
+
diff --git a/src/cpu/inorder/inorder_dyn_inst.cc b/src/cpu/inorder/inorder_dyn_inst.cc
new file mode 100644
index 000000000..ceb3cbe51
--- /dev/null
+++ b/src/cpu/inorder/inorder_dyn_inst.cc
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <iostream>
+#include <set>
+#include <string>
+#include <sstream>
+
+#include "base/cprintf.hh"
+#include "base/trace.hh"
+
+#include "arch/faults.hh"
+#include "cpu/exetrace.hh"
+#include "mem/request.hh"
+
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InOrderDynInst::InOrderDynInst(TheISA::ExtMachInst machInst, Addr inst_PC,
+ Addr pred_PC, InstSeqNum seq_num,
+ InOrderCPU *cpu)
+ : staticInst(machInst, inst_PC), traceData(NULL), cpu(cpu)
+{
+ seqNum = seq_num;
+
+ PC = inst_PC;
+ nextPC = PC + sizeof(MachInst);
+ nextNPC = nextPC + sizeof(MachInst);
+ predPC = pred_PC;
+
+ initVars();
+}
+
+InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
+ InOrderThreadState *state,
+ InstSeqNum seq_num,
+ unsigned tid)
+ : traceData(NULL), cpu(cpu)
+{
+ seqNum = seq_num;
+ thread = state;
+ threadNumber = tid;
+ initVars();
+}
+
+InOrderDynInst::InOrderDynInst(StaticInstPtr &_staticInst)
+ : seqNum(0), staticInst(_staticInst), traceData(NULL)
+{
+ initVars();
+}
+
+InOrderDynInst::InOrderDynInst()
+ : seqNum(0), traceData(NULL), cpu(cpu)
+{
+ initVars();
+}
+
+int InOrderDynInst::instcount = 0;
+
+
+void
+InOrderDynInst::setMachInst(ExtMachInst machInst)
+{
+ staticInst = StaticInst::decode(machInst, PC);
+
+ for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+ _destRegIdx[i] = this->staticInst->destRegIdx(i);
+ }
+
+ for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+ _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+ this->_readySrcRegIdx[i] = 0;
+ }
+}
+
+void
+InOrderDynInst::initVars()
+{
+ req = NULL;
+ effAddr = 0;
+ physEffAddr = 0;
+
+ readyRegs = 0;
+
+ nextStage = 0;
+ nextInstStageNum = 0;
+
+ for(int i = 0; i < MaxInstDestRegs; i++)
+ instResult[i].val.integer = 0;
+
+ status.reset();
+
+ memAddrReady = false;
+ eaCalcDone = false;
+ memOpDone = false;
+
+ predictTaken = false;
+ procDelaySlotOnMispred = false;
+
+ lqIdx = -1;
+ sqIdx = -1;
+
+ // Also make this a parameter, or perhaps get it from xc or cpu.
+ asid = 0;
+
+ virtProcNumber = 0;
+
+ // Initialize the fault to be NoFault.
+ fault = NoFault;
+
+ // Make sure to have the renamed register entries set to the same
+ // as the normal register entries. It will allow the IQ to work
+ // without any modifications.
+ if (this->staticInst) {
+ for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+ _destRegIdx[i] = this->staticInst->destRegIdx(i);
+ }
+
+ for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+ _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+ this->_readySrcRegIdx[i] = 0;
+ }
+ }
+
+ // Update Instruction Count for this instruction
+ ++instcount;
+ if (instcount > 500) {
+ fatal("Number of Active Instructions in CPU is too high. "
+ "(Not Dereferencing Ptrs. Correctly?)\n");
+ }
+
+
+
+ DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction created. (active insts: %i)\n",
+ threadNumber, seqNum, instcount);
+}
+
+
+InOrderDynInst::~InOrderDynInst()
+{
+ if (req) {
+ delete req;
+ }
+
+ if (traceData) {
+ delete traceData;
+ }
+
+ fault = NoFault;
+
+ --instcount;
+
+ deleteStages();
+
+ DPRINTF(InOrderDynInst, "DynInst: [tid:%i] [sn:%lli] Instruction destroyed. (active insts: %i)\n",
+ threadNumber, seqNum, instcount);
+}
+
+void
+InOrderDynInst::setStaticInst(StaticInstPtr &static_inst)
+{
+ this->staticInst = static_inst;
+
+ // Make sure to have the renamed register entries set to the same
+ // as the normal register entries. It will allow the IQ to work
+ // without any modifications.
+ if (this->staticInst) {
+ for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
+ _destRegIdx[i] = this->staticInst->destRegIdx(i);
+ }
+
+ for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
+ _srcRegIdx[i] = this->staticInst->srcRegIdx(i);
+ this->_readySrcRegIdx[i] = 0;
+ }
+ }
+}
+
+Fault
+InOrderDynInst::execute()
+{
+ // @todo: Pretty convoluted way to avoid squashing from happening
+ // when using the TC during an instruction's execution
+ // (specifically for instructions that have side-effects that use
+ // the TC). Fix this.
+ bool in_syscall = this->thread->inSyscall;
+ this->thread->inSyscall = true;
+
+ this->fault = this->staticInst->execute(this, this->traceData);
+
+ this->thread->inSyscall = in_syscall;
+
+ return this->fault;
+}
+
+Fault
+InOrderDynInst::initiateAcc()
+{
+ // @todo: Pretty convoluted way to avoid squashing from happening
+ // when using the TC during an instruction's execution
+ // (specifically for instructions that have side-effects that use
+ // the TC). Fix this.
+ bool in_syscall = this->thread->inSyscall;
+ this->thread->inSyscall = true;
+
+ this->fault = this->staticInst->initiateAcc(this, this->traceData);
+
+ this->thread->inSyscall = in_syscall;
+
+ return this->fault;
+}
+
+
+Fault
+InOrderDynInst::completeAcc(Packet *pkt)
+{
+ this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
+
+ return this->fault;
+}
+
+InstStage *InOrderDynInst::addStage()
+{
+ this->currentInstStage = new InstStage(this, nextInstStageNum++);
+ instStageList.push_back( this->currentInstStage );
+ return this->currentInstStage;
+}
+
+InstStage *InOrderDynInst::addStage(int stage_num)
+{
+ nextInstStageNum = stage_num;
+ return InOrderDynInst::addStage();
+}
+
+void InOrderDynInst::deleteStages() {
+ std::list<InstStage*>::iterator list_it = instStageList.begin();
+ std::list<InstStage*>::iterator list_end = instStageList.end();
+
+ while(list_it != list_end) {
+ delete *list_it;
+ list_it++;
+ }
+}
+
+Fault
+InOrderDynInst::calcEA()
+{
+ return staticInst->eaCompInst()->execute(this, this->traceData);
+}
+
+Fault
+InOrderDynInst::memAccess()
+{
+ //return staticInst->memAccInst()->execute(this, this->traceData);
+ return initiateAcc( );
+}
+
+void
+InOrderDynInst::syscall(int64_t callnum)
+{
+ cpu->syscall(callnum, this->threadNumber);
+}
+
+void
+InOrderDynInst::prefetch(Addr addr, unsigned flags)
+{
+ panic("Prefetch Unimplemented\n");
+}
+
+void
+InOrderDynInst::writeHint(Addr addr, int size, unsigned flags)
+{
+ panic("Write-Hint Unimplemented\n");
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+Fault
+InOrderDynInst::copySrcTranslate(Addr src)
+{
+ // Not currently supported.
+ return NoFault;
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+Fault
+InOrderDynInst::copy(Addr dest)
+{
+ // Not currently supported.
+ return NoFault;
+}
+
+void
+InOrderDynInst::releaseReq(ResourceRequest* req)
+{
+ std::list<ResourceRequest*>::iterator list_it = reqList.begin();
+ std::list<ResourceRequest*>::iterator list_end = reqList.end();
+
+ while(list_it != list_end) {
+ if((*list_it)->getResIdx() == req->getResIdx() &&
+ (*list_it)->getSlot() == req->getSlot()) {
+ DPRINTF(InOrderDynInst, "[tid:%u]: [sn:%i] Done with request to %s.\n",
+ threadNumber, seqNum, req->res->name());
+ reqList.erase(list_it);
+ return;
+ }
+ list_it++;
+ }
+
+ panic("Releasing Res. Request That Isnt There!\n");
+}
+
+/** Records an integer source register being set to a value. */
+void
+InOrderDynInst::setIntSrc(int idx, uint64_t val)
+{
+ DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i being set to %#x.\n",
+ threadNumber, seqNum, idx, val);
+ instSrc[idx].integer = val;
+}
+
+/** Records an fp register being set to a value. */
+void
+InOrderDynInst::setFloatSrc(int idx, FloatReg val, int width)
+{
+ if (width == 32)
+ instSrc[idx].fp = val;
+ else if (width == 64)
+ instSrc[idx].dbl = val;
+ else
+ panic("Unsupported width!");
+}
+
+/** Records an fp register being set to an integer value. */
+void
+InOrderDynInst::setFloatRegBitsSrc(int idx, uint64_t val)
+{
+ instSrc[idx].integer = val;
+}
+
+/** Reads a integer register. */
+IntReg
+InOrderDynInst::readIntRegOperand(const StaticInst *si, int idx, unsigned tid)
+{
+ DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Source Value %i read as %#x.\n",
+ threadNumber, seqNum, idx, instSrc[idx].integer);
+ return instSrc[idx].integer;
+}
+
+/** Reads a FP register. */
+FloatReg
+InOrderDynInst::readFloatRegOperand(const StaticInst *si, int idx, int width)
+{
+ return instSrc[idx].fp;
+}
+
+
+/** Reads a FP register as a integer. */
+FloatRegBits
+InOrderDynInst::readFloatRegOperandBits(const StaticInst *si, int idx, int width)
+{
+ return instSrc[idx].integer;
+}
+
+/** Reads a miscellaneous register. */
+MiscReg
+InOrderDynInst::readMiscReg(int misc_reg)
+{
+ return this->cpu->readMiscReg(misc_reg, threadNumber);
+}
+
+/** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+MiscReg
+InOrderDynInst::readMiscRegNoEffect(int misc_reg)
+{
+ return this->cpu->readMiscRegNoEffect(misc_reg, threadNumber);
+}
+
+/** Reads a miscellaneous register. */
+MiscReg
+InOrderDynInst::readMiscRegOperandNoEffect(const StaticInst *si, int idx)
+{
+ int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+ return cpu->readMiscRegNoEffect(reg, this->threadNumber);
+}
+
+/** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+MiscReg
+InOrderDynInst::readMiscRegOperand(const StaticInst *si, int idx)
+{
+ int reg = si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag;
+ return this->cpu->readMiscReg(reg, this->threadNumber);
+}
+
+/** Sets a misc. register. */
+void
+InOrderDynInst::setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
+{
+ instResult[si->destRegIdx(idx)].val.integer = val;
+ instResult[si->destRegIdx(idx)].tick = curTick;
+
+ this->cpu->setMiscRegNoEffect(
+ si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ val, this->threadNumber);
+}
+
+/** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+void
+InOrderDynInst::setMiscRegOperand(const StaticInst *si, int idx,
+ const MiscReg &val)
+{
+ instResult[si->destRegIdx(idx)].val.integer = val;
+ instResult[si->destRegIdx(idx)].tick = curTick;
+
+ this->cpu->setMiscReg(
+ si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ val, this->threadNumber);
+}
+
+MiscReg
+InOrderDynInst::readRegOtherThread(unsigned reg_idx, int tid)
+{
+ if (tid == -1) {
+ tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
+ }
+
+ if (reg_idx < FP_Base_DepTag) { // Integer Register File
+ return this->cpu->readIntReg(reg_idx, tid);
+ } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
+ reg_idx -= FP_Base_DepTag;
+ return this->cpu->readFloatRegBits(reg_idx, tid);
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ return this->cpu->readMiscReg(reg_idx, tid); // Misc. Register File
+ }
+}
+
+/** Sets a Integer register. */
+void
+InOrderDynInst::setIntRegOperand(const StaticInst *si, int idx, IntReg val)
+{
+ instResult[idx].val.integer = val;
+ instResult[idx].tick = curTick;
+}
+
+/** Sets a FP register. */
+void
+InOrderDynInst::setFloatRegOperand(const StaticInst *si, int idx, FloatReg val, int width)
+{
+ if (width == 32)
+ instResult[idx].val.fp = val;
+ else if (width == 64)
+ instResult[idx].val.dbl = val;
+ else
+ panic("Unsupported Floating Point Width!");
+
+ instResult[idx].tick = curTick;
+}
+
+/** Sets a FP register as a integer. */
+void
+InOrderDynInst::setFloatRegOperandBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+{
+ instResult[idx].val.integer = val;
+ instResult[idx].tick = curTick;
+}
+
+/** Sets a misc. register. */
+/* Alter this when wanting to *speculate* on Miscellaneous registers */
+void
+InOrderDynInst::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+{
+ this->cpu->setMiscRegNoEffect(misc_reg, val, threadNumber);
+}
+
+/** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+/* Alter this if/when wanting to *speculate* on Miscellaneous registers */
+void
+InOrderDynInst::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ this->cpu->setMiscReg(misc_reg, val, threadNumber);
+}
+
+void
+InOrderDynInst::setRegOtherThread(unsigned reg_idx, const MiscReg &val, int tid)
+{
+ if (tid == -1) {
+ tid = TheISA::getTargetThread(this->cpu->tcBase(threadNumber));
+ }
+
+ if (reg_idx < FP_Base_DepTag) { // Integer Register File
+ this->cpu->setIntReg(reg_idx, val, tid);
+ } else if (reg_idx < Ctrl_Base_DepTag) { // Float Register File
+ reg_idx -= FP_Base_DepTag;
+ this->cpu->setFloatRegBits(reg_idx, val, tid);
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ this->cpu->setMiscReg(reg_idx, val, tid); // Misc. Register File
+ }
+}
+
+void
+InOrderDynInst::deallocateContext(int thread_num)
+{
+ this->cpu->deallocateContext(thread_num);
+}
+
+void
+InOrderDynInst::enableVirtProcElement(unsigned vpe)
+{
+ this->cpu->enableVirtProcElement(vpe);
+}
+
+void
+InOrderDynInst::disableVirtProcElement(unsigned vpe)
+{
+ this->cpu->disableVirtProcElement(threadNumber, vpe);
+}
+
+void
+InOrderDynInst::enableMultiThreading(unsigned vpe)
+{
+ this->cpu->enableMultiThreading(vpe);
+}
+
+void
+InOrderDynInst::disableMultiThreading(unsigned vpe)
+{
+ this->cpu->disableMultiThreading(threadNumber, vpe);
+}
+
+void
+InOrderDynInst::setThreadRescheduleCondition(uint32_t cond)
+{
+ this->cpu->setThreadRescheduleCondition(cond);
+}
+
+template<class T>
+inline Fault
+InOrderDynInst::read(Addr addr, T &data, unsigned flags)
+{
+ return cpu->read(this);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint64_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint32_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint16_t &data, unsigned flags);
+
+template
+Fault
+InOrderDynInst::read(Addr addr, uint8_t &data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, double &data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, float &data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+template<>
+Fault
+InOrderDynInst::read(Addr addr, int32_t &data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+template<class T>
+inline Fault
+InOrderDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ //memcpy(memData, gtoh(data), sizeof(T));
+ storeData = data;
+
+ DPRINTF(InOrderDynInst, "[tid:%i]: [sn:%i] Setting store data to %#x.\n",
+ threadNumber, seqNum, memData);
+ return cpu->write(this);
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+InOrderDynInst::write(uint64_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint32_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint16_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+template
+Fault
+InOrderDynInst::write(uint8_t data, Addr addr,
+ unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+InOrderDynInst::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+InOrderDynInst::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+
+template<>
+Fault
+InOrderDynInst::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+void
+InOrderDynInst::dump()
+{
+ cprintf("T%d : %#08d `", threadNumber, PC);
+ cout << staticInst->disassemble(PC);
+ cprintf("'\n");
+}
+
+void
+InOrderDynInst::dump(std::string &outstring)
+{
+ std::ostringstream s;
+ s << "T" << threadNumber << " : 0x" << PC << " "
+ << staticInst->disassemble(PC);
+
+ outstring = s.str();
+}
+
+
+#define NOHASH
+#ifndef NOHASH
+
+#include "base/hashmap.hh"
+
+unsigned int MyHashFunc(const InOrderDynInst *addr)
+{
+ unsigned a = (unsigned)addr;
+ unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+ return hash;
+}
+
+typedef m5::hash_map<const InOrderDynInst *, const InOrderDynInst *, MyHashFunc>
+my_hash_t;
+
+my_hash_t thishash;
+#endif
diff --git a/src/cpu/inorder/inorder_dyn_inst.hh b/src/cpu/inorder/inorder_dyn_inst.hh
new file mode 100644
index 000000000..55c61ffb9
--- /dev/null
+++ b/src/cpu/inorder/inorder_dyn_inst.hh
@@ -0,0 +1,971 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * 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.
+ *
+ * Authors: Kevin Lim
+ * Korey Sewell
+ */
+
+#ifndef __CPU_INORDER_DYN_INST_HH__
+#define __CPU_INORDER_DYN_INST_HH__
+
+#include <bitset>
+#include <list>
+#include <string>
+
+#include "arch/faults.hh"
+#include "base/fast_alloc.hh"
+#include "base/trace.hh"
+#include "cpu/inorder/inorder_trace.hh"
+#include "config/full_system.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/op_class.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "mem/packet.hh"
+#include "sim/system.hh"
+
+/**
+ * @file
+ * Defines a dynamic instruction context for a inorder CPU model.
+ */
+
+// Forward declaration.
+class StaticInstPtr;
+class ResourceRequest;
+
+class InOrderDynInst : public FastAlloc, public RefCounted
+{
+ public:
+ // 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 type.
+ typedef TheISA::IntReg IntReg;
+ // Floating point register type.
+ typedef TheISA::FloatReg FloatReg;
+ // Floating point register type.
+ typedef TheISA::MiscReg MiscReg;
+
+ typedef short int PhysRegIndex;
+
+ /** The refcounted DynInst pointer to be used. In most cases this is
+ * what should be used, and not DynInst*.
+ */
+ typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+ // The list of instructions iterator type.
+ typedef std::list<DynInstPtr>::iterator ListIt;
+
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, /// Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, /// Max dest regs
+ };
+
+ public:
+ /** BaseDynInst constructor given a binary instruction.
+ * @param inst The binary instruction.
+ * @param PC The PC of the instruction.
+ * @param pred_PC The predicted next PC.
+ * @param seq_num The sequence number of the instruction.
+ * @param cpu Pointer to the instruction's CPU.
+ */
+ InOrderDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
+ InOrderCPU *cpu);
+
+ /** BaseDynInst constructor given a binary instruction.
+ * @param seq_num The sequence number of the instruction.
+ * @param cpu Pointer to the instruction's CPU.
+ * NOTE: Must set Binary Instrution through Member Function
+ */
+ InOrderDynInst(InOrderCPU *cpu, InOrderThreadState *state, InstSeqNum seq_num,
+ unsigned tid);
+
+ /** BaseDynInst constructor given a StaticInst pointer.
+ * @param _staticInst The StaticInst for this BaseDynInst.
+ */
+ InOrderDynInst(StaticInstPtr &_staticInst);
+
+ /** Skeleton Constructor. */
+ InOrderDynInst();
+
+ /** InOrderDynInst destructor. */
+ ~InOrderDynInst();
+
+ public:
+ /** The sequence number of the instruction. */
+ InstSeqNum seqNum;
+
+ /** The sequence number of the instruction. */
+ InstSeqNum bdelaySeqNum;
+
+ enum Status {
+ RegDepMapEntry, /// Instruction has been entered onto the RegDepMap
+ IqEntry, /// Instruction is in the IQ
+ RobEntry, /// Instruction is in the ROB
+ LsqEntry, /// Instruction is in the LSQ
+ Completed, /// Instruction has completed
+ ResultReady, /// Instruction has its result
+ CanIssue, /// Instruction can issue and execute
+ Issued, /// Instruction has issued
+ Executed, /// Instruction has executed
+ CanCommit, /// Instruction can commit
+ AtCommit, /// Instruction has reached commit
+ Committed, /// Instruction has committed
+ Squashed, /// Instruction is squashed
+ SquashedInIQ, /// Instruction is squashed in the IQ
+ SquashedInLSQ, /// Instruction is squashed in the LSQ
+ SquashedInROB, /// Instruction is squashed in the ROB
+ RecoverInst, /// Is a recover instruction
+ BlockingInst, /// Is a blocking instruction
+ ThreadsyncWait, /// Is a thread synchronization instruction
+ SerializeBefore, /// Needs to serialize on
+ /// instructions ahead of it
+ SerializeAfter, /// Needs to serialize instructions behind it
+ SerializeHandled, /// Serialization has been handled
+ NumStatus
+ };
+
+ /** The status of this BaseDynInst. Several bits can be set. */
+ std::bitset<NumStatus> status;
+
+ /** The thread this instruction is from. */
+ short threadNumber;
+
+ /** data address space ID, for loads & stores. */
+ short asid;
+
+ /** The virtual processor number */
+ short virtProcNumber;
+
+ /** The StaticInst used by this BaseDynInst. */
+ StaticInstPtr staticInst;
+
+ /** InstRecord that tracks this instructions. */
+ Trace::InOrderTraceRecord *traceData;
+
+ /** Pointer to the Impl's CPU object. */
+ InOrderCPU *cpu;
+
+ /** Pointer to the thread state. */
+ InOrderThreadState *thread;
+
+ /** The kind of fault this instruction has generated. */
+ Fault fault;
+
+ /** The memory request. */
+ Request *req;
+
+ /** Pointer to the data for the memory access. */
+ uint8_t *memData;
+
+ /** Data used for a store for operation. */
+ uint64_t loadData;
+
+ /** Data used for a store for operation. */
+ uint64_t storeData;
+
+ /** The resource schedule for this inst */
+ ThePipeline::ResSchedule resSched;
+
+ /** List of active resource requests for this instruction */
+ std::list<ResourceRequest*> reqList;
+
+ /** The effective virtual address (lds & stores only). */
+ Addr effAddr;
+
+ /** The effective physical address. */
+ Addr physEffAddr;
+
+ /** Effective virtual address for a copy source. */
+ Addr copySrcEffAddr;
+
+ /** Effective physical address for a copy source. */
+ Addr copySrcPhysEffAddr;
+
+ /** The memory request flags (from translation). */
+ unsigned memReqFlags;
+
+ /** How many source registers are ready. */
+ unsigned readyRegs;
+
+ /** An instruction src/dest has to be one of these types */
+ union InstValue {
+ uint64_t integer;
+ float fp;
+ double dbl;
+ };
+
+ /** Result of an instruction execution */
+ struct InstResult {
+ InstValue val;
+ Tick tick;
+ };
+
+ /** The source of the instruction; assumes for now that there's only one
+ * destination register.
+ */
+ InstValue instSrc[MaxInstSrcRegs];
+
+ /** The result of the instruction; assumes for now that there's only one
+ * destination register.
+ */
+ InstResult instResult[MaxInstDestRegs];
+
+ /** PC of this instruction. */
+ Addr PC;
+
+ /** Next non-speculative PC. It is not filled in at fetch, but rather
+ * once the target of the branch is truly known (either decode or
+ * execute).
+ */
+ Addr nextPC;
+
+ /** Next next non-speculative PC. It is not filled in at fetch, but rather
+ * once the target of the branch is truly known (either decode or
+ * execute).
+ */
+ Addr nextNPC;
+
+ /** Predicted next PC. */
+ Addr predPC;
+
+ /** Address to fetch from */
+ Addr fetchAddr;
+
+ /** Address to get/write data from/to */
+ Addr memAddr;
+
+ /** Whether or not the source register is ready.
+ * @todo: Not sure this should be here vs the derived class.
+ */
+ bool _readySrcRegIdx[MaxInstSrcRegs];
+
+ /** 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];
+
+ int nextStage;
+
+ /* vars to keep track of InstStage's - used for resource sched defn */
+ int nextInstStageNum;
+ ThePipeline::InstStage *currentInstStage;
+ std::list<ThePipeline::InstStage*> instStageList;
+
+ private:
+ /** Function to initialize variables in the constructors. */
+ void initVars();
+
+ public:
+ Tick memTime;
+
+ ////////////////////////////////////////////////////////////
+ //
+ // BASE INSTRUCTION INFORMATION.
+ //
+ ////////////////////////////////////////////////////////////
+ void setMachInst(ExtMachInst inst);
+
+ /** Sets the StaticInst. */
+ void setStaticInst(StaticInstPtr &static_inst);
+
+ /** Sets the sequence number. */
+ void setSeqNum(InstSeqNum seq_num) { seqNum = seq_num; }
+
+ /** Sets the ASID. */
+ void setASID(short addr_space_id) { asid = addr_space_id; }
+
+ /** Reads the thread id. */
+ short readTid() { return threadNumber; }
+
+ /** Sets the thread id. */
+ void setTid(unsigned tid) { threadNumber = tid; }
+
+ void setVpn(int id) { virtProcNumber = id; }
+
+ int readVpn() { return virtProcNumber; }
+
+ /** Sets the pointer to the thread state. */
+ void setThreadState(InOrderThreadState *state) { thread = state; }
+
+ /** Returns the thread context. */
+ ThreadContext *tcBase() { return thread->getTC(); }
+
+ /** Returns the fault type. */
+ Fault getFault() { return fault; }
+
+ ////////////////////////////////////////////////////////////
+ //
+ // INSTRUCTION TYPES - Forward checks to StaticInst object.
+ //
+ ////////////////////////////////////////////////////////////
+ bool isNop() const { return staticInst->isNop(); }
+ bool isMemRef() const { return staticInst->isMemRef(); }
+ bool isLoad() const { return staticInst->isLoad(); }
+ bool isStore() const { return staticInst->isStore(); }
+ bool isStoreConditional() const
+ { return staticInst->isStoreConditional(); }
+ bool isInstPrefetch() const { return staticInst->isInstPrefetch(); }
+ bool isDataPrefetch() const { return staticInst->isDataPrefetch(); }
+ bool isCopy() const { return staticInst->isCopy(); }
+ bool isInteger() const { return staticInst->isInteger(); }
+ bool isFloating() const { return staticInst->isFloating(); }
+ bool isControl() const { return staticInst->isControl(); }
+ bool isCall() const { return staticInst->isCall(); }
+ bool isReturn() const { return staticInst->isReturn(); }
+ bool isDirectCtrl() const { return staticInst->isDirectCtrl(); }
+ bool isIndirectCtrl() const { return staticInst->isIndirectCtrl(); }
+ bool isCondCtrl() const { return staticInst->isCondCtrl(); }
+ bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
+ bool isCondDelaySlot() const { return staticInst->isCondDelaySlot(); }
+
+ bool isThreadSync() const { return staticInst->isThreadSync(); }
+ bool isSerializing() const { return staticInst->isSerializing(); }
+ bool isSerializeBefore() const
+ { return staticInst->isSerializeBefore() || status[SerializeBefore]; }
+ bool isSerializeAfter() const
+ { return staticInst->isSerializeAfter() || status[SerializeAfter]; }
+ bool isMemBarrier() const { return staticInst->isMemBarrier(); }
+ bool isWriteBarrier() const { return staticInst->isWriteBarrier(); }
+ bool isNonSpeculative() const { return staticInst->isNonSpeculative(); }
+ bool isQuiesce() const { return staticInst->isQuiesce(); }
+ bool isIprAccess() const { return staticInst->isIprAccess(); }
+ bool isUnverifiable() const { return staticInst->isUnverifiable(); }
+
+ /////////////////////////////////////////////
+ //
+ // RESOURCE SCHEDULING
+ //
+ /////////////////////////////////////////////
+
+ void setNextStage(int stage_num) { nextStage = stage_num; }
+ int getNextStage() { return nextStage; }
+
+ ThePipeline::InstStage *addStage();
+ ThePipeline::InstStage *addStage(int stage);
+ ThePipeline::InstStage *currentStage() { return currentInstStage; }
+ void deleteStages();
+
+ /** Add A Entry To Reource Schedule */
+ void addToSched(ThePipeline::ScheduleEntry* sched_entry)
+ { resSched.push(sched_entry); }
+
+
+ /** Print Resource Schedule */
+ void printSched()
+ {
+ using namespace ThePipeline;
+
+ ResSchedule tempSched;
+ std::cerr << "\tInst. Res. Schedule: ";
+ while (!resSched.empty()) {
+ std::cerr << '\t' << resSched.top()->stageNum << "-"
+ << resSched.top()->resNum << ", ";
+
+ tempSched.push(resSched.top());
+ resSched.pop();
+ }
+
+ std::cerr << std::endl;
+ resSched = tempSched;
+ }
+
+ /** Return Next Resource Stage To Be Used */
+ int nextResStage()
+ {
+ if (resSched.empty())
+ return -1;
+ else
+ return resSched.top()->stageNum;
+ }
+
+
+ /** Return Next Resource To Be Used */
+ int nextResource()
+ {
+ if (resSched.empty())
+ return -1;
+ else
+ return resSched.top()->resNum;
+ }
+
+ /** Remove & Deallocate a schedule entry */
+ void popSchedEntry()
+ {
+ if (!resSched.empty()) {
+ ThePipeline::ScheduleEntry* sked = resSched.top();
+ resSched.pop();
+ delete sked;
+ }
+ }
+
+ /** Release a Resource Request (Currently Unused) */
+ void releaseReq(ResourceRequest* req);
+
+ ////////////////////////////////////////////
+ //
+ // INSTRUCTION EXECUTION
+ //
+ ////////////////////////////////////////////
+ /** Returns the opclass of this instruction. */
+ OpClass opClass() const { return staticInst->opClass(); }
+
+ /** Executes the instruction.*/
+ Fault execute();
+
+ unsigned curResSlot;
+
+ unsigned getCurResSlot() { return curResSlot; }
+
+ void setCurResSlot(unsigned slot_num) { curResSlot = slot_num; }
+
+ /** Calls a syscall. */
+ void syscall(int64_t callnum);
+ void prefetch(Addr addr, unsigned flags);
+ void writeHint(Addr addr, int size, unsigned flags);
+ Fault copySrcTranslate(Addr src);
+ Fault copy(Addr dest);
+
+ ////////////////////////////////////////////////////////////
+ //
+ // MULTITHREADING INTERFACE TO CPU MODELS
+ //
+ ////////////////////////////////////////////////////////////
+ virtual void deallocateContext(int thread_num);
+
+ virtual void enableVirtProcElement(unsigned vpe);
+ virtual void disableVirtProcElement(unsigned vpe);
+
+ virtual void enableMultiThreading(unsigned vpe);
+ virtual void disableMultiThreading(unsigned vpe);
+
+ virtual void setThreadRescheduleCondition(uint32_t cond);
+
+ ////////////////////////////////////////////////////////////
+ //
+ // PROGRAM COUNTERS - PC/NPC/NPC
+ //
+ ////////////////////////////////////////////////////////////
+ /** Read the PC of this instruction. */
+ const Addr readPC() const { return PC; }
+
+ /** Sets the PC of this instruction. */
+ void setPC(Addr pc) { PC = pc; }
+
+ /** Returns the next PC. This could be the speculative next PC if it is
+ * called prior to the actual branch target being calculated.
+ */
+ Addr readNextPC() { return nextPC; }
+
+ /** Set the next PC of this instruction (its actual target). */
+ void setNextPC(uint64_t val) { nextPC = val; }
+
+ /** Returns the next NPC. This could be the speculative next NPC if it is
+ * called prior to the actual branch target being calculated.
+ */
+ Addr readNextNPC() { return nextNPC; }
+
+ /** Set the next PC of this instruction (its actual target). */
+ void setNextNPC(uint64_t val) { nextNPC = val; }
+
+ ////////////////////////////////////////////////////////////
+ //
+ // BRANCH PREDICTION
+ //
+ ////////////////////////////////////////////////////////////
+ /** Set the predicted target of this current instruction. */
+ void setPredTarg(Addr predicted_PC) { predPC = predicted_PC; }
+
+ /** Returns the predicted target of the branch. */
+ Addr readPredTarg() { return predPC; }
+
+ /** Returns whether the instruction was predicted taken or not. */
+ bool predTaken() { return predictTaken; }
+
+ /** Returns whether the instruction mispredicted. */
+ bool mispredicted()
+ {
+ // Special case since a not-taken, cond. delay slot, effectively
+ // nullifies the delay slot instruction
+ if (isCondDelaySlot() && !predictTaken) {
+ return predPC != nextPC;
+ } else {
+ return predPC != nextNPC;
+ }
+ }
+
+ /** Returns whether the instruction mispredicted. */
+ bool mistargeted() { return predPC != nextNPC; }
+
+ /** Returns the branch target address. */
+ Addr branchTarget() const { return staticInst->branchTarget(PC); }
+
+ /** Checks whether or not this instruction has had its branch target
+ * calculated yet. For now it is not utilized and is hacked to be
+ * always false.
+ * @todo: Actually use this instruction.
+ */
+ bool doneTargCalc() { return false; }
+
+ void setBranchPred(bool prediction) { predictTaken = prediction; }
+
+ int squashingStage;
+
+ bool predictTaken;
+
+ bool procDelaySlotOnMispred;
+
+ ////////////////////////////////////////////
+ //
+ // MEMORY ACCESS
+ //
+ ////////////////////////////////////////////
+ /**
+ * Does a read to a given address.
+ * @param addr The address to read.
+ * @param data The read's data is written into this parameter.
+ * @param flags The request's flags.
+ * @return Returns any fault due to the read.
+ */
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ /**
+ * Does a write to a given address.
+ * @param data The data to be written.
+ * @param addr The address to write to.
+ * @param flags The request's flags.
+ * @param res The result of the write (for load locked/store conditionals).
+ * @return Returns any fault due to the write.
+ */
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags,
+ uint64_t *res);
+
+ /** Initiates a memory access - Calculate Eff. Addr & Initiate Memory Access
+ * Only valid for memory operations.
+ */
+ Fault initiateAcc();
+
+ /** Completes a memory access - Only valid for memory operations. */
+ Fault completeAcc(Packet *pkt);
+
+ /** Calculates Eff. Addr. part of a memory instruction. */
+ Fault calcEA();
+
+ /** Read Effective Address from instruction & do memory access */
+ Fault memAccess();
+
+ RequestPtr memReq;
+
+ bool memAddrReady;
+
+ bool validMemAddr()
+ { return memAddrReady; }
+
+ void setMemAddr(Addr addr)
+ { memAddr = addr; memAddrReady = true;}
+
+ void unsetMemAddr()
+ { memAddrReady = false;}
+
+ Addr getMemAddr()
+ { return memAddr; }
+
+ int getMemAccSize() { return staticInst->memAccSize(this); }
+
+ int getMemFlags() { return staticInst->memAccFlags(); }
+
+ /** Sets the effective address. */
+ void setEA(Addr &ea) { instEffAddr = ea; eaCalcDone = true; }
+
+ /** Returns the effective address. */
+ const Addr &getEA() const { return instEffAddr; }
+
+ /** Returns whether or not the eff. addr. calculation has been completed. */
+ bool doneEACalc() { return eaCalcDone; }
+
+ /** Returns whether or not the eff. addr. source registers are ready.
+ * Assume that src registers 1..n-1 are the ones that the
+ * EA calc depends on. (i.e. src reg 0 is the source of the data to be
+ * stored)
+ */
+ bool eaSrcsReady()
+ {
+ for (int i = 1; i < numSrcRegs(); ++i) {
+ if (!_readySrcRegIdx[i])
+ return false;
+ }
+
+ return true;
+ }
+
+ //////////////////////////////////////////////////
+ //
+ // SOURCE-DESTINATION REGISTER INDEXING
+ //
+ //////////////////////////////////////////////////
+ /** Returns the number of source registers. */
+ int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
+
+ /** Returns the number of destination registers. */
+ int8_t numDestRegs() const { return staticInst->numDestRegs(); }
+
+ // the following are used to track physical register usage
+ // for machines with separate int & FP reg files
+ int8_t numFPDestRegs() const { return staticInst->numFPDestRegs(); }
+ int8_t numIntDestRegs() const { return staticInst->numIntDestRegs(); }
+
+ /** Returns the logical register index of the i'th destination register. */
+ RegIndex destRegIdx(int i) const { return staticInst->destRegIdx(i); }
+
+ /** Returns the logical register index of the i'th source register. */
+ RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
+
+ //////////////////////////////////////////////////
+ //
+ // RENAME/PHYSICAL REGISTER FILE SUPPORT
+ //
+ //////////////////////////////////////////////////
+ /** 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];
+ }
+
+ /** Returns if a source register is ready. */
+ bool isReadySrcRegIdx(int idx) const
+ {
+ return this->_readySrcRegIdx[idx];
+ }
+
+ /** Records that one of the source registers is ready. */
+ void markSrcRegReady()
+ {
+ if (++readyRegs == numSrcRegs()) {
+ status.set(CanIssue);
+ }
+ }
+
+ /** Marks a specific register as ready. */
+ void markSrcRegReady(RegIndex src_idx)
+ {
+ _readySrcRegIdx[src_idx] = true;
+
+ markSrcRegReady();
+ }
+
+ /** 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;
+ }
+
+
+ PhysRegIndex readDestRegIdx(int idx)
+ {
+ return _destRegIdx[idx];
+ }
+
+ void setDestRegIdx(int idx, PhysRegIndex dest_idx)
+ {
+ _destRegIdx[idx] = dest_idx;
+ }
+
+ int getDestIdxNum(PhysRegIndex dest_idx)
+ {
+ for (int i=0; i < staticInst->numDestRegs(); i++) {
+ if (_destRegIdx[i] == dest_idx)
+ return i;
+ }
+
+ return -1;
+ }
+
+ PhysRegIndex readSrcRegIdx(int idx)
+ {
+ return _srcRegIdx[idx];
+ }
+
+ void setSrcRegIdx(int idx, PhysRegIndex src_idx)
+ {
+ _srcRegIdx[idx] = src_idx;
+ }
+
+ int getSrcIdxNum(PhysRegIndex src_idx)
+ {
+ for (int i=0; i < staticInst->numSrcRegs(); i++) {
+ if (_srcRegIdx[i] == src_idx)
+ return i;
+ }
+
+ return -1;
+ }
+
+ ////////////////////////////////////////////////////
+ //
+ // SOURCE-DESTINATION REGISTER VALUES
+ //
+ ////////////////////////////////////////////////////
+
+ /** Functions that sets an integer or floating point
+ * source register to a value. */
+ void setIntSrc(int idx, uint64_t val);
+ void setFloatSrc(int idx, FloatReg val, int width = 32);
+ void setFloatRegBitsSrc(int idx, uint64_t val);
+
+ uint64_t* getIntSrcPtr(int idx) { return &instSrc[idx].integer; }
+ uint64_t readIntSrc(int idx) { return instSrc[idx].integer; }
+
+ /** These Instructions read a integer/float/misc. source register
+ * value in the instruction. The instruction's execute function will
+ * call these and it is the interface that is used by the ISA descr.
+ * language (which is why the name isnt readIntSrc(...)) Note: That
+ * the source reg. value is set using the setSrcReg() function.
+ */
+ IntReg readIntRegOperand(const StaticInst *si, int idx, unsigned tid=0);
+ FloatReg readFloatRegOperand(const StaticInst *si, int idx,
+ int width = TheISA::SingleWidth);
+ FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
+ int width = TheISA::SingleWidth);
+ MiscReg readMiscReg(int misc_reg);
+ MiscReg readMiscRegNoEffect(int misc_reg);
+ MiscReg readMiscRegOperand(const StaticInst *si, int idx);
+ MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx);
+
+ /** Returns the result value instruction. */
+ uint64_t readIntResult(int idx) { return instResult[idx].val.integer; }
+ float readFloatResult(int idx) { return instResult[idx].val.fp; }
+ double readDoubleResult(int idx) { return instResult[idx].val.dbl; }
+ Tick readResultTime(int idx) { return instResult[idx].tick; }
+
+ uint64_t* getIntResultPtr(int idx) { return &instResult[idx].val.integer; }
+
+ /** This is the interface that an instruction will use to write
+ * it's destination register.
+ */
+ void setIntRegOperand(const StaticInst *si, int idx, IntReg val);
+ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
+ int width = TheISA::SingleWidth);
+ void setFloatRegOperandBits(const StaticInst *si, int idx, FloatRegBits val,
+ int width = TheISA::SingleWidth);
+ void setMiscReg(int misc_reg, const MiscReg &val);
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+ void setMiscRegOperand(const StaticInst *si, int idx, const MiscReg &val);
+ void setMiscRegOperandNoEffect(const StaticInst *si, int idx, const MiscReg &val);
+
+ virtual uint64_t readRegOtherThread(unsigned idx, int tid = -1);
+ virtual void setRegOtherThread(unsigned idx, const uint64_t &val, int tid = -1);
+
+ //////////////////////////////////////////////////////////////
+ //
+ // INSTRUCTION STATUS FLAGS (READ/SET)
+ //
+ //////////////////////////////////////////////////////////////
+ /** Sets this instruction as entered on the CPU Reg Dep Map */
+ void setRegDepEntry() { status.set(RegDepMapEntry); }
+
+ /** Returns whether or not the entry is on the CPU Reg Dep Map */
+ bool isRegDepEntry() const { return status[RegDepMapEntry]; }
+
+ /** Sets this instruction as completed. */
+ void setCompleted() { status.set(Completed); }
+
+ /** Returns whether or not this instruction is completed. */
+ bool isCompleted() const { return status[Completed]; }
+
+ /** Marks the result as ready. */
+ void setResultReady() { status.set(ResultReady); }
+
+ /** Returns whether or not the result is ready. */
+ bool isResultReady() const { return status[ResultReady]; }
+
+ /** Sets this instruction as ready to issue. */
+ void setCanIssue() { status.set(CanIssue); }
+
+ /** Returns whether or not this instruction is ready to issue. */
+ bool readyToIssue() const { return status[CanIssue]; }
+
+ /** Sets this instruction as issued from the IQ. */
+ void setIssued() { status.set(Issued); }
+
+ /** Returns whether or not this instruction has issued. */
+ bool isIssued() const { return status[Issued]; }
+
+ /** Sets this instruction as executed. */
+ void setExecuted() { status.set(Executed); }
+
+ /** Returns whether or not this instruction has executed. */
+ bool isExecuted() const { return status[Executed]; }
+
+ /** Sets this instruction as ready to commit. */
+ void setCanCommit() { status.set(CanCommit); }
+
+ /** Clears this instruction as being ready to commit. */
+ void clearCanCommit() { status.reset(CanCommit); }
+
+ /** Returns whether or not this instruction is ready to commit. */
+ bool readyToCommit() const { return status[CanCommit]; }
+
+ void setAtCommit() { status.set(AtCommit); }
+
+ bool isAtCommit() { return status[AtCommit]; }
+
+ /** Sets this instruction as committed. */
+ void setCommitted() { status.set(Committed); }
+
+ /** Returns whether or not this instruction is committed. */
+ bool isCommitted() const { return status[Committed]; }
+
+ /** Sets this instruction as squashed. */
+ void setSquashed() { status.set(Squashed); }
+
+ /** Returns whether or not this instruction is squashed. */
+ bool isSquashed() const { return status[Squashed]; }
+
+ /** Temporarily sets this instruction as a serialize before instruction. */
+ void setSerializeBefore() { status.set(SerializeBefore); }
+
+ /** Clears the serializeBefore part of this instruction. */
+ void clearSerializeBefore() { status.reset(SerializeBefore); }
+
+ /** Checks if this serializeBefore is only temporarily set. */
+ bool isTempSerializeBefore() { return status[SerializeBefore]; }
+
+ /** Temporarily sets this instruction as a serialize after instruction. */
+ void setSerializeAfter() { status.set(SerializeAfter); }
+
+ /** Clears the serializeAfter part of this instruction.*/
+ void clearSerializeAfter() { status.reset(SerializeAfter); }
+
+ /** Checks if this serializeAfter is only temporarily set. */
+ bool isTempSerializeAfter() { return status[SerializeAfter]; }
+
+ /** Sets the serialization part of this instruction as handled. */
+ void setSerializeHandled() { status.set(SerializeHandled); }
+
+ /** Checks if the serialization part of this instruction has been
+ * handled. This does not apply to the temporary serializing
+ * state; it only applies to this instruction's own permanent
+ * serializing state.
+ */
+ bool isSerializeHandled() { return status[SerializeHandled]; }
+
+ private:
+ /** Instruction effective address.
+ * @todo: Consider if this is necessary or not.
+ */
+ Addr instEffAddr;
+
+ /** Whether or not the effective address calculation is completed.
+ * @todo: Consider if this is necessary or not.
+ */
+ bool eaCalcDone;
+
+ public:
+ /** Whether or not the memory operation is done. */
+ bool memOpDone;
+
+ public:
+ /** Load queue index. */
+ int16_t lqIdx;
+
+ /** Store queue index. */
+ int16_t sqIdx;
+
+ /** Iterator pointing to this BaseDynInst in the list of all insts. */
+ ListIt instListIt;
+
+ /** Returns iterator to this instruction in the list of all insts. */
+ ListIt &getInstListIt() { return instListIt; }
+
+ /** Sets iterator for this instruction in the list of all insts. */
+ void setInstListIt(ListIt _instListIt) { instListIt = _instListIt; }
+
+ /** Count of total number of dynamic instructions. */
+ static int instcount;
+
+ /** Dumps out contents of this BaseDynInst. */
+ void dump();
+
+ /** Dumps out contents of this BaseDynInst into given string. */
+ void dump(std::string &outstring);
+
+
+ //inline int curCount() { return curCount(); }
+};
+
+
+#endif // __CPU_BASE_DYN_INST_HH__
diff --git a/src/dev/pitreg.h b/src/cpu/inorder/inorder_trace.cc
index d42925a41..f12a1b7a9 100644
--- a/src/dev/pitreg.h
+++ b/src/cpu/inorder/inorder_trace.cc
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -25,51 +26,69 @@
* (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: Miguel Serrano
+ * Authors: Korey Sewell
*/
-/* @file
- * Device register definitions for a device's PCI config space
- */
+#include <iomanip>
-#ifndef __PITREG_H__
-#define __PITREG_H__
+#include "cpu/exetrace.hh"
+#include "cpu/inorder/inorder_trace.hh"
+#include "cpu/static_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/thread_context.hh"
+#include "params/InOrderTrace.hh"
-#include <sys/types.h>
+using namespace std;
+using namespace TheISA;
-// Control Word Format
+namespace Trace {
-#define PIT_SEL_SHFT 0x6
-#define PIT_RW_SHFT 0x4
-#define PIT_MODE_SHFT 0x1
-#define PIT_BCD_SHFT 0x0
+inline void
+Trace::InOrderTraceRecord::dumpTicks(std::ostream &outs)
+{
+ if (!stageTrace) {
+ ccprintf(outs, "%7d: ", when);
+ } else {
+ ccprintf(outs, "");
+ for (int i=0; i < stageCycle.size(); i++) {
+ if (i < stageCycle.size() - 1)
+ outs << dec << stageCycle[i] << "-";
+ else
+ outs << dec << stageCycle[i] << ":";
+ }
+ }
+}
-#define PIT_SEL_MASK 0x3
-#define PIT_RW_MASK 0x3
-#define PIT_MODE_MASK 0x7
-#define PIT_BCD_MASK 0x1
+InOrderTraceRecord *
+InOrderTrace::getInstRecord(unsigned num_stages, bool stage_tracing,
+ ThreadContext *tc)
+{
+ if (!IsOn(ExecEnable))
+ return NULL;
-#define GET_CTRL_FIELD(x, s, m) (((x) >> s) & m)
-#define GET_CTRL_SEL(x) GET_CTRL_FIELD(x, PIT_SEL_SHFT, PIT_SEL_MASK)
-#define GET_CTRL_RW(x) GET_CTRL_FIELD(x, PIT_RW_SHFT, PIT_RW_MASK)
-#define GET_CTRL_MODE(x) GET_CTRL_FIELD(x, PIT_MODE_SHFT, PIT_MODE_MASK)
-#define GET_CTRL_BCD(x) GET_CTRL_FIELD(x, PIT_BCD_SHFT, PIT_BCD_MASK)
+ if (!Trace::enabled)
+ return NULL;
-#define PIT_READ_BACK 0x3
+ return new InOrderTraceRecord(num_stages, stage_tracing, tc);
+}
-#define PIT_RW_LATCH_COMMAND 0x0
-#define PIT_RW_LSB_ONLY 0x1
-#define PIT_RW_MSB_ONLY 0x2
-#define PIT_RW_16BIT 0x3
+InOrderTraceRecord *
+InOrderTrace::getInstRecord(Tick when, ThreadContext *tc,
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst, MicroPC upc)
+{
+ return new InOrderTraceRecord(ThePipeline::NumStages, true, tc);
+}
-#define PIT_MODE_INTTC 0x0
-#define PIT_MODE_ONESHOT 0x1
-#define PIT_MODE_RATEGEN 0x2
-#define PIT_MODE_SQWAVE 0x3
-#define PIT_MODE_SWSTROBE 0x4
-#define PIT_MODE_HWSTROBE 0x5
+/* namespace Trace */ }
-#define PIT_BCD_FALSE 0x0
-#define PIT_BCD_TRUE 0x1
+////////////////////////////////////////////////////////////////////////
+//
+// ExeTracer Simulation Object
+//
+Trace::InOrderTrace *
+InOrderTraceParams::create()
+{
+ return new Trace::InOrderTrace(this);
+};
-#endif // __PITREG_H__
diff --git a/src/cpu/inorder/inorder_trace.hh b/src/cpu/inorder/inorder_trace.hh
new file mode 100644
index 000000000..4338b438c
--- /dev/null
+++ b/src/cpu/inorder/inorder_trace.hh
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * 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.
+ *
+ * Authors: Korey Sewell
+ */
+
+#ifndef __INORDERTRACE_HH__
+#define __INORDERTRACE_HH__
+
+#include "base/trace.hh"
+#include "cpu/static_inst.hh"
+#include "sim/host.hh"
+#include "sim/insttracer.hh"
+#include "params/InOrderTrace.hh"
+#include "cpu/exetrace.hh"
+
+class ThreadContext;
+
+
+namespace Trace {
+
+class InOrderTraceRecord : public ExeTracerRecord
+{
+ public:
+ InOrderTraceRecord(unsigned num_stages, bool _stage_tracing,
+ ThreadContext *_thread, bool spec = false)
+ : ExeTracerRecord(0, _thread, NULL, 0, spec)
+ {
+ stageTrace = _stage_tracing;
+ stageCycle.resize(num_stages);
+ }
+
+ // Trace stage-by-stage execution of instructions.
+ bool stageTrace;
+ std::vector<Tick> stageCycle;
+
+ void dumpTicks(std::ostream &outs);
+
+ void
+ setStageCycle(int num_stage, Tick cur_cycle)
+ {
+ if (stageTrace) {
+ stageCycle[num_stage] = cur_cycle;
+ } else {
+ when = cur_cycle;
+ }
+ }
+
+ void
+ setStaticInst(const StaticInstPtr &_staticInst)
+ {
+ staticInst = _staticInst;
+ }
+ void setPC(Addr _pc) { PC = _pc; }
+};
+
+class InOrderTrace : public InstTracer
+{
+ public:
+ InOrderTrace(const InOrderTraceParams *p) : InstTracer(p)
+ {}
+
+ InOrderTraceRecord *
+ getInstRecord(unsigned num_stages, bool stage_tracing, ThreadContext *tc);
+
+ virtual InOrderTraceRecord *getInstRecord(Tick when, ThreadContext *tc,
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0);
+};
+
+/* namespace Trace */ }
+
+#endif // __EXETRACE_HH__
diff --git a/src/cpu/o3/params.hh b/src/cpu/inorder/params.hh
index b487778c6..51b7409ad 100755..100644
--- a/src/cpu/o3/params.hh
+++ b/src/cpu/inorder/params.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * 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
@@ -25,101 +25,45 @@
* (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: Kevin Lim
+ * Authors: Korey Sewell
*/
-#ifndef __CPU_O3_PARAMS_HH__
-#define __CPU_O3_PARAMS_HH__
+#ifndef __CPU_INORDER_PARAMS_HH__
+#define __CPU_INORDER_PARAMS_HH__
-#include "cpu/o3/cpu.hh"
+#include "cpu/base.hh"
//Forward declarations
-class FUPool;
+class FunctionalMemory;
+class Process;
+class MemObject;
+class MemInterface;
/**
- * This file defines the parameters that will be used for the O3CPU.
+ * This file defines the parameters that will be used for the InOrderCPU.
* This must be defined externally so that the Impl can have a params class
* defined that it can pass to all of the individual stages.
*/
-class O3Params : public BaseO3CPU::Params
+
+class InOrderParams : public BaseCPU::Params
{
public:
- unsigned activity;
- //
- // Pointers to key objects
- //
+ // Workloads
#if !FULL_SYSTEM
std::vector<Process *> workload;
Process *process;
#endif // FULL_SYSTEM
- BaseCPU *checker;
-
//
- // Caches
+ // Memory System/Caches
//
- // MemInterface *icacheInterface;
- // MemInterface *dcacheInterface;
-
unsigned cachePorts;
+ std::string fetchMemPort;
+ std::string dataMemPort;
//
- // Fetch
- //
- unsigned decodeToFetchDelay;
- unsigned renameToFetchDelay;
- unsigned iewToFetchDelay;
- unsigned commitToFetchDelay;
- unsigned fetchWidth;
-
- //
- // Decode
- //
- unsigned renameToDecodeDelay;
- unsigned iewToDecodeDelay;
- unsigned commitToDecodeDelay;
- unsigned fetchToDecodeDelay;
- unsigned decodeWidth;
-
- //
- // Rename
- //
- unsigned iewToRenameDelay;
- unsigned commitToRenameDelay;
- unsigned decodeToRenameDelay;
- unsigned renameWidth;
-
- //
- // IEW
- //
- unsigned commitToIEWDelay;
- unsigned renameToIEWDelay;
- unsigned issueToExecuteDelay;
- unsigned dispatchWidth;
- unsigned issueWidth;
- unsigned wbWidth;
- unsigned wbDepth;
- FUPool *fuPool;
-
- //
- // Commit
- //
- unsigned iewToCommitDelay;
- unsigned renameToROBDelay;
- unsigned commitWidth;
- unsigned squashWidth;
- Tick trapLatency;
- Tick fetchTrapLatency;
-
- //
- // Timebuffer sizes
- //
- unsigned backComSize;
- unsigned forwardComSize;
-
- //
- // Branch predictor (BP, BTB, RAS)
+ // Branch predictor (BP & BTB)
//
std::string predType;
unsigned localPredictorSize;
@@ -131,50 +75,50 @@ class O3Params : public BaseO3CPU::Params
unsigned globalHistoryBits;
unsigned choicePredictorSize;
unsigned choiceCtrBits;
-
unsigned BTBEntries;
unsigned BTBTagSize;
-
unsigned RASSize;
- //
- // Load store queue
- //
- unsigned LQEntries;
- unsigned SQEntries;
+ // Pipeline Parameters
+ unsigned stageWidth;
+
+ // InOrderCPU Simulation Parameters
+ unsigned instShiftAmt;
+ unsigned activity;
+ unsigned deferRegistration;
//
- // Memory dependence
+ // Memory Parameters
//
- unsigned SSITSize;
- unsigned LFSTSize;
+ unsigned memBlockSize;
//
- // Miscellaneous
+ // Multiply Divide Unit
//
- unsigned numPhysIntRegs;
- unsigned numPhysFloatRegs;
- unsigned numIQEntries;
- unsigned numROBEntries;
+ // @NOTE: If >1 MDU is needed and each MDU is to use varying parametesr,
+ // then MDU must be defined as its own SimObject so that an arbitrary # can
+ // be defined with different parameters
+ /** Latency & Repeat Rate for Multiply Insts */
+ unsigned multLatency;
+ unsigned multRepeatRate;
- //SMT Parameters
- unsigned smtNumFetchingThreads;
+ /** Latency & Repeat Rate for 8-bit Divide Insts */
+ unsigned div8Latency;
+ unsigned div8RepeatRate;
- std::string smtFetchPolicy;
+ /** Latency & Repeat Rate for 16-bit Divide Insts */
+ unsigned div16Latency;
+ unsigned div16RepeatRate;
- std::string smtIQPolicy;
- unsigned smtIQThreshold;
+ /** Latency & Repeat Rate for 24-bit Divide Insts */
+ unsigned div24Latency;
+ unsigned div24RepeatRate;
- std::string smtLSQPolicy;
- unsigned smtLSQThreshold;
+ /** Latency & Repeat Rate for 32-bit Divide Insts */
+ unsigned div32Latency;
+ unsigned div32RepeatRate;
- std::string smtCommitPolicy;
- std::string smtROBPolicy;
- unsigned smtROBThreshold;
-
- // Probably can get this from somewhere.
- unsigned instShiftAmt;
};
-#endif // __CPU_O3_ALPHA_PARAMS_HH__
+#endif // _CPU_INORDER_PARAMS_HH__
diff --git a/src/cpu/inorder/pipeline_stage.cc b/src/cpu/inorder/pipeline_stage.cc
new file mode 100644
index 000000000..cb69464b0
--- /dev/null
+++ b/src/cpu/inorder/pipeline_stage.cc
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "base/str.hh"
+#include "cpu/inorder/pipeline_stage.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+PipelineStage::PipelineStage(Params *params, unsigned stage_num)
+ : stageNum(stage_num), stageWidth(ThePipeline::StageWidth),
+ numThreads(ThePipeline::MaxThreads), _status(Inactive),
+ stageBufferMax(ThePipeline::interStageBuffSize[stage_num]),
+ prevStageValid(false), nextStageValid(false)
+{
+ init(params);
+}
+
+void
+PipelineStage::init(Params *params)
+{
+ for(int tid=0; tid < numThreads; tid++) {
+ stageStatus[tid] = Idle;
+
+ for (int stNum = 0; stNum < NumStages; stNum++) {
+ stalls[tid].stage[stNum] = false;
+ }
+ stalls[tid].resources.clear();
+
+ if (stageNum < BackEndStartStage)
+ lastStallingStage[tid] = BackEndStartStage - 1;
+ else
+ lastStallingStage[tid] = NumStages - 1;
+ }
+}
+
+
+std::string
+PipelineStage::name() const
+{
+ return cpu->name() + ".stage-" + to_string(stageNum);
+}
+
+
+void
+PipelineStage::regStats()
+{
+/* stageIdleCycles
+ .name(name() + ".IdleCycles")
+ .desc("Number of cycles stage is idle")
+ .prereq(stageIdleCycles);
+ stageBlockedCycles
+ .name(name() + ".BlockedCycles")
+ .desc("Number of cycles stage is blocked")
+ .prereq(stageBlockedCycles);
+ stageRunCycles
+ .name(name() + ".RunCycles")
+ .desc("Number of cycles stage is running")
+ .prereq(stageRunCycles);
+ stageUnblockCycles
+ .name(name() + ".UnblockCycles")
+ .desc("Number of cycles stage is unblocking")
+ .prereq(stageUnblockCycles);
+ stageSquashCycles
+ .name(name() + ".SquashCycles")
+ .desc("Number of cycles stage is squashing")
+ .prereq(stageSquashCycles);
+ stageProcessedInsts
+ .name(name() + ".ProcessedInsts")
+ .desc("Number of instructions handled by stage")
+ .prereq(stageProcessedInsts);
+ stageSquashedInsts
+ .name(name() + ".SquashedInsts")
+ .desc("Number of squashed instructions handled by stage")
+ .prereq(stageSquashedInsts);*/
+}
+
+
+void
+PipelineStage::setCPU(InOrderCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ dummyBufferInst = new InOrderDynInst(cpu_ptr, NULL, 0, 0);
+
+ DPRINTF(InOrderStage, "Set CPU pointer.\n");
+
+ tracer = dynamic_cast<Trace::InOrderTrace *>(cpu->getTracer());
+}
+
+
+void
+PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(InOrderStage, "Setting time buffer pointer.\n");
+ timeBuffer = tb_ptr;
+
+ // Setup wire to write information back to fetch.
+ toPrevStages = timeBuffer->getWire(0);
+
+ // Create wires to get information from proper places in time buffer.
+ fromNextStages = timeBuffer->getWire(-1);
+}
+
+
+void
+PipelineStage::setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr)
+{
+ DPRINTF(InOrderStage, "Setting previous stage queue pointer.\n");
+ prevStageQueue = prev_stage_ptr;
+
+ // Setup wire to read information from fetch queue.
+ prevStage = prevStageQueue->getWire(-1);
+
+ prevStageValid = true;
+}
+
+
+
+void
+PipelineStage::setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr)
+{
+ DPRINTF(InOrderStage, "Setting next stage pointer.\n");
+ nextStageQueue = next_stage_ptr;
+
+ // Setup wire to write information to proper place in stage queue.
+ nextStage = nextStageQueue->getWire(0);
+ nextStage->size = 0;
+ nextStageValid = true;
+}
+
+
+
+void
+PipelineStage::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(InOrderStage, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+/*inline void
+PipelineStage::switchToActive()
+{
+ if (_status == Inactive) {
+ DPRINTF(Activity, "Activating stage.\n");
+
+ cpu->activateStage(stageNum);
+
+ _status = Active;
+ }
+}*/
+
+void
+PipelineStage::switchOut()
+{
+ // Stage can immediately switch out.
+ panic("Switching Out of Stages Unimplemented");
+}
+
+
+void
+PipelineStage::takeOverFrom()
+{
+ _status = Inactive;
+
+ // Be sure to reset state and clear out any old instructions.
+ for (int i = 0; i < numThreads; ++i) {
+ stageStatus[i] = Idle;
+
+ for (int stNum = 0; stNum < NumStages; stNum++) {
+ stalls[i].stage[stNum] = false;
+ }
+
+ stalls[i].resources.clear();
+
+ while (!insts[i].empty())
+ insts[i].pop();
+
+ while (!skidBuffer[i].empty())
+ skidBuffer[i].pop();
+ }
+ wroteToTimeBuffer = false;
+}
+
+
+
+bool
+PipelineStage::checkStall(unsigned tid) const
+{
+ bool ret_val = false;
+
+ // Only check pipeline stall from stage directly following this stage
+ if (nextStageValid && stalls[tid].stage[stageNum + 1]) {
+ DPRINTF(InOrderStage,"[tid:%i]: Stall fom Stage %i detected.\n",
+ tid, stageNum + 1);
+ ret_val = true;
+ }
+
+ if (!stalls[tid].resources.empty()) {
+ string stall_src;
+
+ for (int i=0; i < stalls[tid].resources.size(); i++) {
+ stall_src += stalls[tid].resources[i]->res->name() + ":";
+ }
+
+ DPRINTF(InOrderStage,"[tid:%i]: Stall fom resources (%s) detected.\n",
+ tid, stall_src);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+
+void
+PipelineStage::removeStalls(unsigned tid)
+{
+ for (int stNum = 0; stNum < NumStages; stNum++) {
+ stalls[tid].stage[stNum] = false;
+ }
+ stalls[tid].resources.clear();
+}
+
+inline bool
+PipelineStage::prevStageInstsValid()
+{
+ return prevStage->size > 0;
+}
+
+bool
+PipelineStage::isBlocked(unsigned tid)
+{
+ return stageStatus[tid] == Blocked;
+}
+
+bool
+PipelineStage::block(unsigned tid)
+{
+ DPRINTF(InOrderStage, "[tid:%d]: Blocking, sending block signal back to previous stages.\n", tid);
+
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ // skidInsert(tid);
+
+ // If the stage status is blocked or unblocking then stage has not yet
+ // signalled fetch to unblock. In that case, there is no need to tell
+ // fetch to block.
+ if (stageStatus[tid] != Blocked) {
+ // Set the status to Blocked.
+ stageStatus[tid] = Blocked;
+
+ if (stageStatus[tid] != Unblocking) {
+ if (prevStageValid)
+ toPrevStages->stageBlock[stageNum][tid] = true;
+ wroteToTimeBuffer = true;
+ }
+
+ return true;
+ }
+
+
+ return false;
+}
+
+void
+PipelineStage::blockDueToBuffer(unsigned tid)
+{
+ DPRINTF(InOrderStage, "[tid:%d]: Blocking instructions from passing to next stage.\n", tid);
+
+ if (stageStatus[tid] != Blocked) {
+ // Set the status to Blocked.
+ stageStatus[tid] = Blocked;
+
+ if (stageStatus[tid] != Unblocking) {
+ wroteToTimeBuffer = true;
+ }
+ }
+}
+
+bool
+PipelineStage::unblock(unsigned tid)
+{
+ // Stage is done unblocking only if the skid buffer is empty.
+ if (skidBuffer[tid].empty()) {
+ DPRINTF(InOrderStage, "[tid:%u]: Done unblocking.\n", tid);
+
+ if (prevStageValid)
+ toPrevStages->stageUnblock[stageNum][tid] = true;
+
+ wroteToTimeBuffer = true;
+
+ stageStatus[tid] = Running;
+
+ return true;
+ }
+
+ DPRINTF(InOrderStage, "[tid:%u]: Currently unblocking.\n", tid);
+ return false;
+}
+
+void
+PipelineStage::squashDueToBranch(DynInstPtr &inst, unsigned tid)
+{
+ if (cpu->squashSeqNum[tid] < inst->seqNum &&
+ cpu->lastSquashCycle[tid] == curTick){
+ DPRINTF(Resource, "Ignoring [sn:%i] squash signal due to another stage's squash "
+ "signal for after [sn:%i].\n", inst->seqNum, cpu->squashSeqNum[tid]);
+ } else {
+ // Send back mispredict information.
+ toPrevStages->stageInfo[stageNum][tid].branchMispredict = true;
+ toPrevStages->stageInfo[stageNum][tid].predIncorrect = true;
+ toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum;
+ toPrevStages->stageInfo[stageNum][tid].squash = true;
+ toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg();
+ toPrevStages->stageInfo[stageNum][tid].branchTaken = inst->readNextNPC() !=
+ (inst->readNextPC() + sizeof(TheISA::MachInst));
+ toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->bdelaySeqNum;
+
+ DPRINTF(InOrderStage, "Target being re-set to %08p\n", inst->readPredTarg());
+ InstSeqNum squash_seq_num = inst->bdelaySeqNum;
+
+ DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], due to [sn:%i] "
+ "branch.\n", tid, squash_seq_num, inst->seqNum);
+
+ // Save squash num for later stage use
+ cpu->squashSeqNum[tid] = squash_seq_num;
+ cpu->lastSquashCycle[tid] = curTick;
+ }
+}
+
+void
+PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num,
+ unsigned tid)
+{
+ DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from "
+ "incoming stage queue.\n", tid);
+
+ for (int i=0; i < prevStage->size; i++) {
+ if (prevStage->insts[i]->threadNumber == tid &&
+ prevStage->insts[i]->seqNum > squash_seq_num) {
+ DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, "
+ "[sn:%i] PC %08p.\n",
+ tid,
+ prevStage->insts[i]->seqNum,
+ prevStage->insts[i]->readPC());
+ prevStage->insts[i]->setSquashed();
+ }
+ }
+}
+
+void
+PipelineStage::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ // Set status to squashing.
+ stageStatus[tid] = Squashing;
+
+ squashPrevStageInsts(squash_seq_num, tid);
+
+ DPRINTF(InOrderStage, "[tid:%i]: Removing instructions from incoming stage skidbuffer.\n",
+ tid);
+ while (!skidBuffer[tid].empty()) {
+ if (skidBuffer[tid].front()->seqNum <= squash_seq_num) {
+ DPRINTF(InOrderStage, "[tid:%i]: Cannot remove skidBuffer "
+ "instructions before delay slot [sn:%i]. %i insts"
+ "left.\n", tid, squash_seq_num,
+ skidBuffer[tid].size());
+ break;
+ }
+ DPRINTF(InOrderStage, "[tid:%i]: Removing instruction, [sn:%i] PC %08p.\n",
+ tid, skidBuffer[tid].front()->seqNum, skidBuffer[tid].front()->PC);
+ skidBuffer[tid].pop();
+ }
+
+}
+
+int
+PipelineStage::stageBufferAvail()
+{
+ unsigned total = 0;
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++) {
+ total += skidBuffer[i].size();
+ }
+
+ int incoming_insts = (prevStageValid) ?
+ cpu->pipelineStage[stageNum]->prevStage->size :
+ 0;
+
+ int avail = stageBufferMax - total -0;// incoming_insts;
+
+ if (avail < 0)
+ fatal("stageNum %i:stageBufferAvail() < 0...stBMax=%i,total=%i,incoming=%i=>%i",
+ stageNum, stageBufferMax, total, incoming_insts, avail);
+
+ return avail;
+}
+
+bool
+PipelineStage::canSendInstToStage(unsigned stage_num)
+{
+ bool buffer_avail = false;
+
+ if (cpu->pipelineStage[stage_num]->prevStageValid) {
+ buffer_avail = cpu->pipelineStage[stage_num]->stageBufferAvail() >= 1;
+ }
+
+ if (!buffer_avail && nextStageQueueValid(stage_num)) {
+ DPRINTF(InOrderStall, "STALL: No room in stage %i buffer.\n", stageNum + 1);
+ }
+
+ return buffer_avail;
+}
+
+void
+PipelineStage::skidInsert(unsigned tid)
+{
+ DynInstPtr inst = NULL;
+
+ while (!insts[tid].empty()) {
+ inst = insts[tid].front();
+
+ insts[tid].pop();
+
+ assert(tid == inst->threadNumber);
+
+ DPRINTF(InOrderStage,"[tid:%i]: Inserting [sn:%lli] PC:%#x into stage skidBuffer %i\n",
+ tid, inst->seqNum, inst->readPC(), inst->threadNumber);
+
+ skidBuffer[tid].push(inst);
+ }
+}
+
+
+int
+PipelineStage::skidSize()
+{
+ int total = 0;
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++) {
+ total += skidBuffer[i].size();
+ }
+
+ return total;
+}
+
+bool
+PipelineStage::skidsEmpty()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ if (!skidBuffer[*threads++].empty())
+ return false;
+ }
+
+ return true;
+}
+
+
+
+void
+PipelineStage::updateStatus()
+{
+ bool any_unblocking = false;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (stageStatus[tid] == Unblocking) {
+ any_unblocking = true;
+ break;
+ }
+ }
+
+ // Stage will have activity if it's unblocking.
+ if (any_unblocking) {
+ if (_status == Inactive) {
+ _status = Active;
+
+ DPRINTF(Activity, "Activating stage.\n");
+
+ cpu->activateStage(stageNum);
+ }
+ } else {
+ // If it's not unblocking, then stage will not have any internal
+ // activity. Switch it to inactive.
+ if (_status == Active) {
+ _status = Inactive;
+ DPRINTF(Activity, "Deactivating stage.\n");
+
+ cpu->deactivateStage(stageNum);
+ }
+ }
+}
+
+
+
+void
+PipelineStage::sortInsts()
+{
+ if (prevStageValid) {
+ int insts_from_prev_stage = prevStage->size;
+
+ DPRINTF(InOrderStage, "%i insts available from stage buffer %i.\n",
+ insts_from_prev_stage, prevStageQueue->id());
+
+ for (int i = 0; i < insts_from_prev_stage; ++i) {
+
+ if (prevStage->insts[i]->isSquashed()) {
+ DPRINTF(InOrderStage, "[tid:%i]: Ignoring squashed [sn:%i], not inserting "
+ "into stage buffer.\n",
+ prevStage->insts[i]->readTid(),
+ prevStage->insts[i]->seqNum);
+
+ continue;
+ }
+
+ DPRINTF(InOrderStage, "[tid:%i]: Inserting [sn:%i] into stage buffer.\n",
+ prevStage->insts[i]->readTid(),
+ prevStage->insts[i]->seqNum);
+
+ int tid = prevStage->insts[i]->threadNumber;
+
+ DynInstPtr inst = prevStage->insts[i];
+
+ skidBuffer[tid].push(prevStage->insts[i]);
+
+ prevStage->insts[i] = dummyBufferInst;
+
+ }
+ }
+}
+
+
+
+void
+PipelineStage::readStallSignals(unsigned tid)
+{
+ for (int stage_idx = stageNum+1; stage_idx <= lastStallingStage[tid];
+ stage_idx++) {
+
+ // Check for Stage Blocking Signal
+ if (fromNextStages->stageBlock[stage_idx][tid]) {
+ stalls[tid].stage[stage_idx] = true;
+ }
+
+ // Check for Stage Unblocking Signal
+ if (fromNextStages->stageUnblock[stage_idx][tid]) {
+ //assert(fromNextStages->stageBlock[stage_idx][tid]);
+ stalls[tid].stage[stage_idx] = false;
+ }
+ }
+}
+
+
+
+bool
+PipelineStage::checkSignalsAndUpdate(unsigned tid)
+{
+ // Check if there's a squash signal, squash if there is.
+ // Check stall signals, block if necessary.
+ // If status was blocked
+ // Check if stall conditions have passed
+ // if so then go to unblocking
+ // If status was Squashing
+ // check if squashing is not high. Switch to running this cycle.
+
+ // Update the per thread stall statuses.
+ readStallSignals(tid);
+
+ // Check for squash from later pipeline stages
+ for (int stage_idx=stageNum; stage_idx < NumStages; stage_idx++) {
+ if (fromNextStages->stageInfo[stage_idx][tid].squash) {
+ DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to squash "
+ "from stage %u.\n", tid, stage_idx);
+ InstSeqNum squash_seq_num = fromNextStages->
+ stageInfo[stage_idx][tid].bdelayDoneSeqNum;
+ squash(squash_seq_num, tid);
+ break; //return true;
+ }
+ }
+
+ if (checkStall(tid)) {
+ return block(tid);
+ }
+
+ if (stageStatus[tid] == Blocked) {
+ DPRINTF(InOrderStage, "[tid:%u]: Done blocking, switching to unblocking.\n",
+ tid);
+
+ stageStatus[tid] = Unblocking;
+
+ unblock(tid);
+
+ return true;
+ }
+
+ if (stageStatus[tid] == Squashing) {
+ if (!skidBuffer[tid].empty()) {
+ DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to unblocking.\n",
+ tid);
+
+ stageStatus[tid] = Unblocking;
+ } else {
+ // Switch status to running if stage isn't being told to block or
+ // squash this cycle.
+ DPRINTF(InOrderStage, "[tid:%u]: Done squashing, switching to running.\n",
+ tid);
+
+ stageStatus[tid] = Running;
+ }
+
+ return true;
+ }
+
+ // If we've reached this point, we have not gotten any signals that
+ // cause stage to change its status. Stage remains the same as before.*/
+ return false;
+}
+
+
+
+void
+PipelineStage::tick()
+{
+ wroteToTimeBuffer = false;
+
+ bool status_change = false;
+
+ if (nextStageValid)
+ nextStage->size = 0;
+
+ toNextStageIndex = 0;
+
+ sortInsts();
+
+ processStage(status_change);
+
+ if (status_change) {
+ updateStatus();
+ }
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+ cpu->activityThisCycle();
+ }
+
+ DPRINTF(InOrderStage, "\n\n");
+}
+
+void
+PipelineStage::setResStall(ResReqPtr res_req, unsigned tid)
+{
+ DPRINTF(InOrderStage, "Inserting stall from %s.\n", res_req->res->name());
+ stalls[tid].resources.push_back(res_req);
+}
+
+void
+PipelineStage::unsetResStall(ResReqPtr res_req, unsigned tid)
+{
+ // Search through stalls to find stalling request and then
+ // remove it
+ vector<ResReqPtr>::iterator req_it = stalls[tid].resources.begin();
+ vector<ResReqPtr>::iterator req_end = stalls[tid].resources.end();
+
+ while (req_it != req_end) {
+ if( (*req_it)->res == res_req->res && // Same Resource
+ (*req_it)->inst == res_req->inst && // Same Instruction
+ (*req_it)->getSlot() == res_req->getSlot()) {
+ DPRINTF(InOrderStage, "[tid:%u]: Clearing stall by %s.\n",
+ tid, res_req->res->name());
+ stalls[tid].resources.erase(req_it);
+ break;
+ }
+
+ req_it++;
+ }
+
+ if (stalls[tid].resources.size() == 0) {
+ DPRINTF(InOrderStage, "[tid:%u]: There are no remaining resource stalls.\n",
+ tid);
+ }
+}
+
+// @TODO: Update How we handled threads in CPU. Maybe threads shouldnt be handled
+// one at a time, but instead first come first serve by instruction?
+// Questions are how should a pipeline stage handle thread-specific stalls &
+// pipeline squashes
+void
+PipelineStage::processStage(bool &status_change)
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ //Check stall and squash signals.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ DPRINTF(InOrderStage,"Processing [tid:%i]\n",tid);
+ status_change = checkSignalsAndUpdate(tid) || status_change;
+
+ processThread(status_change, tid);
+ }
+
+ if (nextStageValid) {
+ DPRINTF(InOrderStage, "%i insts now available for stage %i.\n",
+ nextStage->size, stageNum + 1);
+ }
+
+ DPRINTF(InOrderStage, "%i left in stage %i incoming buffer.\n", skidSize(),
+ stageNum);
+
+ DPRINTF(InOrderStage, "%i available in stage %i incoming buffer.\n", stageBufferAvail(),
+ stageNum);
+}
+
+void
+PipelineStage::processThread(bool &status_change, unsigned tid)
+{
+ // If status is Running or idle,
+ // call stageInsts()
+ // If status is Unblocking,
+ // buffer any instructions coming from fetch
+ // continue trying to empty skid buffer
+ // check if stall conditions have passed
+
+ if (stageStatus[tid] == Blocked) {
+ ;//++stageBlockedCycles;
+ } else if (stageStatus[tid] == Squashing) {
+ ;//++stageSquashCycles;
+ }
+
+ // Stage should try to stage as many instructions as its bandwidth
+ // will allow, as long as it is not currently blocked.
+ if (stageStatus[tid] == Running ||
+ stageStatus[tid] == Idle) {
+ DPRINTF(InOrderStage, "[tid:%u]: Not blocked, so attempting to run "
+ "stage.\n",tid);
+
+ processInsts(tid);
+ } else if (stageStatus[tid] == Unblocking) {
+ // Make sure that the skid buffer has something in it if the
+ // status is unblocking.
+ assert(!skidsEmpty());
+
+ // If the status was unblocking, then instructions from the skid
+ // buffer were used. Remove those instructions and handle
+ // the rest of unblocking.
+ processInsts(tid);
+
+ if (prevStageValid && prevStageInstsValid()) {
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidInsert(tid);
+ }
+
+ status_change = unblock(tid) || status_change;
+ }
+}
+
+
+void
+PipelineStage::processInsts(unsigned tid)
+{
+ // Instructions can come either from the skid buffer or the list of
+ // instructions coming from fetch, depending on stage's status.
+ int insts_available = skidBuffer[tid].size();
+
+ std::queue<DynInstPtr> &insts_to_stage = skidBuffer[tid];
+
+ if (insts_available == 0) {
+ DPRINTF(InOrderStage, "[tid:%u]: Nothing to do, breaking out"
+ " early.\n",tid);
+ // Should I change the status to idle?
+ //++stageIdleCycles;
+ return;
+ }
+
+ DynInstPtr inst;
+ bool last_req_completed = true;
+
+ int insts_processed = 0;
+
+ while (insts_available > 0 &&
+ insts_processed < stageWidth &&
+ (!nextStageValid || canSendInstToStage(stageNum+1)) &&
+ last_req_completed) {
+ assert(!insts_to_stage.empty());
+
+ inst = insts_to_stage.front();
+
+ DPRINTF(InOrderStage, "[tid:%u]: Processing instruction [sn:%lli] with "
+ "PC %#x\n",
+ tid, inst->seqNum, inst->readPC());
+
+ if (inst->isSquashed()) {
+ DPRINTF(InOrderStage, "[tid:%u]: Instruction %i with PC %#x is "
+ "squashed, skipping.\n",
+ tid, inst->seqNum, inst->readPC());
+
+ //++stageSquashedInsts;
+
+ insts_to_stage.pop();
+
+ --insts_available;
+
+ continue;
+ }
+
+
+ last_req_completed = processInstSchedule(inst);
+
+ // Don't let instruction pass to next stage if it hasnt completed
+ // all of it's requests for this stage.
+ if (!last_req_completed)
+ continue;
+
+ // Send to Next Stage or Break Loop
+ if (nextStageValid && !sendInstToNextStage(inst)) {
+ DPRINTF(InOrderStage, "[tid:%i] [sn:%i] unable to proceed to stage %i.\n",
+ tid, inst->seqNum,inst->nextStage);
+ break;
+ }
+
+ insts_processed++;
+
+ insts_to_stage.pop();
+
+ //++stageProcessedInsts;
+ --insts_available;
+ }
+
+ // If we didn't process all instructions, then we will need to block
+ // and put all those instructions into the skid buffer.
+ if (!insts_to_stage.empty()) {
+ blockDueToBuffer(tid);
+ }
+
+ // Record that stage has written to the time buffer for activity
+ // tracking.
+ if (toNextStageIndex) {
+ wroteToTimeBuffer = true;
+ }
+}
+
+bool
+PipelineStage::processInstSchedule(DynInstPtr inst)
+{
+ bool last_req_completed = true;
+ int tid;
+
+ tid = inst->readTid();
+
+ if (inst->nextResStage() == stageNum) {
+ int res_stage_num = inst->nextResStage();
+
+ while (res_stage_num == stageNum) {
+ int res_num = inst->nextResource();
+
+
+ DPRINTF(InOrderStage, "[tid:%i]: [sn:%i]: sending request to %s.\n",
+ tid, inst->seqNum, cpu->resPool->name(res_num));
+
+ ResReqPtr req = cpu->resPool->request(res_num, inst);
+
+ if (req->isCompleted()) {
+ DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s completed.\n",
+ tid, inst->seqNum, cpu->resPool->name(res_num));
+
+ if (req->fault == NoFault) {
+ inst->popSchedEntry();
+ } else {
+ panic("%i: encountered %s fault!\n",
+ curTick, req->fault->name());
+ }
+ } else {
+ DPRINTF(InOrderStage, "[tid:%i]: [sn:%i] request to %s failed.\n",
+ tid, inst->seqNum, cpu->resPool->name(res_num));
+
+ last_req_completed = false;
+
+ break;
+ }
+
+ res_stage_num = inst->nextResStage();
+ }
+ } else {
+ DPRINTF(InOrderStage, "[tid:%u]: Instruction [sn:%i] with PC %#x "
+ " needed no resources in stage %i.\n",
+ tid, inst->seqNum, inst->readPC(), stageNum);
+ }
+
+ return last_req_completed;
+}
+
+bool
+PipelineStage::nextStageQueueValid(int stage_num)
+{
+ return cpu->pipelineStage[stage_num]->nextStageValid;
+}
+
+
+bool
+PipelineStage::sendInstToNextStage(DynInstPtr inst)
+{
+ // Update Next Stage Variable in Instruction
+ // NOTE: Some Resources will update this nextStage var. to
+ // for bypassing, so can't always assume nextStage=stageNum+1
+ if (inst->nextStage == stageNum)
+ inst->nextStage++;
+
+ bool success = false;
+ int tid = inst->readTid();
+ int next_stage = inst->nextStage;
+ int prev_stage = next_stage - 1;
+
+ assert(next_stage >= 1);
+ assert(prev_stage >= 0);
+
+ DPRINTF(InOrderStage, "[tid:%u]: Attempting to send instructions to stage %u.\n", tid,
+ stageNum+1);
+
+ if (!canSendInstToStage(inst->nextStage)) {
+ DPRINTF(InOrderStage, "[tid:%u]: Could not send instruction to stage %u.\n", tid,
+ stageNum+1);
+ return false;
+ }
+
+
+ if (nextStageQueueValid(inst->nextStage - 1)) {
+ if (inst->seqNum > cpu->squashSeqNum[tid] &&
+ curTick == cpu->lastSquashCycle[tid]) {
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping insertion "
+ "into stage %i queue.\n", tid, inst->seqNum, inst->nextStage);
+ } else {
+ if (nextStageValid) {
+ DPRINTF(InOrderStage, "[tid:%u] %i slots available in next stage buffer.\n",
+ tid, cpu->pipelineStage[next_stage]->stageBufferAvail());
+ }
+
+ DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: being placed into "
+ "index %i of stage buffer %i queue.\n",
+ tid, inst->seqNum, toNextStageIndex,
+ cpu->pipelineStage[prev_stage]->nextStageQueue->id());
+
+ int next_stage_idx = cpu->pipelineStage[prev_stage]->nextStage->size;
+
+ // Place instructions in inter-stage communication struct for the next
+ // pipeline stage to read next cycle
+ cpu->pipelineStage[prev_stage]->nextStage->insts[next_stage_idx] = inst;
+
+ ++(cpu->pipelineStage[prev_stage]->nextStage->size);
+
+ ++toNextStageIndex;
+
+ success = true;
+
+ // Take note of trace data for this inst & stage
+ if (inst->traceData) {
+ inst->traceData->setStageCycle(stageNum, curTick);
+ }
+
+ }
+ }
+
+ return success;
+}
+
+void
+PipelineStage::dumpInsts()
+{
+ cprintf("Insts in Stage %i skidbuffers\n",stageNum);
+
+ for (int tid=0; tid < ThePipeline::MaxThreads; tid++) {
+
+ std::queue<DynInstPtr> copy_buff(skidBuffer[tid]);
+
+ while (!copy_buff.empty()) {
+ DynInstPtr inst = copy_buff.front();
+
+ cprintf("Inst. PC:%#x\n[tid:%i]\n[sn:%i]\n\n",
+ inst->readPC(), inst->threadNumber, inst->seqNum);
+
+ copy_buff.pop();
+ }
+ }
+
+}
diff --git a/src/cpu/inorder/pipeline_stage.hh b/src/cpu/inorder/pipeline_stage.hh
new file mode 100644
index 000000000..b074639fb
--- /dev/null
+++ b/src/cpu/inorder/pipeline_stage.hh
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_PIPELINE_STAGE_HH__
+#define __CPU_INORDER_PIPELINE_STAGE_HH__
+
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/comm.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+class InOrderCPU;
+
+class PipelineStage
+{
+ protected:
+ typedef ThePipeline::Params Params;
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ /** Overall stage status. Used to determine if the CPU can
+ * deschedule itself due to a lack of activity.
+ */
+ enum StageStatus {
+ Active,
+ Inactive
+ };
+
+ /** Individual thread status. */
+ enum ThreadStatus {
+ Running,
+ Idle,
+ StartSquash,
+ Squashing,
+ Blocked,
+ Unblocking,
+ MemWaitResponse,
+ MemWaitRetry,
+ MemAccessComplete
+ };
+
+ protected:
+ /** The Number of This Pipeline Stage */
+ unsigned stageNum;
+
+ /** The width of stage, in instructions. */
+ unsigned stageWidth;
+
+ /** Number of Threads*/
+ unsigned numThreads;
+
+ /** Stage status. */
+ StageStatus _status;
+
+ /** Per-thread status. */
+ ThreadStatus stageStatus[ThePipeline::MaxThreads];
+
+ public:
+ PipelineStage(Params *params, unsigned stage_num);
+
+ /** MUST use init() function if this constructor is used. */
+ PipelineStage() { }
+
+ virtual ~PipelineStage() { }
+
+ /** PipelineStage initialization. */
+ void init(Params *params);
+
+ /** Returns the name of stage. */
+ std::string name() const;
+
+ /** Registers statistics. */
+ void regStats();
+
+ /** Sets CPU pointer. */
+ virtual void setCPU(InOrderCPU *cpu_ptr);
+
+ virtual void scheduleStageStart(int delay, int tid) { }
+
+ /** Sets the main backwards communication time buffer pointer. */
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ /** Sets pointer to time buffer coming from fetch. */
+ void setPrevStageQueue(TimeBuffer<InterStageStruct> *prev_stage_ptr);
+
+ /** Sets pointer to time buffer used to communicate to the next stage. */
+ void setNextStageQueue(TimeBuffer<InterStageStruct> *next_stage_ptr);
+
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ bool nextStageQueueValid(int stage_num);
+
+ bool isBlocked(unsigned tid);
+
+ /** Changes the status of this stage to active, and indicates this
+ * to the CPU.
+ */
+ //inline void switchToActive();
+
+ /** Changes the status of this stage to inactive, and indicates
+ * this to the CPU.
+ */
+ //inline void switchToInactive();
+
+ /** Switches out the stage stage. */
+ void switchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Ticks stage, processing all input signals and executing as many
+ * instructions as possible.
+ */
+ virtual void tick();
+
+ /** Set a resource stall in the pipeline-stage */
+ void setResStall(ResReqPtr res_req, unsigned tid);
+
+ /** Unset a resource stall in the pipeline-stage */
+ void unsetResStall(ResReqPtr res_req, unsigned tid);
+
+ /** Remove all stall signals for a particular thread; */
+ virtual void removeStalls(unsigned tid);
+
+ /** Is there room in the stage buffer? */
+ int stageBufferAvail();
+
+ protected:
+ /** Evaluate Stage Conditions and then process stage */
+ virtual void processStage(bool &status_change);
+
+ /** Determines what to do based on stage's current status.
+ * @param status_change stage() sets this variable if there was a status
+ * change (ie switching from from blocking to unblocking).
+ * @param tid Thread id to stage instructions from.
+ */
+ virtual void processThread(bool &status_change, unsigned tid);
+
+ /** Processes instructions from fetch and passes them on to rename.
+ * Decoding of instructions actually happens when they are created in
+ * fetch, so this function mostly checks if PC-relative branches are
+ * correct.
+ */
+ virtual void processInsts(unsigned tid);
+
+ /** Process all resources on an instruction's resource schedule */
+ virtual bool processInstSchedule(DynInstPtr inst);
+
+ /** Is there room in the next stage buffer for this instruction? */
+ virtual bool canSendInstToStage(unsigned stage_num);
+
+ /** Send an instruction to the next stage buffer */
+ virtual bool sendInstToNextStage(DynInstPtr inst);
+
+ /** Inserts a thread's instructions into the skid buffer, to be staged
+ * once stage unblocks.
+ */
+ virtual void skidInsert(unsigned tid);
+
+ /** Total size of all skid buffers */
+ int skidSize();
+
+ /** Returns if all of the skid buffers are empty. */
+ bool skidsEmpty();
+
+ /** Updates overall stage status based on all of the threads' statuses. */
+ virtual void updateStatus();
+
+ /** Separates instructions from fetch into individual lists of instructions
+ * sorted by thread.
+ */
+ void sortInsts();
+
+ /** Reads all stall signals from the backwards communication timebuffer. */
+ virtual void readStallSignals(unsigned tid);
+
+ /** Checks all input signals and updates stage's status appropriately. */
+ virtual bool checkSignalsAndUpdate(unsigned tid);
+
+ /** Checks all stall signals, and returns if any are true. */
+ virtual bool checkStall(unsigned tid) const;
+
+ /** Returns if there any instructions from the previous stage
+ * on this cycle.
+ */
+ inline bool prevStageInstsValid();
+
+ /** Switches stage to blocking, and signals back that stage has
+ * become blocked.
+ * @return Returns true if there is a status change.
+ */
+ virtual bool block(unsigned tid);
+
+ void blockDueToBuffer(unsigned tid);
+
+ /** Switches stage to unblocking if the skid buffer is empty, and
+ * signals back that stage has unblocked.
+ * @return Returns true if there is a status change.
+ */
+ virtual bool unblock(unsigned tid);
+
+
+ public:
+ /** Squashes if there is a PC-relative branch that was predicted
+ * incorrectly. Sends squash information back to fetch.
+ */
+ virtual void squashDueToBranch(DynInstPtr &inst, unsigned tid);
+
+ /** Squash instructions from stage buffer */
+ virtual void squashPrevStageInsts(InstSeqNum squash_seq_num, unsigned tid);
+
+ /** Squashes due to commit signalling a squash. Changes status to
+ * squashing and clears block/unblock signals as needed.
+ */
+ virtual void squash(InstSeqNum squash_num, unsigned tid);
+
+ void dumpInsts();
+
+ protected:
+ /** CPU interface. */
+ InOrderCPU *cpu;
+
+ Trace::InOrderTrace *tracer;
+
+ /** List of active thread ids */
+ std::list<unsigned> *activeThreads;
+
+ /** Queue of all instructions coming from previous stage on this cycle. */
+ std::queue<DynInstPtr> insts[ThePipeline::MaxThreads];
+
+ /** Queue of instructions that are finished processing and ready to go next stage.
+ * This is used to prevent from processing an instrution more than once on any
+ * stage. NOTE: It is up to the PROGRAMMER must manage this as a queue
+ */
+ std::list<DynInstPtr> instsToNextStage;
+
+ /** Skid buffer between previous stage and this one. */
+ std::queue<DynInstPtr> skidBuffer[ThePipeline::MaxThreads];
+
+ /** Instruction used to signify that there is no *real* instruction in buffer slot */
+ DynInstPtr dummyBufferInst;
+
+ /** SeqNum of Squashing Branch Delay Instruction (used for MIPS) */
+ Addr bdelayDoneSeqNum[ThePipeline::MaxThreads];
+
+ /** Instruction used for squashing branch (used for MIPS) */
+ DynInstPtr squashInst[ThePipeline::MaxThreads];
+
+ /** Tells when their is a pending delay slot inst. to send
+ * to rename. If there is, then wait squash after the next
+ * instruction (used for MIPS).
+ */
+ bool squashAfterDelaySlot[ThePipeline::MaxThreads];
+
+ /** Maximum size of the inter-stage buffer connecting the previous stage to
+ * this stage (which we call a skid buffer) */
+ unsigned stageBufferMax;
+
+ /** Variable that tracks if stage has written to the time buffer this
+ * cycle. Used to tell CPU if there is activity this cycle.
+ */
+ bool wroteToTimeBuffer;
+
+ /** Index of instructions being sent to the next stage. */
+ unsigned toNextStageIndex;
+
+ /** The last stage that this particular stage should look for stalls */
+ int lastStallingStage[ThePipeline::MaxThreads];
+
+ /** Time buffer interface. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ public:
+ /** Wire to get rename's output from backwards time buffer. */
+ TimeBuffer<TimeStruct>::wire fromNextStages;
+
+ /** Wire to get iew's information from backwards time buffer. */
+ TimeBuffer<TimeStruct>::wire toPrevStages;
+
+ /** Instruction queue linking previous stage */
+ TimeBuffer<InterStageStruct> *prevStageQueue;
+
+ /** Wire to get the previous stage's. */
+ TimeBuffer<InterStageStruct>::wire prevStage;
+
+ /** Instruction queue linking next stage */
+ TimeBuffer<InterStageStruct> *nextStageQueue;
+
+ /** Wire to write to the next stage */
+ TimeBuffer<InterStageStruct>::wire nextStage;
+
+ /** Is Previous Stage Valid? */
+ bool prevStageValid;
+
+ /** Is Next Stage Valid? */
+ bool nextStageValid;
+
+ /** Source of possible stalls. */
+ struct Stalls {
+ bool stage[ThePipeline::NumStages];
+ std::vector<ResReqPtr> resources;
+ };
+
+ /** Tracks which stages are telling decode to stall. */
+ Stalls stalls[ThePipeline::MaxThreads];
+
+ //@TODO: Use Stats for the pipeline stages
+ /** Stat for total number of idle cycles. */
+ //Stats::Scalar stageIdleCycles;
+ /** Stat for total number of blocked cycles. */
+ //Stats::Scalar stageBlockedCycles;
+ /** Stat for total number of normal running cycles. */
+ //Stats::Scalar stageRunCycles;
+ /** Stat for total number of unblocking cycles. */
+ //Stats::Scalar stageUnblockCycles;
+ /** Stat for total number of squashing cycles. */
+ //Stats::Scalar stageSquashCycles;
+ /** Stat for total number of staged instructions. */
+ //Stats::Scalar stageProcessedInsts;
+ /** Stat for total number of squashed instructions. */
+ //Stats::Scalar stageSquashedInsts;
+};
+
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.5stage.cc b/src/cpu/inorder/pipeline_traits.5stage.cc
new file mode 100644
index 000000000..50c30af1e
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.5stage.cc
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+ int cur_pri = 20;
+
+ /*
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_it = inst->resSched.begin();
+
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_end = inst->resSched.end();
+
+ while (sked_it != sked_end) {
+
+ if (sked_it.top()->stageNum == stage_num) {
+ cur_pri = sked_it.top()->priority;
+ }
+
+ sked_it++;
+ }
+ */
+
+ return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+ int stNum = 0;
+ int stPri = 0;
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // IF - Stage 0
+ // ---------------------------------------
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::AssignNextPC));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, ITLB, TLBUnit::FetchLookup));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::InitiateFetch));
+
+ //
+ // DE - Stage 1
+ // ---------------------------------------
+ stNum++; stPri = 0;
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, ICache, CacheUnit::CompleteFetch));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, Decode, DecodeUnit::DecodeInst));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, BPred, BranchPredictor::PredictBranch));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+ if (!inst->staticInst) {
+ return false;
+ }
+
+ int stNum = BackEndStartStage;
+ int stPri = 0;
+
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // EX - Stage 2
+ // ---------------------------------------
+ for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+ if (!idx || !inst->isStore())
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, idx));
+ }
+
+ if ( inst->isNonSpeculative() ) {
+ // skip execution of non speculative insts until later
+ } else if (inst->isMemRef()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, AGEN, AGENUnit::GenerateAddr));
+ if ( inst->isLoad() ) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateReadData));
+ }
+ } else {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
+ }
+
+ //
+ // MEM - Stage 3
+ // ---------------------------------------
+ stPri = 0; stNum++;
+ if ( inst->isStore() ) { // for store, need src reg at this point
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::ReadSrcReg, 1));
+ }
+ if ( inst->isLoad() ) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteReadData));
+ } else if ( inst->isStore() ) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DTLB, TLBUnit::DataLookup));
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::InitiateWriteData));
+ }
+
+ //
+ // WB - Stage 4
+ // ---------------------------------------
+ stPri = 0; stNum++;
+ if (inst->isNonSpeculative()) {
+ if (inst->isMemRef())
+ fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+ if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+ } else {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, ExecUnit, ExecutionUnit::ExecuteInst));
+ }
+ }
+
+ if ( inst->isStore() )
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, DCache, CacheUnit::CompleteWriteData));
+
+ // Write Back to Register File
+ for (int idx=0; idx < inst->numDestRegs(); idx++) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, RegManager, UseDefUnit::WriteDestReg, idx));
+ }
+
+ // Graduate Instructions
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, Grad, GraduationUnit::GraduateInst));
+
+ return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.5stage.hh b/src/cpu/inorder/pipeline_traits.5stage.hh
new file mode 100644
index 000000000..aea6eff37
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.5stage.hh
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+ // Pipeline Constants
+ const unsigned NumStages = 5;
+ const unsigned MaxThreads = 3;
+ const unsigned StageWidth = 1;
+ const unsigned BackEndStartStage = 2;
+
+ // Enumerated List of Resources The Pipeline Uses
+ enum ResourceList {
+ FetchSeq = 0,
+ ITLB,
+ ICache,
+ Decode,
+ BPred,
+ FetchBuff,
+ RegManager,
+ AGEN,
+ ExecUnit,
+ DTLB,
+ DCache,
+ Grad,
+ FetchBuff2
+ };
+
+ // Expand this as necessary for your inter stage buffer sizes
+ static const unsigned interStageBuffSize[] = {
+ StageWidth, /* Stage 0 - 1 */
+ StageWidth, /* Stage 1 - 2 */
+ StageWidth, /* Stage 2 - 3 */
+ StageWidth, /* Stage 3 - 4 */
+ StageWidth, /* Stage 4 - 5 */
+ StageWidth, /* Stage 5 - 6 */
+ StageWidth, /* Stage 6 - 7 */
+ StageWidth, /* Stage 7 - 8 */
+ StageWidth /* Stage 8 - 9 */
+ };
+
+ typedef InOrderCPUParams Params;
+ typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+ //////////////////////////
+ // RESOURCE SCHEDULING
+ //////////////////////////
+ struct ScheduleEntry {
+ ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+ int _idx = 0) :
+ stageNum(stage_num), resNum(res_num), cmd(_cmd),
+ idx(_idx), priority(_priority)
+ { }
+ virtual ~ScheduleEntry(){}
+
+ // Stage number to perform this service.
+ int stageNum;
+
+ // Resource ID to access
+ int resNum;
+
+ // See specific resource for meaning
+ unsigned cmd;
+
+ // See specific resource for meaning
+ unsigned idx;
+
+ // Some Resources May Need Priority?
+ int priority;
+ };
+
+ struct entryCompare {
+ bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+ {
+ // Prioritize first by stage number that the resource is needed
+ if (lhs->stageNum > rhs->stageNum) {
+ return true;
+ } else if (lhs->stageNum == rhs->stageNum) {
+ /*if (lhs->resNum > rhs->resNum) {
+ return true;
+ } else {
+ return false;
+ }*/
+
+ if (lhs->priority > rhs->priority) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare> ResSchedule;
+
+ void createFrontEndSchedule(DynInstPtr &inst);
+ bool createBackEndSchedule(DynInstPtr &inst);
+ int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.9stage.cc b/src/cpu/inorder/pipeline_traits.9stage.cc
new file mode 100644
index 000000000..d686bb3bc
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.cc
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+ int cur_pri = 20;
+
+ /*
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_it = inst->resSched.begin();
+
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_end = inst->resSched.end();
+
+ while (sked_it != sked_end) {
+
+ if (sked_it.top()->stageNum == stage_num) {
+ cur_pri = sked_it.top()->priority;
+ }
+
+ sked_it++;
+ }
+ */
+
+ return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+ int stNum = 0;
+ int stPri = 0;
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // Stage 0
+ // ---------------------------------------
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+
+ //
+ // Stage 1
+ // ---------------------------------------
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+ stPri++;
+
+ if (inst->readTid() == 0)
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff, InstBuffer::ScheduleOrBypass));
+ else //if (inst->readTid() == 1)
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchBuff2, InstBuffer::ScheduleOrBypass));
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+
+ //
+ // Stage 2
+ // ---------------------------------------
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+ if (!inst->staticInst) {
+ return false;
+ }
+
+ std::string name = inst->staticInst->getName();
+
+ int stNum = BackEndStartStage;
+ int stPri = 0;
+
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // Stage 3
+ // ---------------------------------------
+ // Set When Source Registers Should be read - Stage 4
+ for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
+ }
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 4
+ // ---------------------------------------
+ if (inst->isMemRef()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 5
+ // ---------------------------------------
+ // Execution Unit
+ if (!inst->isNonSpeculative() && !inst->isMemRef()) {
+ if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+ } else {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+ }
+ }
+ stPri++;
+
+ // DCache Initiate Access
+ if (inst->isMemRef()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
+ stPri++;
+
+ if (inst->isLoad()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
+ } else if (inst->isStore()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
+ }
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 6
+ // ---------------------------------------
+ // DCache Complete Access
+ if (inst->isMemRef()) {
+ if (inst->isLoad()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
+ } else if (inst->isStore()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
+ }
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 7
+ // ---------------------------------------
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 8
+ // ---------------------------------------
+ // NonSpeculative Execution
+ if (inst->isNonSpeculative() ) {
+ if (inst->isMemRef())
+ fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+ stPri++;
+ }
+
+ // Write Back to Register File
+ for (int idx=0; idx < inst->numDestRegs(); idx++) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
+ stPri++;
+ }
+
+ // Graduate Instructions
+ inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.9stage.hh b/src/cpu/inorder/pipeline_traits.9stage.hh
new file mode 100644
index 000000000..91e537366
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.hh
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+#include <map>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+ // Pipeline Constants
+ const unsigned NumStages = 9;
+ const unsigned MaxThreads = 3;
+ const unsigned StageWidth = 2;
+ const unsigned BackEndStartStage = 3;
+
+ // Use this to over-ride default stage widths
+ static std::map<unsigned, unsigned> stageBufferSizes;
+
+ //static unsigned interStageBuffSize[NumStages];
+
+ static const unsigned interStageBuffSize[NumStages] = {
+ StageWidth, /* Stage 0 - 1 */
+ StageWidth, /* Stage 1 - 2 */
+ 4, /* Stage 2 - 3 */
+ StageWidth, /* Stage 3 - 4 */
+ StageWidth, /* Stage 4 - 5 */
+ StageWidth, /* Stage 5 - 6 */
+ StageWidth, /* Stage 6 - 7 */
+ StageWidth, /* Stage 7 - 8 */
+ StageWidth /* Stage 8 - 9 */
+ };
+
+
+ // Enumerated List of Resources The Pipeline Uses
+ enum ResourceList {
+ FetchSeq = 0,
+ ITLB,
+ ICache,
+ Decode,
+ BPred,
+ FetchBuff,
+ RegManager,
+ AGEN,
+ ExecUnit,
+ DTLB,
+ DCache,
+ Grad,
+ FetchBuff2
+ };
+
+ typedef InOrderCPUParams Params;
+ typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+//void initPipelineTraits();
+
+ //////////////////////////
+ // RESOURCE SCHEDULING
+ //////////////////////////
+ struct ScheduleEntry {
+ ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+ int _idx = 0) :
+ stageNum(stage_num), resNum(res_num), cmd(_cmd),
+ idx(_idx), priority(_priority)
+ { }
+ virtual ~ScheduleEntry(){}
+
+ // Stage number to perform this service.
+ int stageNum;
+
+ // Resource ID to access
+ int resNum;
+
+ // See specific resource for meaning
+ unsigned cmd;
+
+ // See specific resource for meaning
+ unsigned idx;
+
+ // Some Resources May Need Priority?
+ int priority;
+ };
+
+ struct entryCompare {
+ bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+ {
+ // Prioritize first by stage number that the resource is needed
+ if (lhs->stageNum > rhs->stageNum) {
+ return true;
+ } else if (lhs->stageNum == rhs->stageNum) {
+ /*if (lhs->resNum > rhs->resNum) {
+ return true;
+ } else {
+ return false;
+ }*/
+
+ if (lhs->priority > rhs->priority) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare> ResSchedule;
+
+ void createFrontEndSchedule(DynInstPtr &inst);
+ bool createBackEndSchedule(DynInstPtr &inst);
+ int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.cc b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
new file mode 100644
index 000000000..9d2ed8e61
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.cc
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+ int cur_pri = 20;
+
+ /*
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_it = inst->resSched.begin();
+
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_end = inst->resSched.end();
+
+ while (sked_it != sked_end) {
+
+ if (sked_it.top()->stageNum == stage_num) {
+ cur_pri = sked_it.top()->priority;
+ }
+
+ sked_it++;
+ }
+ */
+
+ return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+ int stNum = 0;
+ int stPri = 0;
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // Stage 0
+ // ---------------------------------------
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::AssignNextPC));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ITLB, TLBUnit::FetchLookup));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::InitiateFetch));
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+
+ //
+ // Stage 1
+ // ---------------------------------------
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ICache, CacheUnit::CompleteFetch));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, Decode, DecodeUnit::DecodeInst));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, BPred, BranchPredictor::PredictBranch));
+ stPri++;
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, FetchSeq, FetchSeqUnit::UpdateTargetPC));
+ stPri++;
+
+ int fetch_buff_num = FetchBuff + inst->readTid();
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, fetch_buff_num, InstBuffer::ScheduleOrBypass));
+
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+
+ //
+ // Stage 2
+ // ---------------------------------------
+ // Reset Priority / Update Next Stage Number
+ stNum++;
+ stPri = 0;
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+ if (!inst->staticInst) {
+ return false;
+ }
+
+ std::string name = inst->staticInst->getName();
+
+ int stNum = BackEndStartStage;
+ int stPri = 0;
+
+ // Get Pointer to Instuction's Schedule
+ ResSchedule *inst_sched = &inst->resSched;
+
+ //
+ // Stage 3
+ // ---------------------------------------
+ // Set When Source Registers Should be read - Stage 4
+ for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::ReadSrcReg, idx));
+ }
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 4
+ // ---------------------------------------
+ if (inst->isMemRef()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, AGEN, AGENUnit::GenerateAddr));
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 5
+ // ---------------------------------------
+ // Execution Unit
+ if (!inst->isNonSpeculative() && !inst->isMemRef()) {
+ //if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+ //inst_sched->push(new ScheduleEntry(stNum, stPri++, MDU, MultDivUnit::MultDiv));
+ //} else {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+ //}
+ }
+ stPri++;
+
+ // DCache Initiate Access
+ if (inst->isMemRef()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DTLB, TLBUnit::DataLookup));
+ stPri++;
+
+ if (inst->isLoad()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateReadData));
+ } else if (inst->isStore()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::InitiateWriteData));
+ }
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 6
+ // ---------------------------------------
+ // DCache Complete Access
+ if (inst->isMemRef()) {
+ if (inst->isLoad()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteReadData));
+ } else if (inst->isStore()) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, DCache, CacheUnit::CompleteWriteData));
+ }
+ }
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 7
+ // ---------------------------------------
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ //
+ // Stage 8
+ // ---------------------------------------
+ // NonSpeculative Execution
+ if (inst->isNonSpeculative() ) {
+ if (inst->isMemRef())
+ fatal("Schedule doesnt handle Non-Speculative Memory Instructions.\n");
+
+ inst_sched->push(new ScheduleEntry(stNum, stPri, ExecUnit, ExecutionUnit::ExecuteInst));
+ stPri++;
+ }
+
+ // Write Back to Register File
+ for (int idx=0; idx < inst->numDestRegs(); idx++) {
+ inst_sched->push(new ScheduleEntry(stNum, stPri, RegManager, UseDefUnit::WriteDestReg, idx));
+ stPri++;
+ }
+
+ // Graduate Instructions
+ inst_sched->push(new ScheduleEntry(stNum, stPri, Grad, GraduationUnit::GraduateInst));
+ stPri++;
+
+ // Reset Priority / Update Next Stage Number
+ stPri = 0;
+ stNum++;
+
+ return true;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.9stage.smt2.hh b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
new file mode 100644
index 000000000..22da4ea0f
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.9stage.smt2.hh
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+#include <map>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/params.hh"
+
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+ // Pipeline Constants
+ const unsigned NumStages = 9;
+ const unsigned MaxThreads = 2;
+ const unsigned StageWidth = 1;
+ const unsigned BackEndStartStage = 3;
+
+ // Use this to over-ride default stage widths
+ static std::map<unsigned, unsigned> stageBufferSizes;
+
+ //static unsigned interStageBuffSize[NumStages];
+
+ static const unsigned interStageBuffSize[NumStages] = {
+ StageWidth, /* Stage 0 - 1 */
+ StageWidth, /* Stage 1 - 2 */
+ MaxThreads * 4, /* Stage 2 - 3 */
+ StageWidth, /* Stage 3 - 4 */
+ MaxThreads * 4, /* Stage 4 - 5 */
+ StageWidth, /* Stage 5 - 6 */
+ StageWidth, /* Stage 6 - 7 */
+ StageWidth, /* Stage 7 - 8 */
+ MaxThreads /* Stage 8 - 9 */
+ };
+
+
+ // Enumerated List of Resources The Pipeline Uses
+ enum ResourceList {
+ FetchSeq = 0,
+ ITLB,
+ ICache,
+ Decode,
+ BPred,
+ RegManager,
+ AGEN,
+ ExecUnit,
+ DTLB,
+ DCache,
+ Grad,
+ FetchBuff,
+ FetchBuff2
+ };
+
+ typedef InOrderCPUParams Params;
+ typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+//void initPipelineTraits();
+
+ //////////////////////////
+ // RESOURCE SCHEDULING
+ //////////////////////////
+ struct ScheduleEntry {
+ ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+ int _idx = 0) :
+ stageNum(stage_num), resNum(res_num), cmd(_cmd),
+ idx(_idx), priority(_priority)
+ { }
+ virtual ~ScheduleEntry(){}
+
+ // Stage number to perform this service.
+ int stageNum;
+
+ // Resource ID to access
+ int resNum;
+
+ // See specific resource for meaning
+ unsigned cmd;
+
+ // See specific resource for meaning
+ unsigned idx;
+
+ // Some Resources May Need Priority?
+ int priority;
+ };
+
+ struct entryCompare {
+ bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+ {
+ // Prioritize first by stage number that the resource is needed
+ if (lhs->stageNum > rhs->stageNum) {
+ return true;
+ } else if (lhs->stageNum == rhs->stageNum) {
+ /*if (lhs->resNum > rhs->resNum) {
+ return true;
+ } else {
+ return false;
+ }*/
+
+ if (lhs->priority > rhs->priority) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare> ResSchedule;
+
+ void createFrontEndSchedule(DynInstPtr &inst);
+ bool createBackEndSchedule(DynInstPtr &inst);
+ int getNextPriority(DynInstPtr &inst, int stage_num);
+};
+#endif
diff --git a/src/cpu/inorder/pipeline_traits.cc b/src/cpu/inorder/pipeline_traits.cc
new file mode 100644
index 000000000..eb899452a
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.cc
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+using namespace std;
+
+namespace ThePipeline {
+
+//@TODO: create my own Instruction Schedule Class
+//that operates as a Priority QUEUE
+int getNextPriority(DynInstPtr &inst, int stage_num)
+{
+ int cur_pri = 20;
+
+ /*
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_it = inst->resSched.begin();
+
+ std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare>::iterator sked_end = inst->resSched.end();
+
+ while (sked_it != sked_end) {
+
+ if (sked_it.top()->stageNum == stage_num) {
+ cur_pri = sked_it.top()->priority;
+ }
+
+ sked_it++;
+ }
+ */
+
+ return cur_pri;
+}
+
+void createFrontEndSchedule(DynInstPtr &inst)
+{
+ InstStage *I = inst->addStage();
+ InstStage *E = inst->addStage();
+
+ I->needs(FetchSeq, FetchSeqUnit::AssignNextPC);
+ I->needs(ITLB, TLBUnit::FetchLookup);
+ I->needs(ICache, CacheUnit::InitiateFetch);
+
+ E->needs(ICache, CacheUnit::CompleteFetch);
+ E->needs(Decode, DecodeUnit::DecodeInst);
+ E->needs(BPred, BranchPredictor::PredictBranch);
+ E->needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
+}
+
+bool createBackEndSchedule(DynInstPtr &inst)
+{
+ if (!inst->staticInst) {
+ return false;
+ }
+
+ InstStage *E = inst->currentStage();
+ InstStage *M = inst->addStage();
+ InstStage *A = inst->addStage();
+ InstStage *W = inst->addStage();
+
+ for (int idx=0; idx < inst->numSrcRegs(); idx++) {
+ if (!idx || !inst->isStore()) {
+ E->needs(RegManager, UseDefUnit::ReadSrcReg, idx);
+ }
+ }
+
+
+ if ( inst->isNonSpeculative() ) {
+ // skip execution of non speculative insts until later
+ } else if ( inst->isMemRef() ) {
+ E->needs(AGEN, AGENUnit::GenerateAddr);
+ if ( inst->isLoad() ) {
+ E->needs(DTLB, TLBUnit::DataLookup);
+ E->needs(DCache, CacheUnit::InitiateReadData);
+ }
+ } else if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+ E->needs(MDU, MultDivUnit::StartMultDiv);
+
+ // ZERO-LATENCY Multiply:
+ // E->needs(MDU, MultDivUnit::MultDiv);
+ } else {
+ E->needs(ExecUnit, ExecutionUnit::ExecuteInst);
+ }
+
+ if (inst->opClass() == IntMultOp || inst->opClass() == IntDivOp) {
+ M->needs(MDU, MultDivUnit::EndMultDiv);
+ }
+
+ if ( inst->isLoad() ) {
+ M->needs(DCache, CacheUnit::CompleteReadData);
+ } else if ( inst->isStore() ) {
+ M->needs(RegManager, UseDefUnit::ReadSrcReg, 1);
+ M->needs(DTLB, TLBUnit::DataLookup);
+ M->needs(DCache, CacheUnit::InitiateWriteData);
+ }
+
+ if ( inst->isStore() ) {
+ A->needs(DCache, CacheUnit::CompleteWriteData);
+ }
+
+ if ( inst->isNonSpeculative() ) {
+ if ( inst->isMemRef() ) fatal("Non-Speculative Memory Instruction");
+ W->needs(ExecUnit, ExecutionUnit::ExecuteInst);
+ }
+
+ for (int idx=0; idx < inst->numDestRegs(); idx++) {
+ W->needs(RegManager, UseDefUnit::WriteDestReg, idx);
+ }
+
+ W->needs(Grad, GraduationUnit::GraduateInst);
+
+ return true;
+}
+
+InstStage::InstStage(DynInstPtr inst, int stage_num)
+{
+ stageNum = stage_num;
+ nextTaskPriority = 0;
+ instSched = &inst->resSched;
+}
+
+};
diff --git a/src/cpu/inorder/pipeline_traits.hh b/src/cpu/inorder/pipeline_traits.hh
new file mode 100644
index 000000000..3c49143bc
--- /dev/null
+++ b/src/cpu/inorder/pipeline_traits.hh
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_PIPELINE_IMPL_HH__
+#define __CPU_INORDER_PIPELINE_IMPL_HH__
+
+#include <list>
+#include <queue>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/base.hh"
+
+#include "params/InOrderCPU.hh"
+
+class InOrderDynInst;
+
+/* This Namespace contains constants, typedefs, functions and
+ * objects specific to the Pipeline Implementation.
+ */
+namespace ThePipeline {
+ // Pipeline Constants
+ const unsigned NumStages = 5;
+ const unsigned MaxThreads = 8;
+ const unsigned StageWidth = 1;
+ const unsigned BackEndStartStage = 2;
+
+ // Enumerated List of Resources The Pipeline Uses
+ enum ResourceList {
+ FetchSeq = 0,
+ ITLB,
+ ICache,
+ Decode,
+ BPred,
+ FetchBuff,
+ RegManager,
+ AGEN,
+ ExecUnit,
+ MDU,
+ DTLB,
+ DCache,
+ Grad,
+ FetchBuff2
+ };
+
+ // Expand this as necessary for your inter stage buffer sizes
+ static const unsigned interStageBuffSize[] = {
+ StageWidth, /* Stage 0 - 1 */
+ StageWidth, /* Stage 1 - 2 */
+ StageWidth, /* Stage 2 - 3 */
+ StageWidth, /* Stage 3 - 4 */
+ StageWidth, /* Stage 4 - 5 */
+ StageWidth, /* Stage 5 - 6 */
+ StageWidth, /* Stage 6 - 7 */
+ StageWidth, /* Stage 7 - 8 */
+ StageWidth /* Stage 8 - 9 */
+ };
+
+ typedef InOrderCPUParams Params;
+ typedef RefCountingPtr<InOrderDynInst> DynInstPtr;
+
+ //////////////////////////
+ // RESOURCE SCHEDULING
+ //////////////////////////
+ struct ScheduleEntry {
+ ScheduleEntry(int stage_num, int _priority, int res_num, int _cmd = 0,
+ int _idx = 0) :
+ stageNum(stage_num), resNum(res_num), cmd(_cmd),
+ idx(_idx), priority(_priority)
+ { }
+ virtual ~ScheduleEntry(){}
+
+ // Stage number to perform this service.
+ int stageNum;
+
+ // Resource ID to access
+ int resNum;
+
+ // See specific resource for meaning
+ unsigned cmd;
+
+ // See specific resource for meaning
+ unsigned idx;
+
+ // Some Resources May Need Priority?
+ int priority;
+ };
+
+ struct entryCompare {
+ bool operator()(const ScheduleEntry* lhs, const ScheduleEntry* rhs) const
+ {
+ // Prioritize first by stage number that the resource is needed
+ if (lhs->stageNum > rhs->stageNum) {
+ return true;
+ } else if (lhs->stageNum == rhs->stageNum) {
+ if (lhs->priority > rhs->priority) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ typedef std::priority_queue<ScheduleEntry*, std::vector<ScheduleEntry*>,
+ entryCompare> ResSchedule;
+
+ void createFrontEndSchedule(DynInstPtr &inst);
+ bool createBackEndSchedule(DynInstPtr &inst);
+ int getNextPriority(DynInstPtr &inst, int stage_num);
+
+ class InstStage {
+ private:
+ int nextTaskPriority;
+ int stageNum;
+ ResSchedule *instSched;
+
+ public:
+ InstStage(DynInstPtr inst, int stage_num);
+
+ void needs(int unit, int request) {
+ instSched->push( new ScheduleEntry(
+ stageNum, nextTaskPriority++, unit, request
+ ));
+ }
+
+ void needs(int unit, int request, int param) {
+ instSched->push( new ScheduleEntry(
+ stageNum, nextTaskPriority++, unit, request, param
+ ));
+ }
+
+ };
+};
+
+
+
+
+#endif
diff --git a/src/cpu/inorder/reg_dep_map.cc b/src/cpu/inorder/reg_dep_map.cc
new file mode 100644
index 000000000..a405b1fb9
--- /dev/null
+++ b/src/cpu/inorder/reg_dep_map.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+RegDepMap::RegDepMap(int size)
+{
+ regMap.resize(size);
+}
+
+string
+RegDepMap::name()
+{
+ return cpu->name() + ".RegDepMap";
+}
+
+void
+RegDepMap::setCPU(InOrderCPU *_cpu)
+{
+ cpu = _cpu;
+}
+
+void
+RegDepMap::clear()
+{
+ regMap.clear();
+}
+
+void
+RegDepMap::insert(DynInstPtr inst)
+{
+ int dest_regs = inst->numDestRegs();
+
+ DPRINTF(RegDepMap, "Setting Output Dependencies for [sn:%i] "
+ ", %s (dest. regs = %i).\n",
+ inst->seqNum,
+ inst->staticInst->getName(),
+ dest_regs);
+
+ for (int i = 0; i < dest_regs; i++) {
+ int idx = inst->destRegIdx(i);
+
+ //if (inst->numFPDestRegs())
+ // idx += TheISA::FP_Base_DepTag;
+
+ insert(idx, inst);
+ }
+}
+
+
+void
+RegDepMap::insert(unsigned idx, DynInstPtr inst)
+{
+ DPRINTF(RegDepMap, "Inserting [sn:%i] onto dep. list for reg. idx %i.\n",
+ inst->seqNum, idx);
+
+ regMap[idx].push_back(inst);
+
+ inst->setRegDepEntry();
+}
+
+void
+RegDepMap::remove(DynInstPtr inst)
+{
+ if (inst->isRegDepEntry()) {
+ DPRINTF(RegDepMap, "Removing [sn:%i]'s entries from reg. dep. map.\n",
+ inst->seqNum);
+
+ int dest_regs = inst->numDestRegs();
+
+ for (int i = 0; i < dest_regs; i++) {
+ int idx = inst->destRegIdx(i);
+ remove(idx, inst);
+ }
+ }
+}
+
+void
+RegDepMap::remove(unsigned idx, DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+ std::list<DynInstPtr>::iterator list_end = regMap[idx].end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ regMap[idx].erase(list_it);
+ break;
+ }
+
+ list_it++;
+ }
+}
+
+void
+RegDepMap::removeFront(unsigned idx, DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+ DPRINTF(RegDepMap, "[tid:%u]: Removing dependency entry on phys. reg."
+ "%i for [sn:%i].\n", inst->readTid(), idx, inst->seqNum);
+
+ assert(list_it != regMap[idx].end());
+
+ assert(inst == (*list_it));
+
+ regMap[idx].erase(list_it);
+}
+
+bool
+RegDepMap::canRead(unsigned idx, DynInstPtr inst)
+{
+ if (regMap[idx].size() == 0)
+ return true;
+
+ std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+ if (inst->seqNum <= (*list_it)->seqNum) {
+ return true;
+ } else {
+ DPRINTF(RegDepMap, "[sn:%i] Can't read from RegFile, [sn:%i] has not written"
+ " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum);
+ return false;
+ }
+}
+
+ThePipeline::DynInstPtr
+RegDepMap::canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = regMap[reg_idx].begin();
+ std::list<DynInstPtr>::iterator list_end = regMap[reg_idx].end();
+
+ DynInstPtr forward_inst = NULL;
+
+ // Look for first, oldest instruction
+ while (list_it != list_end &&
+ (*list_it)->seqNum < inst->seqNum) {
+ forward_inst = (*list_it);
+ list_it++;
+ }
+
+ if (forward_inst) {
+ if (forward_inst->isExecuted() &&
+ forward_inst->readResultTime(src_idx) < curTick) {
+ return forward_inst;
+ } else {
+ DPRINTF(RegDepMap, "[sn:%i] Can't get value through forwarding, "
+ " [sn:%i] has not been executed yet.\n",
+ inst->seqNum, forward_inst->seqNum);
+ return NULL;
+ }
+ } else {
+ DPRINTF(RegDepMap, "[sn:%i] No instruction found to forward from.\n",
+ inst->seqNum);
+ return NULL;
+ }
+}
+
+bool
+RegDepMap::canWrite(unsigned idx, DynInstPtr inst)
+{
+ if (regMap[idx].size() == 0)
+ return true;
+
+ std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+ if (inst->seqNum <= (*list_it)->seqNum) {
+ return true;
+ } else {
+ DPRINTF(RegDepMap, "[sn:%i] Can't write from RegFile: [sn:%i] has not written"
+ " it's value back yet.\n", inst->seqNum, (*list_it)->seqNum);
+ }
+
+ return false;
+}
+
+int
+RegDepMap::depSize(unsigned idx)
+{
+ return regMap[idx].size();
+}
+
+ThePipeline::DynInstPtr
+RegDepMap::findBypassInst(unsigned idx)
+{
+ std::list<DynInstPtr>::iterator list_it = regMap[idx].begin();
+
+ if (depSize(idx) == 1)
+ return NULL;
+
+ list_it++;
+
+ while (list_it != regMap[idx].end()) {
+ if((*list_it)->isExecuted()) {
+ return *list_it;
+ break;
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/cpu/inorder/reg_dep_map.hh b/src/cpu/inorder/reg_dep_map.hh
new file mode 100644
index 000000000..ba2a8c8a3
--- /dev/null
+++ b/src/cpu/inorder/reg_dep_map.hh
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 CPU_INORDER_REG_DEP_MAP_HH
+#define CPU_INORDER_REG_DEP_MAP_HH
+
+#include <list>
+#include <vector>
+
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+class InOrderCPU;
+
+class RegDepMap
+{
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ RegDepMap(int size = TheISA::TotalNumRegs);
+
+ ~RegDepMap() { }
+
+ std::string name();
+
+ void setCPU(InOrderCPU *_cpu);
+
+ /** Clear the Entire Map */
+ void clear();
+
+ /** Insert all of a instruction's destination registers into map*/
+ void insert(DynInstPtr inst);
+
+ /** Insert an instruction into a specific destination register index onto map */
+ void insert(unsigned idx, DynInstPtr inst);
+
+ /** Remove all of a instruction's destination registers into map*/
+ void remove(DynInstPtr inst);
+
+ /** Remove a specific instruction and destination register index from map */
+ void remove(unsigned idx, DynInstPtr inst);
+
+ /** Remove Front instruction from a destination register */
+ void removeFront(unsigned idx, DynInstPtr inst);
+
+ /** Is the current instruction able to read from this destination register? */
+ bool canRead(unsigned idx, DynInstPtr inst);
+
+ /** Is the current instruction able to get a forwarded value from another instruction
+ * for this destination register? */
+ DynInstPtr canForward(unsigned reg_idx, unsigned src_idx, DynInstPtr inst);
+
+ /** find an instruction to forward/bypass a value from */
+ DynInstPtr findBypassInst(unsigned idx);
+
+ /** Is the current instruction able to write to this destination register? */
+ bool canWrite(unsigned idx, DynInstPtr inst);
+
+ /** Size of Dependency of Map */
+ int depSize(unsigned idx);
+
+ protected:
+ // Eventually make this a map of lists for
+ // efficiency sake!
+ std::vector<std::list<DynInstPtr> > regMap;
+
+ InOrderCPU *cpu;
+};
+
+#endif
+
+
+
+
+
+
+
diff --git a/src/cpu/inorder/resource.cc b/src/cpu/inorder/resource.cc
new file mode 100644
index 000000000..3106628f0
--- /dev/null
+++ b/src/cpu/inorder/resource.cc
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/cpu.hh"
+using namespace std;
+
+Resource::Resource(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu)
+ : resName(res_name), id(res_id),
+ width(res_width), latency(res_latency), cpu(_cpu)
+{
+ // Use to deny a instruction a resource.
+ deniedReq = new ResourceRequest(this, NULL, 0, 0, 0, 0);
+}
+
+void
+Resource::init()
+{
+ // Set Up Resource Events to Appropriate Resource BandWidth
+ resourceEvent = new ResourceEvent[width];
+
+ initSlots();
+}
+
+void
+Resource::initSlots()
+{
+ // Add available slot numbers for resource
+ for (int slot_idx = 0; slot_idx < width; slot_idx++) {
+ availSlots.push_back(slot_idx);
+ resourceEvent[slot_idx].init(this, slot_idx);
+ }
+}
+
+std::string
+Resource::name()
+{
+ return cpu->name() + "." + resName;
+}
+
+void
+Resource::regStats()
+{
+ instReqsProcessed
+ .name(name() + ".instReqsProcessed")
+ .desc("Number of Instructions Requests that completed in this resource.");
+}
+
+int
+Resource::slotsAvail()
+{
+ return availSlots.size();
+}
+
+int
+Resource::slotsInUse()
+{
+ return width - availSlots.size();
+}
+
+void
+Resource::freeSlot(int slot_idx)
+{
+ DPRINTF(RefCount, "Removing [tid:%i] [sn:%i]'s request from resource [slot:%i].\n",
+ reqMap[slot_idx]->inst->readTid(),
+ reqMap[slot_idx]->inst->seqNum,
+ slot_idx);
+
+ // Put slot number on this resource's free list
+ availSlots.push_back(slot_idx);
+
+ // Erase Request Pointer From Request Map
+ std::map<int, ResReqPtr>::iterator req_it = reqMap.find(slot_idx);
+
+ assert(req_it != reqMap.end());
+ reqMap.erase(req_it);
+
+}
+
+// TODO: More efficiently search for instruction's slot within
+// resource.
+int
+Resource::findSlot(DynInstPtr inst)
+{
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ int slot_num = -1;
+
+ while (map_it != map_end) {
+ if ((*map_it).second->getInst()->seqNum ==
+ inst->seqNum) {
+ slot_num = (*map_it).second->getSlot();
+ }
+ map_it++;
+ }
+
+ return slot_num;
+}
+
+int
+Resource::getSlot(DynInstPtr inst)
+{
+ int slot_num;
+
+ if (slotsAvail() != 0) {
+ slot_num = availSlots[0];
+
+ vector<int>::iterator vect_it = availSlots.begin();
+
+ assert(slot_num == *vect_it);
+
+ availSlots.erase(vect_it);
+ } else {
+ DPRINTF(Resource, "[tid:%i]: No slots in resource "
+ "available to service [sn:%i].\n", inst->readTid(),
+ inst->seqNum);
+ slot_num = -1;
+
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ if ((*map_it).second) {
+ DPRINTF(Resource, "Currently Serving request from: [tid:%i] [sn:%i].\n",
+ (*map_it).second->getInst()->readTid(),
+ (*map_it).second->getInst()->seqNum);
+ }
+ map_it++;
+ }
+ }
+
+ return slot_num;
+}
+
+ResReqPtr
+Resource::request(DynInstPtr inst)
+{
+ // See if the resource is already serving this instruction.
+ // If so, use that request;
+ bool try_request = false;
+ int slot_num;
+ int stage_num;
+ ResReqPtr inst_req = findRequest(inst);
+
+ if (inst_req) {
+ // If some preprocessing has to be done on instruction
+ // that has already requested once, then handle it here.
+ // update the 'try_request' variable if we should
+ // re-execute the request.
+ requestAgain(inst, try_request);
+
+ slot_num = inst_req->getSlot();
+ stage_num = inst_req->getStageNum();
+ } else {
+ // Get new slot # for instruction
+ slot_num = getSlot(inst);
+
+ if (slot_num != -1) {
+ // Get Stage # from Schedule Entry
+ stage_num = inst->resSched.top()->stageNum;
+ unsigned cmd = inst->resSched.top()->cmd;
+
+ // Generate Resource Request
+ inst_req = getRequest(inst, stage_num, id, slot_num, cmd);
+
+ if (inst->staticInst) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource.\n",
+ inst->readTid(), inst->seqNum);
+ } else {
+ DPRINTF(Resource, "[tid:%i]: instruction requesting this resource.\n",
+ inst->readTid());
+ }
+
+ reqMap[slot_num] = inst_req;
+
+ try_request = true;
+ }
+ }
+
+ if (try_request) {
+ // Schedule execution of resource
+ scheduleExecution(slot_num);
+ } else {
+ inst_req = deniedReq;
+ rejectRequest(inst);
+ }
+
+ return inst_req;
+}
+
+void
+Resource::requestAgain(DynInstPtr inst, bool &do_request)
+{
+ do_request = true;
+
+ if (inst->staticInst) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i] requesting this resource again.\n",
+ inst->readTid(), inst->seqNum);
+ } else {
+ DPRINTF(Resource, "[tid:%i]: requesting this resource again.\n",
+ inst->readTid());
+ }
+}
+
+ResReqPtr
+Resource::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ return new ResourceRequest(this, inst, stage_num, id, slot_num,
+ cmd);
+}
+
+ResReqPtr
+Resource::findRequest(DynInstPtr inst)
+{
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ if ((*map_it).second &&
+ (*map_it).second->getInst() == inst) {
+ return (*map_it).second;
+ }
+ map_it++;
+ }
+
+ return NULL;
+}
+
+void
+Resource::rejectRequest(DynInstPtr inst)
+{
+ DPRINTF(RefCount, "[tid:%i]: Unable to grant request for [sn:%i].\n",
+ inst->readTid(), inst->seqNum);
+}
+
+void
+Resource::execute(int slot_idx)
+{
+ DPRINTF(Resource, "[tid:%i]: Executing %s resource.\n",
+ reqMap[slot_idx]->getTid(), name());
+ reqMap[slot_idx]->setCompleted(true);
+ reqMap[slot_idx]->fault = NoFault;
+ reqMap[slot_idx]->done();
+}
+
+void
+Resource::deactivateThread(unsigned tid)
+{
+ // In the most basic case, deactivation means squashing everything
+ // from a particular thread
+ DynInstPtr dummy_inst = new InOrderDynInst(cpu, NULL, 0, tid);
+ squash(dummy_inst, 0, 0, tid);
+}
+
+void
+Resource::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+ std::vector<int> slot_remove_list;
+
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ ResReqPtr req_ptr = (*map_it).second;
+
+ if (req_ptr &&
+ req_ptr->getInst()->readTid() == tid &&
+ req_ptr->getInst()->seqNum > squash_seq_num) {
+
+ DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i].\n",
+ req_ptr->getInst()->readTid(),
+ req_ptr->getInst()->seqNum);
+
+ int req_slot_num = req_ptr->getSlot();
+
+ unscheduleEvent(req_slot_num);
+
+ // Mark request for later removal
+ cpu->reqRemoveList.push(req_ptr);
+
+ // Mark slot for removal from resource
+ slot_remove_list.push_back(req_ptr->getSlot());
+ }
+
+ map_it++;
+ }
+
+ // Now Delete Slot Entry from Req. Map
+ for (int i = 0; i < slot_remove_list.size(); i++) {
+ freeSlot(slot_remove_list[i]);
+ }
+}
+
+
+Tick
+Resource::ticks(int num_cycles)
+{
+ return cpu->ticks(num_cycles);
+}
+
+
+void
+Resource::scheduleExecution(int slot_num)
+{
+ int res_latency = getLatency(slot_num);
+
+ if (res_latency >= 1) {
+ scheduleEvent(slot_num, res_latency);
+ } else {
+ execute(slot_num);
+ }
+}
+
+void
+Resource::scheduleEvent(int slot_idx, int delay)
+{
+ DPRINTF(Resource, "[tid:%i]: Scheduling event for [sn:%i] on tick %i.\n",
+ reqMap[slot_idx]->inst->readTid(),
+ reqMap[slot_idx]->inst->seqNum,
+ cpu->ticks(delay) + curTick);
+ resourceEvent[slot_idx].scheduleEvent(delay);
+}
+
+bool
+Resource::scheduleEvent(DynInstPtr inst, int delay)
+{
+ int slot_idx = findSlot(inst);
+
+ if(slot_idx != -1)
+ resourceEvent[slot_idx].scheduleEvent(delay);
+
+ return slot_idx;
+}
+
+void
+Resource::unscheduleEvent(int slot_idx)
+{
+ resourceEvent[slot_idx].unscheduleEvent();
+}
+
+bool
+Resource::unscheduleEvent(DynInstPtr inst)
+{
+ int slot_idx = findSlot(inst);
+
+ if(slot_idx != -1)
+ resourceEvent[slot_idx].unscheduleEvent();
+
+ return slot_idx;
+}
+
+int ResourceRequest::resReqID = 0;
+
+int ResourceRequest::resReqCount = 0;
+
+void
+ResourceRequest::done(bool completed)
+{
+ DPRINTF(Resource, "%s done with request from [sn:%i] [tid:%i].\n",
+ res->name(), inst->seqNum, inst->readTid());
+
+ setCompleted(completed);
+
+ // Add to remove list
+ res->cpu->reqRemoveList.push(res->reqMap[slotNum]);
+
+ // Free Slot So Another Instruction Can Use This Resource
+ res->freeSlot(slotNum);
+
+ res->instReqsProcessed++;
+}
+
+ResourceEvent::ResourceEvent()
+ : Event((Event::Priority)Resource_Event_Pri)
+{ }
+
+ResourceEvent::ResourceEvent(Resource *res, int slot_idx)
+ : Event((Event::Priority)Resource_Event_Pri), resource(res),
+ slotIdx(slot_idx)
+{ }
+
+void
+ResourceEvent::init(Resource *res, int slot_idx)
+{
+ resource = res;
+ slotIdx = slot_idx;
+}
+
+void
+ResourceEvent::process()
+{
+ resource->execute(slotIdx);
+}
+
+const char *
+ResourceEvent::description()
+{
+ string desc = resource->name() + " event";
+
+ return desc.c_str();
+}
diff --git a/src/cpu/inorder/resource.hh b/src/cpu/inorder/resource.hh
new file mode 100644
index 000000000..b857e59ed
--- /dev/null
+++ b/src/cpu/inorder/resource.hh
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_RESOURCE_HH__
+#define __CPU_INORDER_RESOURCE_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inst_seq.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class Event;
+class InOrderCPU;
+class ResourceEvent;
+class ResourceRequest;
+
+typedef ResourceRequest ResReq;
+typedef ResourceRequest* ResReqPtr;
+
+class Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ friend class ResourceEvent;
+ friend class ResourceRequest;
+
+ public:
+ Resource(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~Resource() {}
+
+ /** Return name of this resource */
+ virtual std::string name();
+
+ /** Define this function if resource, has a port to connect to an outside
+ * simulation object.
+ */
+ virtual Port* getPort(const std::string &if_name, int idx) { return NULL; }
+
+ /** Return ID for this resource */
+ int getId() { return id; }
+
+ /** Any extra initiliazation stuff can be set up using this function that
+ * should get called before the simulation starts (tick 0)
+ */
+ virtual void init();
+ virtual void initSlots();
+
+ /** Register Stats for this resource */
+ virtual void regStats();
+
+ /** Resources that care about thread activation override this. */
+ virtual void activateThread(unsigned tid) { }
+
+ /** Deactivate Thread. Default action is to squash all instructions
+ * from deactivated thread.
+ */
+ virtual void deactivateThread(unsigned tid);
+
+ /** Resources that care when an instruction has been graduated
+ * can override this
+ */
+ virtual void instGraduated(InstSeqNum seq_num,unsigned tid) { }
+
+ /** Request usage of this resource. Returns a ResourceRequest object
+ * with all the necessary resource information
+ */
+ virtual ResourceRequest* request(DynInstPtr inst);
+
+ /** Get the next available slot in this resource. Instruction is passed
+ * so that resources can check the instruction before allocating a slot
+ * if necessary.
+ */
+ virtual int getSlot(DynInstPtr inst);
+
+ /** Find the slot that this instruction is using in a resource */
+ virtual int findSlot(DynInstPtr inst);
+
+ /** Free a resource slot */
+ virtual void freeSlot(int slot_idx);
+
+ /** Request usage of a resource for this instruction. If this instruction already
+ * has made this request to this resource, and that request is uncompleted
+ * this function will just return that request
+ */
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ /** Schedule Execution of This Resource For A Given Slot*/
+ virtual void scheduleExecution(int slot_idx);
+
+ /** Execute the function of this resource. The Default is action
+ * is to do nothing. More specific models will derive from this
+ * class and define their own execute function.
+ */
+ virtual void execute(int slot_idx);
+
+ /** Fetch on behalf of an instruction. Will check to see
+ * if instruction is actually in resource before
+ * trying to fetch. Needs to be defined for derived units.
+ */
+ virtual Fault doFetchAccess(DynInstPtr inst)
+ { panic("doFetchAccess undefined for %s", name()); return NoFault; }
+
+ /** Read/Write on behalf of an instruction. Will check to see
+ * if instruction is actually in resource before
+ * trying to do access.Needs to be defined for derived units.
+ */
+ virtual Fault doDataAccess(DynInstPtr inst)
+ { panic("doDataAccess undefined for %s", name()); return NoFault; }
+
+ /** Squash All Requests After This Seq Num */
+ virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ /** The number of instructions available that this resource can
+ * can still process
+ */
+ int slotsAvail();
+
+ /** The number of instructions using this resource */
+ int slotsInUse();
+
+ /** Schedule resource event, regardless of its current state. */
+ void scheduleEvent(int slot_idx, int delay);
+
+ /** Find instruction in list, Schedule resource event, regardless of its current state. */
+ bool scheduleEvent(DynInstPtr inst, int delay);
+
+ /** Unschedule resource event, regardless of its current state. */
+ void unscheduleEvent(int slot_idx);
+
+ /** Unschedule resource event, regardless of its current state. */
+ bool unscheduleEvent(DynInstPtr inst);
+
+ /** Return the number of cycles in 'Tick' format */
+ Tick ticks(int numCycles);
+
+ /** Find the request that corresponds to this instruction */
+ virtual ResReqPtr findRequest(DynInstPtr inst);
+
+ /** */
+ virtual void rejectRequest(DynInstPtr inst);
+
+ /** Request a Resource again. Some resources have to special process this
+ * in subsequent accesses.
+ */
+ virtual void requestAgain(DynInstPtr inst, bool &try_request);
+
+ /** Return Latency of Resource */
+ /* Can be overridden for complex cases */
+ virtual int getLatency(int slot_num) { return latency; }
+
+ protected:
+ /** The name of this resource */
+ std::string resName;
+
+ /** ID of the resource. The Resource Pool uses this # to identify this
+ * resource.
+ */
+ int id;
+
+ /** The number of instructions the resource can simultaneously
+ * process.
+ */
+ int width;
+
+ /** Constant latency for this resource.
+ * Note: Dynamic latency resources set this to 0 and
+ * manage the latency themselves
+ */
+ const int latency;
+
+ public:
+ /** Mapping of slot-numbers to the resource-request pointers */
+ std::map<int, ResReqPtr> reqMap;
+
+ /** A list of all the available execution slots for this resource.
+ * This correlates with the actual resource event idx.
+ */
+ std::vector<int> availSlots;
+
+ /** The CPU(s) that this resource interacts with */
+ InOrderCPU *cpu;
+
+ protected:
+ /** The resource event used for scheduling resource slots on the
+ * event queue
+ */
+ ResourceEvent *resourceEvent;
+
+ /** Default denied resource request pointer*/
+ ResReqPtr deniedReq;
+
+ public:
+ /////////////////////////////////////////////////////////////////
+ //
+ // DEFAULT RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar instReqsProcessed;
+};
+
+class ResourceEvent : public Event
+{
+ public:
+ /** Pointer to the CPU. */
+ Resource *resource;
+
+
+ /// Resource events that come before other associated CPU events
+ /// (for InOrderCPU model).
+ /// check src/sim/eventq.hh for more event priorities.
+ enum InOrderPriority {
+ Resource_Event_Pri = 45,
+ };
+
+ /** The Resource Slot that this event is servicing */
+ int slotIdx;
+
+ /** Constructs a resource event. */
+ ResourceEvent();
+ ResourceEvent(Resource *res, int slot_idx);
+ virtual ~ResourceEvent() { }
+
+ /** Initialize data for this resource event. */
+ virtual void init(Resource *res, int slot_idx);
+
+ /** Processes a resource event. */
+ virtual void process();
+
+ /** Returns the description of the resource event. */
+ const char *description();
+
+ /** Set slot idx for event */
+ void setSlot(int slot) { slotIdx = slot; }
+
+ /** Schedule resource event, regardless of its current state. */
+ void scheduleEvent(int delay)
+ {
+ if (squashed())
+ mainEventQueue.reschedule(this, curTick + resource->ticks(delay));
+ else if (!scheduled())
+ mainEventQueue.schedule(this, curTick + resource->ticks(delay));
+ }
+
+ /** Unschedule resource event, regardless of its current state. */
+ void unscheduleEvent()
+ {
+ if (scheduled())
+ squash();
+ }
+
+};
+
+class ResourceRequest
+{
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ static int resReqID;
+
+ static int resReqCount;
+
+ public:
+ ResourceRequest(Resource *_res, DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num, unsigned _cmd)
+ : res(_res), inst(_inst), cmd(_cmd), stageNum(stage_num),
+ resIdx(res_idx), slotNum(slot_num), completed(false),
+ squashed(false), processing(false), waiting(false)
+ {
+ reqID = resReqID++;
+ resReqCount++;
+ DPRINTF(ResReqCount, "Res. Req %i created. resReqCount=%i.\n", reqID, resReqCount);
+
+ if (resReqCount > 100) {
+ fatal("Too many undeleted resource requests. Memory leak?\n");
+ }
+ }
+
+ virtual ~ResourceRequest()
+ {
+ resReqCount--;
+ DPRINTF(ResReqCount, "Res. Req %i deleted. resReqCount=%i.\n", reqID, resReqCount);
+ }
+
+ int reqID;
+
+ /** Acknowledge that this is a request is done and remove
+ * from resource.
+ */
+ void done(bool completed = true);
+
+ /////////////////////////////////////////////
+ //
+ // GET RESOURCE REQUEST IDENTIFICATION / INFO
+ //
+ /////////////////////////////////////////////
+ /** Get Resource Index */
+ int getResIdx() { return resIdx; }
+
+ /** Get Slot Number */
+ int getSlot() { return slotNum; }
+
+ /** Get Stage Number */
+ int getStageNum() { return stageNum; }
+
+ /** Set/Get Thread Ids */
+ void setTid(unsigned _tid) { tid = _tid; }
+ int getTid() { return tid; }
+
+ /** Instruction this request is for */
+ DynInstPtr getInst() { return inst; }
+
+ /** Data from this request. Overridden by Resource-Specific Request
+ * Objects
+ */
+ virtual PacketDataPtr getData() { return NULL; }
+
+ /** Pointer to Resource that is being used */
+ Resource *res;
+
+ /** Instruction being used */
+ DynInstPtr inst;
+
+ /** Fault Associated With This Resource Request */
+ Fault fault;
+
+ /** Command For This Resource */
+ unsigned cmd;
+
+ ////////////////////////////////////////
+ //
+ // GET RESOURCE REQUEST STATUS FROM VARIABLES
+ //
+ ////////////////////////////////////////
+ /** Get/Set Completed variables */
+ bool isCompleted() { return completed; }
+ void setCompleted(bool cond = true) { completed = cond; }
+
+ /** Get/Set Squashed variables */
+ bool isSquashed() { return squashed; }
+ void setSquashed() { squashed = true; }
+
+ /** Get/Set IsProcessing variables */
+ bool isProcessing() { return processing; }
+ void setProcessing() { processing = true; }
+
+ /** Get/Set IsWaiting variables */
+ bool isWaiting() { return waiting; }
+ void setWaiting() { waiting = true; }
+
+ protected:
+ /** Resource Identification */
+ int tid;
+ int stageNum;
+ int resIdx;
+ int slotNum;
+
+ /** Resource Status */
+ bool completed;
+ bool squashed;
+ bool processing;
+ bool waiting;
+};
+
+#endif //__CPU_INORDER_RESOURCE_HH__
diff --git a/src/cpu/inorder/resource_pool.9stage.cc b/src/cpu/inorder/resource_pool.9stage.cc
new file mode 100644
index 000000000..4a0258e71
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.9stage.cc
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+#include <vector>
+#include <list>
+
+using namespace std;
+using namespace ThePipeline;
+
+ResourcePool::ResourcePool(InOrderCPU *_cpu, InOrderCPUParams *params)
+ : cpu(_cpu)
+{
+ //@todo: use this function to instantiate the resources in resource pool. This will help in the
+ //auto-generation of this pipeline model.
+ //ThePipeline::addResources(resources, memObjects);
+
+ // Declare Resource Objects
+ // name - id - bandwidth - latency - CPU - Parameters
+ // --------------------------------------------------
+ resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
+
+ resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
+
+ memObjects.push_back(ICache);
+ resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
+
+ for (int i = 0; i < params->numberOfThreads; i++) {
+ char fbuff_name[20];
+ sprintf(fbuff_name, "Fetch-Buffer-T%i", i);
+ resources.push_back(new InstBuffer(fbuff_name, FetchBuff + i, 4, 0, _cpu, params));
+ }
+
+ resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
+
+ resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
+
+ memObjects.push_back(DCache);
+ resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
+}
+
+void
+ResourcePool::init()
+{
+ for (int i=0; i < resources.size(); i++) {
+ resources[i]->init();
+ }
+}
+
+string
+ResourcePool::name()
+{
+ return cpu->name() + ".ResourcePool";
+}
+
+
+void
+ResourcePool::regStats()
+{
+ DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->regStats();
+ }
+}
+
+Port *
+ResourcePool::getPort(const std::string &if_name, int idx)
+{
+ for (int i = 0; i < memObjects.size(); i++) {
+ int obj_idx = memObjects[i];
+ Port *port = resources[obj_idx]->getPort(if_name, idx);
+ if (port != NULL) {
+ return port;
+ }
+ }
+
+ return NULL;
+}
+
+unsigned
+ResourcePool::getPortIdx(const std::string &port_name)
+{
+ for (int i = 0; i < memObjects.size(); i++) {
+ unsigned obj_idx = memObjects[i];
+ Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
+ if (port != NULL) {
+ return obj_idx;
+ }
+ }
+
+ return 0;
+}
+
+ResReqPtr
+ResourcePool::request(int res_idx, DynInstPtr inst)
+{
+ //Make Sure This is a valid resource ID
+ assert(res_idx >= 0 && res_idx < resources.size());
+
+ return resources[res_idx]->request(inst);
+}
+
+void
+ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
+{
+ resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
+}
+
+int
+ResourcePool::slotsAvail(int res_idx)
+{
+ return resources[res_idx]->slotsAvail();
+}
+
+int
+ResourcePool::slotsInUse(int res_idx)
+{
+ return resources[res_idx]->slotsInUse();
+}
+
+void
+ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
+ int delay, int res_idx, int tid)
+{
+ assert(delay >= 0);
+
+ ResPoolEvent *res_pool_event = new ResPoolEvent(this);
+
+ switch (e_type)
+ {
+ case InOrderCPU::ActivateThread:
+ {
+ DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
+ curTick + delay);
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ inst->readTid());
+ res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+ }
+ break;
+
+ case InOrderCPU::SuspendThread:
+ case InOrderCPU::DeallocateThread:
+ {
+ DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
+ curTick + delay);
+
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ tid);
+
+ res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+ }
+ break;
+
+ case ResourcePool::InstGraduated:
+ {
+ DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
+ curTick + delay);
+
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->seqNum,
+ inst->readTid());
+ res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+ }
+ break;
+
+ case ResourcePool::SquashAll:
+ {
+ DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
+ curTick + delay);
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ inst->readTid());
+ res_pool_event->schedule(curTick + cpu->cycles(delay));
+
+ }
+ break;
+
+ default:
+ DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
+ ; // If Resource Pool doesnt recognize event, we ignore it.
+ }
+}
+
+void
+ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
+{
+ resources[res_idx]->unscheduleEvent(inst);
+}
+
+void
+ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
+ stage_num, tid, done_seq_num);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->squash(inst, stage_num, done_seq_num, tid);
+ }
+}
+
+void
+ResourcePool::activateAll(unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
+ tid);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->activateThread(tid);
+ }
+}
+
+void
+ResourcePool::deactivateAll(unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
+ tid);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->deactivateThread(tid);
+ }
+}
+
+void
+ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
+ tid, seq_num);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->instGraduated(seq_num, tid);
+ }
+}
+
+ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
+ : Event(&mainEventQueue, CPU_Tick_Pri),
+ resPool(_resPool)
+{ eventType = (InOrderCPU::CPUEventType) Default; }
+
+void
+ResourcePool::ResPoolEvent::process()
+{
+ switch (eventType)
+ {
+ case InOrderCPU::ActivateThread:
+ resPool->activateAll(tid);
+ break;
+
+ case InOrderCPU::SuspendThread:
+ case InOrderCPU::DeallocateThread:
+ resPool->deactivateAll(tid);
+ break;
+
+ case ResourcePool::InstGraduated:
+ resPool->instGraduated(seqNum, tid);
+ break;
+
+ case ResourcePool::SquashAll:
+ resPool->squashAll(inst, stageNum, seqNum, tid);
+ break;
+
+ default:
+ fatal("Unrecognized Event Type");
+ }
+
+ resPool->cpu->cpuEventRemoveList.push(this);
+}
+
+
+const char *
+ResourcePool::ResPoolEvent::description()
+{
+ return "Resource Pool event";
+}
+
+/** Schedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::scheduleEvent(int delay)
+{
+ if (squashed())
+ reschedule(curTick + resPool->cpu->cycles(delay));
+ else if (!scheduled())
+ schedule(curTick + resPool->cpu->cycles(delay));
+}
+
+/** Unschedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::unscheduleEvent()
+{
+ if (scheduled())
+ squash();
+}
diff --git a/src/cpu/inorder/resource_pool.cc b/src/cpu/inorder/resource_pool.cc
new file mode 100644
index 000000000..94af68c7a
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.cc
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/resources/resource_list.hh"
+
+#include <vector>
+#include <list>
+
+using namespace std;
+using namespace ThePipeline;
+
+ResourcePool::ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params)
+ : cpu(_cpu)
+{
+ //@todo: use this function to instantiate the resources in resource pool. This will help in the
+ //auto-generation of this pipeline model.
+ //ThePipeline::addResources(resources, memObjects);
+
+ // Declare Resource Objects
+ // name - id - bandwidth - latency - CPU - Parameters
+ // --------------------------------------------------
+ resources.push_back(new FetchSeqUnit("Fetch-Seq-Unit", FetchSeq, StageWidth * 2, 0, _cpu, params));
+
+ resources.push_back(new TLBUnit("I-TLB", ITLB, StageWidth, 0, _cpu, params));
+
+ memObjects.push_back(ICache);
+ resources.push_back(new CacheUnit("icache_port", ICache, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new DecodeUnit("Decode-Unit", Decode, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new BranchPredictor("Branch-Predictor", BPred, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new InstBuffer("Fetch-Buffer-T0", FetchBuff, 4, 0, _cpu, params));
+
+ resources.push_back(new UseDefUnit("RegFile-Manager", RegManager, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new AGENUnit("AGEN-Unit", AGEN, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new ExecutionUnit("Execution-Unit", ExecUnit, StageWidth, 0, _cpu, params));
+
+ resources.push_back(new MultDivUnit("Mult-Div-Unit", MDU, 5, 0, _cpu, params));
+
+ resources.push_back(new TLBUnit("D-TLB", DTLB, StageWidth, 0, _cpu, params));
+
+ memObjects.push_back(DCache);
+ resources.push_back(new CacheUnit("dcache_port", DCache, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new GraduationUnit("Graduation-Unit", Grad, StageWidth * MaxThreads, 0, _cpu, params));
+
+ resources.push_back(new InstBuffer("Fetch-Buffer-T1", FetchBuff2, 4, 0, _cpu, params));
+}
+
+void
+ResourcePool::init()
+{
+ for (int i=0; i < resources.size(); i++) {
+ DPRINTF(Resource, "Initializing resource: %s.\n", resources[i]->name());
+
+ resources[i]->init();
+ }
+}
+
+string
+ResourcePool::name()
+{
+ return cpu->name() + ".ResourcePool";
+}
+
+
+void
+ResourcePool::regStats()
+{
+ DPRINTF(Resource, "Registering Stats Throughout Resource Pool.\n");
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->regStats();
+ }
+}
+
+Port *
+ResourcePool::getPort(const std::string &if_name, int idx)
+{
+ DPRINTF(Resource, "Binding %s in Resource Pool.\n", if_name);
+
+ for (int i = 0; i < memObjects.size(); i++) {
+ int obj_idx = memObjects[i];
+ Port *port = resources[obj_idx]->getPort(if_name, idx);
+ if (port != NULL) {
+ DPRINTF(Resource, "%s set to resource %s(#%i) in Resource Pool.\n", if_name,
+ resources[obj_idx]->name(), obj_idx);
+ return port;
+ }
+ }
+
+ return NULL;
+}
+
+unsigned
+ResourcePool::getPortIdx(const std::string &port_name)
+{
+ DPRINTF(Resource, "Finding Port Idx for %s.\n", port_name);
+
+ for (int i = 0; i < memObjects.size(); i++) {
+ unsigned obj_idx = memObjects[i];
+ Port *port = resources[obj_idx]->getPort(port_name, obj_idx);
+ if (port != NULL) {
+ DPRINTF(Resource, "Returning Port Idx %i for %s.\n", obj_idx, port_name);
+ return obj_idx;
+ }
+ }
+
+ return 0;
+}
+
+ResReqPtr
+ResourcePool::request(int res_idx, DynInstPtr inst)
+{
+ //Make Sure This is a valid resource ID
+ assert(res_idx >= 0 && res_idx < resources.size());
+
+ return resources[res_idx]->request(inst);
+}
+
+void
+ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid)
+{
+ resources[res_idx]->squash(inst, ThePipeline::NumStages-1, done_seq_num, tid);
+}
+
+int
+ResourcePool::slotsAvail(int res_idx)
+{
+ return resources[res_idx]->slotsAvail();
+}
+
+int
+ResourcePool::slotsInUse(int res_idx)
+{
+ return resources[res_idx]->slotsInUse();
+}
+
+void
+ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
+ int delay, int res_idx, int tid)
+{
+ assert(delay >= 0);
+
+ ResPoolEvent *res_pool_event = new ResPoolEvent(this);
+
+ switch (e_type)
+ {
+ case InOrderCPU::ActivateThread:
+ {
+ DPRINTF(Resource, "Scheduling Activate Thread Resource Pool Event for tick %i.\n",
+ curTick + delay);
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ inst->readTid());
+ mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+ }
+ break;
+
+ case InOrderCPU::SuspendThread:
+ case InOrderCPU::DeallocateThread:
+ {
+ DPRINTF(Resource, "Scheduling Deactivate Thread Resource Pool Event for tick %i.\n",
+ curTick + delay);
+
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ tid);
+
+ mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+ }
+ break;
+
+ case ResourcePool::InstGraduated:
+ {
+ DPRINTF(Resource, "Scheduling Inst-Graduated Resource Pool Event for tick %i.\n",
+ curTick + delay);
+
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->seqNum,
+ inst->readTid());
+ mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+ }
+ break;
+
+ case ResourcePool::SquashAll:
+ {
+ DPRINTF(Resource, "Scheduling Squash Resource Pool Event for tick %i.\n",
+ curTick + delay);
+ res_pool_event->setEvent(e_type,
+ inst,
+ inst->squashingStage,
+ inst->bdelaySeqNum,
+ inst->readTid());
+ mainEventQueue.schedule(res_pool_event, curTick + cpu->ticks(delay));
+
+ }
+ break;
+
+ default:
+ DPRINTF(Resource, "Ignoring Unrecognized CPU Event Type #%i.\n", e_type);
+ ; // If Resource Pool doesnt recognize event, we ignore it.
+ }
+}
+
+void
+ResourcePool::unscheduleEvent(int res_idx, DynInstPtr inst)
+{
+ resources[res_idx]->unscheduleEvent(inst);
+}
+
+void
+ResourcePool::squashAll(DynInstPtr inst, int stage_num, InstSeqNum done_seq_num, unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Stage %i squashing all instructions above [sn:%i].\n",
+ stage_num, tid, done_seq_num);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->squash(inst, stage_num, done_seq_num, tid);
+ }
+}
+
+void
+ResourcePool::activateAll(unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting Thread Activation to all resources.\n",
+ tid);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->activateThread(tid);
+ }
+}
+
+void
+ResourcePool::deactivateAll(unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting Thread Deactivation to all resources.\n",
+ tid);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->deactivateThread(tid);
+ }
+}
+
+void
+ResourcePool::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting [sn:%i] graduation to all resources.\n",
+ tid, seq_num);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++) {
+ resources[idx]->instGraduated(seq_num, tid);
+ }
+}
+
+ResourcePool::ResPoolEvent::ResPoolEvent(ResourcePool *_resPool)
+ : Event(CPU_Tick_Pri),
+ resPool(_resPool)
+{ eventType = (InOrderCPU::CPUEventType) Default; }
+
+void
+ResourcePool::ResPoolEvent::process()
+{
+ switch (eventType)
+ {
+ case InOrderCPU::ActivateThread:
+ resPool->activateAll(tid);
+ break;
+
+ case InOrderCPU::SuspendThread:
+ case InOrderCPU::DeallocateThread:
+ resPool->deactivateAll(tid);
+ break;
+
+ case ResourcePool::InstGraduated:
+ resPool->instGraduated(seqNum, tid);
+ break;
+
+ case ResourcePool::SquashAll:
+ resPool->squashAll(inst, stageNum, seqNum, tid);
+ break;
+
+ default:
+ fatal("Unrecognized Event Type");
+ }
+
+ resPool->cpu->cpuEventRemoveList.push(this);
+}
+
+
+const char *
+ResourcePool::ResPoolEvent::description()
+{
+ return "Resource Pool event";
+}
+
+/** Schedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::scheduleEvent(int delay)
+{
+ if (squashed())
+ mainEventQueue.reschedule(this,curTick + resPool->cpu->ticks(delay));
+ else if (!scheduled())
+ mainEventQueue.schedule(this,curTick + resPool->cpu->ticks(delay));
+}
+
+/** Unschedule resource event, regardless of its current state. */
+void
+ResourcePool::ResPoolEvent::unscheduleEvent()
+{
+ if (scheduled())
+ squash();
+}
diff --git a/src/cpu/inorder/resource_pool.hh b/src/cpu/inorder/resource_pool.hh
new file mode 100644
index 000000000..35fce7db7
--- /dev/null
+++ b/src/cpu/inorder/resource_pool.hh
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_RESOURCE_POOL_HH__
+#define __CPU_INORDER_RESOURCE_POOL_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inst_seq.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/params.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/cpu.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class Event;
+class InOrderCPU;
+class Resource;
+class ResourceEvent;
+
+class ResourcePool {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ // List of Resource Pool Events that extends
+ // the list started by the CPU
+ // NOTE(1): Resource Pool also uses event list
+ // CPUEventType defined in inorder/cpu.hh
+ enum ResPoolEventType {
+ InstGraduated = InOrderCPU::NumCPUEvents,
+ SquashAll,
+ Default
+ };
+
+ class ResPoolEvent : public Event
+ {
+ protected:
+ /** Resource Pool */
+ ResourcePool *resPool;
+
+ public:
+ InOrderCPU::CPUEventType eventType;
+
+ DynInstPtr inst;
+
+ InstSeqNum seqNum;
+
+ int stageNum;
+
+ unsigned tid;
+
+ public:
+ /** Constructs a resource event. */
+ ResPoolEvent(ResourcePool *_resPool);
+
+ /** Set Type of Event To Be Scheduled */
+ void setEvent(InOrderCPU::CPUEventType e_type,
+ DynInstPtr _inst,
+ int stage_num,
+ InstSeqNum seq_num,
+ unsigned _tid)
+ {
+ eventType = e_type;
+ inst = _inst;
+ seqNum = seq_num;
+ stageNum = stage_num;
+ tid = _tid;
+ }
+
+ /** Processes a resource event. */
+ virtual void process();
+
+ /** Returns the description of the resource event. */
+ const char *description();
+
+ /** Schedule Event */
+ void scheduleEvent(int delay);
+
+ /** Unschedule This Event */
+ void unscheduleEvent();
+ };
+
+ public:
+ ResourcePool(InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~ResourcePool() {}
+
+ std::string name();
+
+ std::string name(int res_idx) { return resources[res_idx]->name(); }
+
+ void init();
+
+ /** Register Statistics in All Resources */
+ void regStats();
+
+ /** Returns a specific port. */
+ Port* getPort(const std::string &if_name, int idx);
+
+ /** Returns a specific port. */
+ unsigned getPortIdx(const std::string &if_name);
+
+ Resource* getResource(int res_idx) { return resources[res_idx]; }
+
+ /** Request usage of this resource. Returns -1 if not granted and
+ * a positive request tag if granted.
+ */
+ ResReqPtr request(int res_idx, DynInstPtr inst);
+
+ /** Squash The Resource */
+ void squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num, int tid);
+
+ /** Squash All Resources in Pool after Done Seq. Num */
+ void squashAll(DynInstPtr inst, int stage_num,
+ InstSeqNum done_seq_num, unsigned tid);
+
+ /** Activate Thread in all resources */
+ void activateAll(unsigned tid);
+
+ /** De-Activate Thread in all resources */
+ void deactivateAll(unsigned tid);
+
+ /** Broadcast graduation to all resources */
+ void instGraduated(InstSeqNum seq_num,unsigned tid);
+
+ /** The number of instructions available that a resource can
+ * can still process.
+ */
+ int slotsAvail(int res_idx);
+
+ /** The number of instructions using a resource */
+ int slotsInUse(int res_idx);
+
+ /** Schedule resource event, regardless of its current state. */
+ void scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst = NULL,
+ int delay = 0, int res_idx = 0, int tid = 0);
+
+ /** UnSchedule resource event, regardless of its current state. */
+ void unscheduleEvent(int res_idx, DynInstPtr inst);
+
+ /** Tasks to perform when simulation starts */
+ virtual void startup() { }
+
+ /** The CPU(s) that this resource interacts with */
+ InOrderCPU *cpu;
+
+ DynInstPtr dummyInst[ThePipeline::MaxThreads];
+
+ private:
+ std::vector<Resource *> resources;
+
+ std::vector<int> memObjects;
+
+};
+
+#endif //__CPU_INORDER_RESOURCE_HH__
diff --git a/src/cpu/inorder/resources/agen_unit.cc b/src/cpu/inorder/resources/agen_unit.cc
new file mode 100644
index 000000000..f462b12ea
--- /dev/null
+++ b/src/cpu/inorder/resources/agen_unit.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resources/agen_unit.hh"
+
+AGENUnit::AGENUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+AGENUnit::execute(int slot_num)
+{
+ ResourceRequest* agen_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid;
+ int seq_num = inst->seqNum;
+
+ tid = inst->readTid();
+ agen_req->fault = NoFault;
+
+ switch (agen_req->cmd)
+ {
+ case GenerateAddr:
+ {
+ // Load/Store Instruction
+ if (inst->isMemRef()) {
+ DPRINTF(InOrderAGEN, "[tid:%i] Generating Address for [sn:%i] (%s).\n",
+ tid, inst->seqNum, inst->staticInst->getName());
+
+
+ // We are not handdling Prefetches quite yet
+ if (inst->isDataPrefetch() || inst->isInstPrefetch()) {
+ panic("Prefetches arent handled yet.\n");
+ } else {
+ if (inst->isLoad()) {
+ fault = inst->calcEA();
+ inst->setMemAddr(inst->getEA());
+ //inst->setExecuted();
+
+ DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: "
+ "%#x.\n", tid, inst->seqNum, inst->getEA());
+ } else if (inst->isStore()) {
+ fault = inst->calcEA();
+ inst->setMemAddr(inst->getEA());
+
+ DPRINTF(InOrderAGEN, "[tid:%i] [sn:%i] Effective address calculated to be: "
+ "%#x.\n", tid, inst->seqNum, inst->getEA());
+ } else {
+ panic("Unexpected memory type!\n");
+ }
+
+ if (fault == NoFault) {
+ agen_req->done();
+ } else {
+ fatal("%s encountered @ [sn:%i]",fault->name(), seq_num);
+ }
+ }
+ } else {
+ DPRINTF(InOrderAGEN, "[tid:] Ignoring non-memory instruction [sn:%i].\n", tid, seq_num);
+ agen_req->done();
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
diff --git a/src/base/annotate.hh b/src/cpu/inorder/resources/agen_unit.hh
index 36607bf90..2010c9fa6 100644
--- a/src/base/annotate.hh
+++ b/src/cpu/inorder/resources/agen_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,49 +25,40 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __BASE__ANNOTATE_HH__
-#define __BASE__ANNOTATE_HH__
-
-#include "sim/host.hh"
+#ifndef __CPU_INORDER_AGEN_UNIT_HH__
+#define __CPU_INORDER_AGEN_UNIT_HH__
-#include <string>
+#include <vector>
#include <list>
-#include <map>
-
-
-class System;
+#include <string>
-namespace Annotate {
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/params.hh"
+class AGENUnit : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
-class Annotate {
+ public:
+ AGENUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~AGENUnit() {}
- protected:
- struct AnnotateData {
- Tick time;
- std::string system;
- Addr stack;
- uint32_t stateMachine;
- uint32_t curState;
- uint32_t waitMachine;
- uint32_t waitState;
+ enum Command {
+ GenerateAddr
};
- std::list<AnnotateData*> data;
- std::map<System*, std::string> nameCache;
+ virtual void execute(int slot_num);
- public:
- Annotate();
- void add(System *sys, Addr stack, uint32_t sm, uint32_t st, uint32_t
- wm, uint32_t ws);
- void dump();
+ protected:
+ /** @todo: Add Resource Stats Here */
};
-extern Annotate annotations;
-} //namespace Annotate
-
-#endif //__BASE__ANNOTATE_HH__
-
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/bpred_unit.cc b/src/cpu/inorder/resources/bpred_unit.cc
new file mode 100644
index 000000000..66d0779a2
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.cc
@@ -0,0 +1,426 @@
+/*
+ * 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.
+ *
+ * Authors: Kevin Lim
+ */
+
+#include <list>
+#include <vector>
+
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/inorder/resources/bpred_unit.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+BPredUnit::BPredUnit(ThePipeline::Params *params)
+ : BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
+{
+ // Setup the selected predictor.
+ if (params->predType == "local") {
+ localBP = new LocalBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->instShiftAmt);
+ predictor = Local;
+ } else if (params->predType == "tournament") {
+ tournamentBP = new TournamentBP(params->localPredictorSize,
+ params->localCtrBits,
+ params->localHistoryTableSize,
+ params->localHistoryBits,
+ params->globalPredictorSize,
+ params->globalHistoryBits,
+ params->globalCtrBits,
+ params->choicePredictorSize,
+ params->choiceCtrBits,
+ params->instShiftAmt);
+ predictor = Tournament;
+ } else {
+ fatal("Invalid BP selected!");
+ }
+
+ for (int i=0; i < ThePipeline::MaxThreads; i++)
+ RAS[i].init(params->RASSize);
+}
+
+
+void
+BPredUnit::regStats()
+{
+ lookups
+ .name(name() + ".BPredUnit.lookups")
+ .desc("Number of BP lookups")
+ ;
+
+ condPredicted
+ .name(name() + ".BPredUnit.condPredicted")
+ .desc("Number of conditional branches predicted")
+ ;
+
+ condIncorrect
+ .name(name() + ".BPredUnit.condIncorrect")
+ .desc("Number of conditional branches incorrect")
+ ;
+
+ BTBLookups
+ .name(name() + ".BPredUnit.BTBLookups")
+ .desc("Number of BTB lookups")
+ ;
+
+ BTBHits
+ .name(name() + ".BPredUnit.BTBHits")
+ .desc("Number of BTB hits")
+ ;
+
+ BTBCorrect
+ .name(name() + ".BPredUnit.BTBCorrect")
+ .desc("Number of correct BTB predictions (this stat may not "
+ "work properly.")
+ ;
+
+ usedRAS
+ .name(name() + ".BPredUnit.usedRAS")
+ .desc("Number of times the RAS was used to get a target.")
+ ;
+
+ RASIncorrect
+ .name(name() + ".BPredUnit.RASInCorrect")
+ .desc("Number of incorrect RAS predictions.")
+ ;
+}
+
+
+void
+BPredUnit::switchOut()
+{
+ // Clear any state upon switch out.
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ squash(0, i);
+ }
+}
+
+
+void
+BPredUnit::takeOverFrom()
+{
+ // Can reset all predictor state, but it's not necessarily better
+ // than leaving it be.
+/*
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i)
+ RAS[i].reset();
+
+ BP.reset();
+ BTB.reset();
+*/
+}
+
+
+bool
+BPredUnit::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
+{
+ // See if branch predictor predicts taken.
+ // If so, get its target addr either from the BTB or the RAS.
+ // Save off record of branch stuff so the RAS can be fixed
+ // up once it's done.
+
+ using TheISA::MachInst;
+
+ bool pred_taken = false;
+ Addr target;
+
+ ++lookups;
+
+ void *bp_history = NULL;
+
+ if (inst->isUncondCtrl()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid);
+ pred_taken = true;
+ // Tell the BP there was an unconditional branch.
+ BPUncond(bp_history);
+
+ if (inst->isReturn() && RAS[tid].empty()) {
+ DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting "
+ "false.\n", tid);
+ pred_taken = false;
+ }
+ } else {
+ ++condPredicted;
+
+ pred_taken = BPLookup(PC, bp_history);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+ "for PC %#x\n",
+ tid, pred_taken, inst->readPC());
+ }
+
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+ bp_history, tid);
+
+ // Now lookup in the BTB or RAS.
+ if (pred_taken) {
+ if (inst->isReturn()) {
+ ++usedRAS;
+
+ // If it's a function return call, then look up the address
+ // in the RAS.
+ target = RAS[tid].top();
+
+ // Record the top entry of the RAS, and its index.
+ predict_record.usedRAS = true;
+ predict_record.RASIndex = RAS[tid].topIdx();
+ predict_record.RASTarget = target;
+
+ assert(predict_record.RASIndex < 16);
+
+ RAS[tid].pop();
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, "
+ "RAS predicted target: %#x, RAS index: %i.\n",
+ tid, inst->readPC(), target, predict_record.RASIndex);
+ } else {
+ ++BTBLookups;
+
+ if (inst->isCall()) {
+ RAS[tid].push(PC + sizeof(MachInst));
+
+ // Record that it was a call so that the top RAS entry can
+ // be popped off if the speculation is incorrect.
+ predict_record.wasCall = true;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call"
+ ", adding %#x to the RAS.\n",
+ tid, inst->readPC(), PC + sizeof(MachInst));
+ }
+
+ if (inst->isCall() &&
+ inst->isUncondCtrl() &&
+ inst->isDirectCtrl()) {
+ target = inst->branchTarget();
+
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted"
+ " target to %#x.\n",
+ tid, inst->readPC(), target);
+ } else if (BTB.valid(PC, tid)) {
+ ++BTBHits;
+
+ // If it's not a return, use the BTB to get the target addr.
+ target = BTB.lookup(PC, tid);
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted"
+ " target is %#x.\n",
+ tid, inst->readPC(), target);
+ } else {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
+ pred_taken = false;
+ }
+ }
+ }
+
+ if (pred_taken) {
+ // Set the PC and the instruction's predicted target.
+ PC = target;
+ inst->setPredTarg(target);
+ } else {
+ PC = PC + sizeof(MachInst);
+ inst->setPredTarg(PC);
+ }
+
+ predHist[tid].push_front(predict_record);
+
+ DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
+
+ inst->setBranchPred(pred_taken);
+
+ return pred_taken;
+}
+
+
+void
+BPredUnit::update(const InstSeqNum &done_sn, unsigned tid)
+{
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Commiting branches until sequence"
+ "number %lli.\n", tid, done_sn);
+
+ while (!predHist[tid].empty() &&
+ predHist[tid].back().seqNum <= done_sn) {
+ // Update the branch predictor with the correct results.
+ BPUpdate(predHist[tid].back().PC,
+ predHist[tid].back().predTaken,
+ predHist[tid].back().bpHistory);
+
+ predHist[tid].pop_back();
+ }
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn, unsigned tid)
+{
+ History &pred_hist = predHist[tid];
+
+ while (!pred_hist.empty() &&
+ pred_hist.front().seqNum > squashed_sn) {
+ if (pred_hist.front().usedRAS) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
+ " target: %#x.\n",
+ tid,
+ pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ RAS[tid].restore(pred_hist.front().RASIndex,
+ pred_hist.front().RASTarget);
+
+ } else if (pred_hist.front().wasCall) {
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry "
+ "added to the RAS.\n",tid);
+
+ RAS[tid].pop();
+ }
+
+ // This call should delete the bpHistory.
+ BPSquash(pred_hist.front().bpHistory);
+
+ pred_hist.pop_front();
+ }
+
+}
+
+
+void
+BPredUnit::squash(const InstSeqNum &squashed_sn,
+ const Addr &corr_target,
+ const bool actually_taken,
+ unsigned tid)
+{
+ // Now that we know that a branch was mispredicted, we need to undo
+ // all the branches that have been seen up until this branch and
+ // fix up everything.
+
+ History &pred_hist = predHist[tid];
+
+ ++condIncorrect;
+
+ DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
+ "setting target to %#x.\n",
+ tid, squashed_sn, corr_target);
+
+ squash(squashed_sn, tid);
+
+ // If there's a squash due to a syscall, there may not be an entry
+ // corresponding to the squash. In that case, don't bother trying to
+ // fix up the entry.
+ if (!pred_hist.empty()) {
+ assert(pred_hist.front().seqNum == squashed_sn);
+ if (pred_hist.front().usedRAS) {
+ ++RASIncorrect;
+ }
+
+ BPUpdate(pred_hist.front().PC, actually_taken,
+ pred_hist.front().bpHistory);
+
+ BTB.update(pred_hist.front().PC, corr_target, tid);
+ pred_hist.pop_front();
+ }
+}
+
+
+void
+BPredUnit::BPUncond(void * &bp_history)
+{
+ // Only the tournament predictor cares about unconditional branches.
+ if (predictor == Tournament) {
+ tournamentBP->uncondBr(bp_history);
+ }
+}
+
+
+void
+BPredUnit::BPSquash(void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->squash(bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->squash(bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+bool
+BPredUnit::BPLookup(Addr &inst_PC, void * &bp_history)
+{
+ if (predictor == Local) {
+ return localBP->lookup(inst_PC, bp_history);
+ } else if (predictor == Tournament) {
+ return tournamentBP->lookup(inst_PC, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
+{
+ if (predictor == Local) {
+ localBP->update(inst_PC, taken, bp_history);
+ } else if (predictor == Tournament) {
+ tournamentBP->update(inst_PC, taken, bp_history);
+ } else {
+ panic("Predictor type is unexpected value!");
+ }
+}
+
+
+void
+BPredUnit::dump()
+{
+ /*typename History::iterator pred_hist_it;
+
+ for (int i = 0; i < ThePipeline::MaxThreads; ++i) {
+ if (!predHist[i].empty()) {
+ pred_hist_it = predHist[i].begin();
+
+ cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
+
+ while (pred_hist_it != predHist[i].end()) {
+ cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
+ "bpHistory:%#x\n",
+ (*pred_hist_it).seqNum, (*pred_hist_it).PC,
+ (*pred_hist_it).tid, (*pred_hist_it).predTaken,
+ (*pred_hist_it).bpHistory);
+ pred_hist_it++;
+ }
+
+ cprintf("\n");
+ }
+ }*/
+}
diff --git a/src/cpu/inorder/resources/bpred_unit.hh b/src/cpu/inorder/resources/bpred_unit.hh
new file mode 100644
index 000000000..bd68459d1
--- /dev/null
+++ b/src/cpu/inorder/resources/bpred_unit.hh
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ *
+ * Authors: Kevin Lim
+ * Korey Sewell
+ */
+
+#ifndef __CPU_INORDER_BPRED_UNIT_HH__
+#define __CPU_INORDER_BPRED_UNIT_HH__
+
+// For Addr type.
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "cpu/inst_seq.hh"
+
+//#include "cpu/inorder/params.hh"
+#include "cpu/o3/2bit_local_pred.hh"
+#include "cpu/o3/btb.hh"
+#include "cpu/o3/ras.hh"
+#include "cpu/o3/tournament_pred.hh"
+#include "params/InOrderCPU.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+
+#include <list>
+
+/**
+ * Basically a wrapper class to hold both the branch predictor
+ * and the BTB.
+ */
+class BPredUnit
+{
+ private:
+
+ enum PredType {
+ Local,
+ Tournament
+ };
+
+ PredType predictor;
+
+ public:
+
+ /**
+ * @param params The params object, that has the size of the BP and BTB.
+ */
+ BPredUnit(ThePipeline::Params *params);
+
+ /**
+ * Registers statistics.
+ */
+ void regStats();
+
+ void switchOut();
+
+ void takeOverFrom();
+
+ /**
+ * Predicts whether or not the instruction is a taken branch, and the
+ * target of the branch if it is taken.
+ * @param inst The branch instruction.
+ * @param PC The predicted PC is passed back through this parameter.
+ * @param tid The thread id.
+ * @return Returns if the branch is taken or not.
+ */
+ bool predict(ThePipeline::DynInstPtr &inst, Addr &PC, unsigned tid);
+
+ // @todo: Rename this function.
+ void BPUncond(void * &bp_history);
+
+ /**
+ * Tells the branch predictor to commit any updates until the given
+ * sequence number.
+ * @param done_sn The sequence number to commit any older updates up until.
+ * @param tid The thread id.
+ */
+ void update(const InstSeqNum &done_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, unsigned tid);
+
+ /**
+ * Squashes all outstanding updates until a given sequence number, and
+ * corrects that sn's update with the proper address and taken/not taken.
+ * @param squashed_sn The sequence number to squash any younger updates up
+ * until.
+ * @param corr_target The correct branch target.
+ * @param actually_taken The correct branch direction.
+ * @param tid The thread id.
+ */
+ void squash(const InstSeqNum &squashed_sn, const Addr &corr_target,
+ bool actually_taken, unsigned tid);
+
+ /**
+ * @param bp_history Pointer to the history object. The predictor
+ * will need to update any state and delete the object.
+ */
+ void BPSquash(void *bp_history);
+
+ /**
+ * Looks up a given PC in the BP to see if it is taken or not taken.
+ * @param inst_PC The PC to look up.
+ * @param bp_history Pointer that will be set to an object that
+ * has the branch predictor state associated with the lookup.
+ * @return Whether the branch is taken or not taken.
+ */
+ bool BPLookup(Addr &inst_PC, void * &bp_history);
+
+ /**
+ * Looks up a given PC in the BTB to see if a matching entry exists.
+ * @param inst_PC The PC to look up.
+ * @return Whether the BTB contains the given PC.
+ */
+ bool BTBValid(Addr &inst_PC)
+ { return BTB.valid(inst_PC, 0); }
+
+ /**
+ * Looks up a given PC in the BTB to get the predicted target.
+ * @param inst_PC The PC to look up.
+ * @return The address of the target of the branch.
+ */
+ Addr BTBLookup(Addr &inst_PC)
+ { return BTB.lookup(inst_PC, 0); }
+
+ /**
+ * Updates the BP with taken/not taken information.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param taken Whether the branch was taken or not taken.
+ * @param bp_history Pointer to the branch predictor state that is
+ * associated with the branch lookup that is being updated.
+ * @todo Make this update flexible enough to handle a global predictor.
+ */
+ void BPUpdate(Addr &inst_PC, bool taken, void *bp_history);
+
+ /**
+ * Updates the BTB with the target of a branch.
+ * @param inst_PC The branch's PC that will be updated.
+ * @param target_PC The branch's target that will be added to the BTB.
+ */
+ void BTBUpdate(Addr &inst_PC, Addr &target_PC)
+ { BTB.update(inst_PC, target_PC,0); }
+
+ void dump();
+
+ private:
+ struct PredictorHistory {
+ /**
+ * Makes a predictor history struct that contains any
+ * information needed to update the predictor, BTB, and RAS.
+ */
+ PredictorHistory(const InstSeqNum &seq_num, const Addr &inst_PC,
+ const bool pred_taken, void *bp_history,
+ const unsigned _tid)
+ : seqNum(seq_num), PC(inst_PC), RASTarget(0),
+ RASIndex(0), tid(_tid), predTaken(pred_taken), usedRAS(0),
+ wasCall(0), bpHistory(bp_history)
+ { }
+
+ /** The sequence number for the predictor history entry. */
+ InstSeqNum seqNum;
+
+ /** The PC associated with the sequence number. */
+ Addr PC;
+
+ /** The RAS target (only valid if a return). */
+ Addr RASTarget;
+
+ /** The RAS index of the instruction (only valid if a call). */
+ unsigned RASIndex;
+
+ /** The thread id. */
+ unsigned tid;
+
+ /** Whether or not it was predicted taken. */
+ bool predTaken;
+
+ /** Whether or not the RAS was used. */
+ bool usedRAS;
+
+ /** Whether or not the instruction was a call. */
+ bool wasCall;
+
+ /** Pointer to the history object passed back from the branch
+ * predictor. It is used to update or restore state of the
+ * branch predictor.
+ */
+ void *bpHistory;
+ };
+
+ typedef std::list<PredictorHistory> History;
+
+ /**
+ * The per-thread predictor history. This is used to update the predictor
+ * as instructions are committed, or restore it to the proper state after
+ * a squash.
+ */
+ History predHist[ThePipeline::MaxThreads];
+
+ /** The local branch predictor. */
+ LocalBP *localBP;
+
+ /** The tournament branch predictor. */
+ TournamentBP *tournamentBP;
+
+ /** The BTB. */
+ DefaultBTB BTB;
+
+ /** The per-thread return address stack. */
+ ReturnAddrStack RAS[ThePipeline::MaxThreads];
+
+ /** Stat for number of BP lookups. */
+ Stats::Scalar lookups;
+ /** Stat for number of conditional branches predicted. */
+ Stats::Scalar condPredicted;
+ /** Stat for number of conditional branches predicted incorrectly. */
+ Stats::Scalar condIncorrect;
+ /** Stat for number of BTB lookups. */
+ Stats::Scalar BTBLookups;
+ /** Stat for number of BTB hits. */
+ Stats::Scalar BTBHits;
+ /** Stat for number of times the BTB is correct. */
+ Stats::Scalar BTBCorrect;
+ /** Stat for number of times the RAS is used to get a target. */
+ Stats::Scalar usedRAS;
+ /** Stat for number of times the RAS is incorrect. */
+ Stats::Scalar RASIncorrect;
+};
+
+#endif // __CPU_INORDER_BPRED_UNIT_HH__
diff --git a/src/cpu/inorder/resources/branch_predictor.cc b/src/cpu/inorder/resources/branch_predictor.cc
new file mode 100644
index 000000000..511a0ac82
--- /dev/null
+++ b/src/cpu/inorder/resources/branch_predictor.cc
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resources/branch_predictor.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+BranchPredictor::BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ branchPred(params)
+{
+ instSize = sizeof(MachInst);
+}
+
+void
+BranchPredictor::regStats()
+{
+ predictedTaken
+ .name(name() + ".predictedTaken")
+ .desc("Number of Branches Predicted As Taken (True).");
+
+ predictedNotTaken
+ .name(name() + ".predictedNotTaken")
+ .desc("Number of Branches Predicted As Not Taken (False).");
+
+ Resource::regStats();
+}
+
+void
+BranchPredictor::execute(int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ ResourceRequest* bpred_req = reqMap[slot_num];
+
+ DynInstPtr inst = bpred_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ //int stage_num = bpred_req->getStageNum();
+
+ bpred_req->fault = NoFault;
+
+ switch (bpred_req->cmd)
+ {
+ case PredictBranch:
+ {
+ Addr pred_PC = inst->readNextPC();
+
+ if (inst->isControl()) {
+ // If predicted, the pred_PC will be updated to new target value
+ // If not, the pred_PC be updated to pc+8
+ bool predict_taken = branchPred.predict(inst, pred_PC, tid);
+
+ if (predict_taken) {
+ DPRINTF(Resource, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
+ tid, seq_num);
+
+ inst->setPredTarg(pred_PC);
+
+ predictedTaken++;
+ } else {
+ DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n",
+ tid, seq_num);
+
+ if (inst->isCondDelaySlot())
+ {
+ inst->setPredTarg(inst->readPC() + (2 * instSize));
+ } else {
+ inst->setPredTarg(pred_PC);
+ }
+
+ predictedNotTaken++;
+ }
+
+ inst->setBranchPred(predict_taken);
+
+ DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
+ tid, seq_num, pred_PC);
+
+ } else {
+ DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't "
+ "a control instruction.\n", tid, seq_num);
+ }
+
+ bpred_req->done();
+ }
+ break;
+
+ case UpdatePredictor:
+ {
+ DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n",
+ tid, seq_num);
+
+
+ branchPred.update(seq_num, tid);
+
+ bpred_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+void
+BranchPredictor::squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(InOrderBPred, "Squashing...\n");
+ branchPred.squash(squash_seq_num, tid);
+}
+
+void
+BranchPredictor::instGraduated(InstSeqNum seq_num,unsigned tid)
+{
+ branchPred.update(seq_num, tid);
+}
diff --git a/src/dev/x86/opteron.cc b/src/cpu/inorder/resources/branch_predictor.hh
index ba46f2dfa..47053910d 100644
--- a/src/dev/x86/opteron.cc
+++ b/src/cpu/inorder/resources/branch_predictor.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,85 +25,62 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-/** @file
- * Implementation of Opteron platform.
- */
+#ifndef __CPU_INORDER_BRANCH_PREDICTOR_HH__
+#define __CPU_INORDER_BRANCH_PREDICTOR_HH__
-#include <deque>
-#include <string>
#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/bpred_unit.hh"
+#include "cpu/inorder/cpu.hh"
-#include "arch/x86/x86_traits.hh"
-#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
-#include "dev/x86/opteron.hh"
-#include "sim/system.hh"
+class BranchPredictor : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
-using namespace std;
-using namespace TheISA;
+ public:
+ enum Command {
+ PredictBranch,
+ UpdatePredictor
+ };
-Opteron::Opteron(const Params *p)
- : Platform(p), system(p->system)
-{
- // set the back pointer from the system to myself
- system->platform = this;
-}
+ public:
+ BranchPredictor(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
-Tick
-Opteron::intrFrequency()
-{
- panic("Need implementation\n");
- M5_DUMMY_RETURN
-}
+ virtual void regStats();
-void
-Opteron::postConsoleInt()
-{
- warn_once("Don't know what interrupt to post for console.\n");
- //panic("Need implementation\n");
-}
+ virtual void execute(int slot_num);
-void
-Opteron::clearConsoleInt()
-{
- warn_once("Don't know what interrupt to clear for console.\n");
- //panic("Need implementation\n");
-}
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
-void
-Opteron::postPciInt(int line)
-{
- panic("Need implementation\n");
-}
+ virtual void instGraduated(InstSeqNum seq_num,unsigned tid);
-void
-Opteron::clearPciInt(int line)
-{
- panic("Need implementation\n");
-}
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ BPredUnit branchPred;
-Addr
-Opteron::pciToDma(Addr pciAddr) const
-{
- panic("Need implementation\n");
- M5_DUMMY_RETURN
-}
+ int instSize;
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar predictedTaken;
+ Stats::Scalar predictedNotTaken;
-Addr
-Opteron::calcConfigAddr(int bus, int dev, int func)
-{
- assert(func < 8);
- assert(dev < 32);
- assert(bus == 0);
- return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11));
-}
+};
-Opteron *
-OpteronParams::create()
-{
- return new Opteron(this);
-}
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/cache_unit.cc b/src/cpu/inorder/resources/cache_unit.cc
new file mode 100644
index 000000000..57bcb10ef
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.cc
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "arch/mips/locked_mem.hh"
+#include "arch/utility.hh"
+#include "cpu/inorder/resources/cache_unit.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "mem/request.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+Tick
+CacheUnit::CachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("DefaultFetch doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+void
+CacheUnit::CachePort::recvFunctional(PacketPtr pkt)
+{
+ panic("DefaultFetch doesn't expect recvFunctional callback!");
+}
+
+void
+CacheUnit::CachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("DefaultFetch doesn't expect recvStatusChange callback!");
+}
+
+bool
+CacheUnit::CachePort::recvTiming(Packet *pkt)
+{
+ cachePortUnit->processCacheCompletion(pkt);
+ return true;
+}
+
+void
+CacheUnit::CachePort::recvRetry()
+{
+ cachePortUnit->recvRetry();
+}
+
+CacheUnit::CacheUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ retryPkt(NULL), retrySlot(-1), cacheBlocked(false)
+{
+ cachePort = new CachePort(this);
+}
+
+Port *
+CacheUnit::getPort(const string &if_name, int idx)
+{
+ if (if_name == resName)
+ return cachePort;
+ else
+ return NULL;
+}
+
+int
+CacheUnit::getSlot(DynInstPtr inst)
+{
+ if (!inst->validMemAddr()) {
+ panic("Mem. Addr. must be set before requesting cache access\n");
+ }
+
+ Addr req_addr = inst->getMemAddr();
+
+ if (resName == "icache_port" ||
+ find(addrList.begin(), addrList.end(), req_addr) == addrList.end()) {
+
+ int new_slot = Resource::getSlot(inst);
+
+ if (new_slot == -1)
+ return -1;
+
+ inst->memTime = curTick;
+ addrList.push_back(req_addr);
+ addrMap[req_addr] = inst->seqNum;
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: Address %08p added to dependency list\n",
+ inst->readTid(), inst->seqNum, req_addr);
+ return new_slot;
+ } else {
+ DPRINTF(InOrderCachePort,
+ "Denying request because there is an outstanding"
+ " request to/for addr. %08p. by [sn:%i] @ tick %i\n",
+ req_addr, addrMap[req_addr], inst->memTime);
+ return -1;
+ }
+}
+
+void
+CacheUnit::freeSlot(int slot_num)
+{
+ vector<Addr>::iterator vect_it = find(addrList.begin(), addrList.end(),
+ reqMap[slot_num]->inst->getMemAddr());
+ assert(vect_it != addrList.end());
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: Address %08p removed from dependency list\n",
+ reqMap[slot_num]->inst->readTid(), (*vect_it));
+
+ addrList.erase(vect_it);
+
+ Resource::freeSlot(slot_num);
+}
+
+ResReqPtr
+CacheUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ ScheduleEntry* sched_entry = inst->resSched.top();
+
+ if (!inst->validMemAddr()) {
+ panic("Mem. Addr. must be set before requesting cache access\n");
+ }
+
+ int req_size = 0;
+ MemCmd::Command pkt_cmd;
+
+ if (sched_entry->cmd == InitiateReadData) {
+ pkt_cmd = MemCmd::ReadReq;
+ req_size = inst->getMemAccSize();
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: %i byte Read request from [sn:%i] for addr %08p\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else if (sched_entry->cmd == InitiateWriteData) {
+ pkt_cmd = MemCmd::WriteReq;
+ req_size = inst->getMemAccSize();
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: %i byte Write request from [sn:%i] for addr %08p\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else if (sched_entry->cmd == InitiateFetch){
+ pkt_cmd = MemCmd::ReadReq;
+ req_size = sizeof(MachInst); //@TODO: mips16e
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: %i byte Fetch request from [sn:%i] for addr %08p\n",
+ inst->readTid(), req_size, inst->seqNum, inst->getMemAddr());
+ } else {
+ panic("%i: Unexpected request type (%i) to %s", curTick,
+ sched_entry->cmd, name());
+ }
+
+ return new CacheRequest(this, inst, stage_num, id, slot_num,
+ sched_entry->cmd, req_size, pkt_cmd,
+ 0/*flags*/, this->cpu->readCpuId());
+}
+
+void
+CacheUnit::requestAgain(DynInstPtr inst, bool &service_request)
+{
+ //service_request = false;
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(findRequest(inst));
+ assert(cache_req);
+
+ // Check to see if this instruction is requesting the same command
+ // or a different one
+ if (cache_req->cmd != inst->resSched.top()->cmd) {
+ // If different, then update command in the request
+ cache_req->cmd = inst->resSched.top()->cmd;
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: the command for this instruction\n",
+ inst->readTid(), inst->seqNum);
+
+ service_request = true;
+ } else {
+ // If same command, just check to see if memory access was completed
+ // but dont try to re-execute
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: requesting this resource again\n",
+ inst->readTid(), inst->seqNum);
+
+ service_request = true;
+ }
+}
+
+void
+CacheUnit::execute(int slot_num)
+{
+ if (cacheBlocked) {
+ DPRINTF(InOrderCachePort, "Cache Blocked. Cannot Access\n");
+ return;
+ }
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(reqMap[slot_num]);
+ assert(cache_req);
+
+ DynInstPtr inst = cache_req->inst;
+ int tid;
+ tid = inst->readTid();
+ int seq_num;
+ seq_num = inst->seqNum;
+ //int stage_num = cache_req->getStageNum();
+
+ cache_req->fault = NoFault;
+
+ switch (cache_req->cmd)
+ {
+ case InitiateFetch:
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Initiating fetch access to %s for addr. %08p\n",
+ tid, name(), cache_req->inst->getMemAddr());
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Fetching new cache block from addr: %08p\n",
+ tid, cache_req->memReq->getVaddr());
+
+ inst->setCurResSlot(slot_num);
+ doDataAccess(inst);
+ break;
+
+ case CompleteFetch:
+ if (cache_req->isMemAccComplete()) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: Completing Fetch Access for [sn:%i]\n",
+ tid, inst->seqNum);
+
+ MachInst mach_inst = cache_req->dataPkt->get<MachInst>();
+
+ /**
+ * @TODO: May Need This Function for Endianness-Compatibility
+ * mach_inst =
+ * gtoh(*reinterpret_cast<MachInst *>(&cacheData[tid][offset]));
+ */
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: Fetched instruction is %08p\n",
+ tid, mach_inst);
+
+ // ExtMachInst ext_inst = makeExtMI(mach_inst, cpu->tcBase(tid));
+
+ inst->setMachInst(mach_inst);
+ inst->setASID(tid);
+ inst->setThreadState(cpu->thread[tid]);
+
+ DPRINTF(InOrderStage, "[tid:%i]: Instruction [sn:%i] is: %s\n",
+ tid, seq_num, inst->staticInst->disassemble(inst->PC));
+
+ // Set Up More TraceData info
+ if (inst->traceData) {
+ inst->traceData->setStaticInst(inst->staticInst);
+ inst->traceData->setPC(inst->readPC());
+ }
+
+ cache_req->done();
+ } else {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: Unable to Complete Fetch Access\n",
+ tid, inst->seqNum);
+ DPRINTF(InOrderStall,
+ "STALL: [tid:%i]: Fetch miss from %08p\n",
+ tid, cache_req->inst->readPC());
+ cache_req->setCompleted(false);
+ }
+ break;
+
+ case InitiateReadData:
+ case InitiateWriteData:
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Initiating data access to %s for addr. %08p\n",
+ tid, name(), cache_req->inst->getMemAddr());
+
+ inst->setCurResSlot(slot_num);
+ //inst->memAccess();
+ inst->initiateAcc();
+ break;
+
+ case CompleteReadData:
+ case CompleteWriteData:
+ DPRINTF(InOrderCachePort,
+ "[tid:%i]: [sn:%i]: Trying to Complete Data Access\n",
+ tid, inst->seqNum);
+ if (cache_req->isMemAccComplete()) {
+ cache_req->done();
+ } else {
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: Data miss from %08p\n",
+ tid, cache_req->inst->getMemAddr());
+ cache_req->setCompleted(false);
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+Fault
+CacheUnit::doDataAccess(DynInstPtr inst)
+{
+ Fault fault = NoFault;
+ int tid = 0;
+
+ tid = inst->readTid();
+
+ CacheReqPtr cache_req
+ = dynamic_cast<CacheReqPtr>(reqMap[inst->getCurResSlot()]);
+ assert(cache_req);
+
+ cache_req->dataPkt = new CacheReqPacket(cache_req, cache_req->pktCmd,
+ Packet::Broadcast);
+
+ if (cache_req->dataPkt->isRead()) {
+ cache_req->dataPkt->dataStatic(cache_req->reqData);
+ } else if (cache_req->dataPkt->isWrite()) {
+ cache_req->dataPkt->dataStatic(&cache_req->inst->storeData);
+
+ }
+
+ cache_req->dataPkt->time = curTick;
+
+ bool do_access = true; // flag to suppress cache access
+
+ Request *memReq = cache_req->dataPkt->req;
+
+ if (cache_req->dataPkt->isWrite() && memReq->isLocked()) {
+ assert(cache_req->inst->isStoreConditional());
+ DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
+ do_access = TheISA::handleLockedWrite(cpu, memReq);
+ }
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i] [sn:%i] attempting to access cache\n",
+ tid, inst->seqNum);
+
+ //@TODO: If you want to ignore failed store conditional accesses, then
+ // enable this. However, this might skew memory stats because
+ // the failed store conditional access will get ignored.
+ // - Remove optionality here ...
+ if (1/*do_access*/) {
+ if (!cachePort->sendTiming(cache_req->dataPkt)) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i] [sn:%i] is waiting to retry request\n",
+ tid, inst->seqNum);
+
+ retrySlot = cache_req->getSlot();
+ retryReq = cache_req;
+ retryPkt = cache_req->dataPkt;
+
+ cacheStatus = cacheWaitRetry;
+
+ //cacheBlocked = true;
+
+ DPRINTF(InOrderStall, "STALL: \n");
+
+ cache_req->setCompleted(false);
+ } else {
+ DPRINTF(InOrderCachePort,
+ "[tid:%i] [sn:%i] is now waiting for cache response\n",
+ tid, inst->seqNum);
+ cache_req->setCompleted();
+ cache_req->setMemAccPending();
+ cacheStatus = cacheWaitResponse;
+ cacheBlocked = false;
+ }
+ } else if (!do_access && memReq->isLocked()){
+ // Store-Conditional instructions complete even if they "failed"
+ assert(cache_req->inst->isStoreConditional());
+ cache_req->setCompleted(true);
+
+ DPRINTF(LLSC,
+ "[tid:%i]: T%i Ignoring Failed Store Conditional Access\n",
+ tid, tid);
+
+ cache_req->dataPkt->req->setExtraData(0);
+
+ processCacheCompletion(cache_req->dataPkt);
+
+ // Automatically set these since we ignored the memory access
+ //cache_req->setMemAccPending(false);
+ //cache_req->setMemAccCompleted();
+ } else {
+ // Make cache request again since access due to
+ // inability to access
+ DPRINTF(InOrderStall, "STALL: \n");
+ cache_req->setCompleted(false);
+ }
+
+ return fault;
+}
+
+void
+CacheUnit::processCacheCompletion(PacketPtr pkt)
+{
+ // Cast to correct packet type
+ CacheReqPacket* cache_pkt = dynamic_cast<CacheReqPacket*>(pkt);
+ assert(cache_pkt);
+
+ if (cache_pkt->cacheReq->isSquashed()) {
+ DPRINTF(InOrderCachePort,
+ "Ignoring completion of squashed access, [tid:%i] [sn:%i]\n",
+ cache_pkt->cacheReq->getInst()->readTid(),
+ cache_pkt->cacheReq->getInst()->seqNum);
+
+ cache_pkt->cacheReq->done();
+ return;
+ }
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Waking from cache access to addr. %08p\n",
+ cache_pkt->cacheReq->getInst()->readTid(),
+ cache_pkt->cacheReq->getInst()->seqNum,
+ cache_pkt->cacheReq->getInst()->getMemAddr());
+
+ // Cast to correct request type
+ CacheRequest *cache_req = dynamic_cast<CacheReqPtr>(
+ findRequest(cache_pkt->cacheReq->getInst()));
+ assert(cache_req);
+
+
+ // Get resource request info
+ // @todo: SMT needs to figure out where to get thread # from.
+ unsigned tid = 0;
+ unsigned stage_num = cache_req->getStageNum();
+ DynInstPtr inst = cache_req->inst;
+
+ if (!cache_req->isSquashed()) {
+ if (inst->resSched.top()->cmd == CompleteFetch) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Processing fetch access\n",
+ tid, inst->seqNum);
+ } else if (inst->staticInst && inst->isMemRef()) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Processing cache access\n",
+ tid, inst->seqNum);
+
+ inst->completeAcc(pkt);
+
+ if (inst->isLoad()) {
+ assert(cache_pkt->isRead());
+
+ if (cache_pkt->req->isLocked()) {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: Handling Load-Linked for [sn:%u]\n",
+ tid, inst->seqNum);
+ TheISA::handleLockedRead(cpu, cache_pkt->req);
+ }
+
+ // @TODO: Hardcoded to for load instructions. Assumes that
+ // the dest. idx 0 is always where the data is loaded to.
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Data loaded was: %08p\n",
+ tid, inst->seqNum, inst->readIntResult(0));
+ } else if(inst->isStore()) {
+ assert(cache_pkt->isWrite());
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%u]: [sn:%i]: Data stored was: %08p\n",
+ tid, inst->seqNum,
+ getMemData(cache_pkt));
+
+ }
+ }
+
+ cache_req->setMemAccPending(false);
+ cache_req->setMemAccCompleted();
+
+ // Wake up the CPU (if it went to sleep and was waiting on this
+ // completion event).
+ cpu->wakeCPU();
+
+ DPRINTF(Activity, "[tid:%u] Activating %s due to cache completion\n",
+ tid, cpu->pipelineStage[stage_num]->name());
+
+ cpu->switchToActive(stage_num);
+ } else {
+ DPRINTF(InOrderCachePort,
+ "[tid:%u] Miss on block @ %08p completed, but squashed\n",
+ tid, cache_req->inst->readPC());
+ cache_req->setMemAccCompleted();
+ }
+
+ inst->unsetMemAddr();
+}
+
+void
+CacheUnit::recvRetry()
+{
+ DPRINTF(InOrderCachePort, "Retrying Request for [tid:%i] [sn:%i]\n",
+ retryReq->inst->readTid(), retryReq->inst->seqNum);
+
+ assert(retryPkt != NULL);
+ assert(cacheBlocked);
+ assert(cacheStatus == cacheWaitRetry);
+
+ if (cachePort->sendTiming(retryPkt)) {
+ cacheStatus = cacheWaitResponse;
+ retryPkt = NULL;
+ cacheBlocked = false;
+ } else {
+ DPRINTF(InOrderCachePort,
+ "Retry Request for [tid:%i] [sn:%i] failed\n",
+ retryReq->inst->readTid(), retryReq->inst->seqNum);
+ }
+}
+
+void
+CacheUnit::squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ vector<int> slot_remove_list;
+
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ ResReqPtr req_ptr = (*map_it).second;
+
+ if (req_ptr &&
+ req_ptr->getInst()->readTid() == tid &&
+ req_ptr->getInst()->seqNum > squash_seq_num) {
+
+ DPRINTF(InOrderCachePort,
+ "[tid:%i] Squashing request from [sn:%i]\n",
+ req_ptr->getInst()->readTid(), req_ptr->getInst()->seqNum);
+
+ req_ptr->setSquashed();
+
+ req_ptr->getInst()->setSquashed();
+
+ CacheReqPtr cache_req = dynamic_cast<CacheReqPtr>(req_ptr);
+ assert(cache_req);
+
+ if (!cache_req->isMemAccPending()) {
+ // Mark request for later removal
+ cpu->reqRemoveList.push(req_ptr);
+
+ // Mark slot for removal from resource
+ slot_remove_list.push_back(req_ptr->getSlot());
+ }
+ }
+
+ map_it++;
+ }
+
+ // Now Delete Slot Entry from Req. Map
+ for (int i = 0; i < slot_remove_list.size(); i++)
+ freeSlot(slot_remove_list[i]);
+}
+
+uint64_t
+CacheUnit::getMemData(Packet *packet)
+{
+ switch (packet->getSize())
+ {
+ case 8:
+ return packet->get<uint8_t>();
+
+ case 16:
+ return packet->get<uint16_t>();
+
+ case 32:
+ return packet->get<uint32_t>();
+
+ case 864:
+ return packet->get<uint64_t>();
+
+ default:
+ panic("bad store data size = %d\n", packet->getSize());
+ }
+}
+
diff --git a/src/cpu/inorder/resources/cache_unit.hh b/src/cpu/inorder/resources/cache_unit.hh
new file mode 100644
index 000000000..8cd2b89cb
--- /dev/null
+++ b/src/cpu/inorder/resources/cache_unit.hh
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_CACHE_UNIT_HH__
+#define __CPU_INORDER_CACHE_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+//#include "cpu/inorder/params.hh"
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "mem/port.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "sim/sim_object.hh"
+
+#include "params/InOrderCPU.hh"
+
+class CacheRequest;
+typedef CacheRequest* CacheReqPtr;
+
+class CacheReqPacket;
+typedef CacheReqPacket* CacheReqPktPtr;
+
+class CacheUnit : public Resource
+{
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ CacheUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~CacheUnit() {}
+
+ enum Command {
+ InitiateFetch,
+ CompleteFetch,
+ InitiateReadData,
+ CompleteReadData,
+ InitiateWriteData,
+ CompleteWriteData,
+ Fetch,
+ ReadData,
+ WriteData
+ };
+
+ public:
+ /** CachePort class for the Cache Unit. Handles doing the
+ * communication with the cache/memory.
+ */
+ class CachePort : public Port
+ {
+ protected:
+ /** Pointer to cache port unit */
+ CacheUnit *cachePortUnit;
+
+ public:
+ /** Default constructor. */
+ CachePort(CacheUnit *_cachePortUnit)
+ : Port(_cachePortUnit->name() + "-cache-port",
+ (MemObject*)_cachePortUnit->cpu),
+ cachePortUnit(_cachePortUnit)
+ { }
+
+ bool snoopRangeSent;
+
+ protected:
+ /** Atomic version of receive. Panics. */
+ virtual Tick recvAtomic(PacketPtr pkt);
+
+ /** Functional version of receive. Panics. */
+ virtual void recvFunctional(PacketPtr pkt);
+
+ /** Receives status change. Other than range changing, panics. */
+ virtual void recvStatusChange(Status status);
+
+ /** Returns the address ranges of this device. */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+
+ /** Timing version of receive. Handles setting fetch to the
+ * proper status to start fetching. */
+ virtual bool recvTiming(PacketPtr pkt);
+
+ /** Handles doing a retry of a failed fetch. */
+ virtual void recvRetry();
+ };
+
+ enum CachePortStatus {
+ cacheWaitResponse,
+ cacheWaitRetry,
+ cacheAccessComplete
+ };
+
+ ///virtual void init();
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ void requestAgain(DynInstPtr inst, bool &try_request);
+
+ int getSlot(DynInstPtr inst);
+
+ void freeSlot(int slot_num);
+
+ /** Execute the function of this resource. The Default is action
+ * is to do nothing. More specific models will derive from this
+ * class and define their own execute function.
+ */
+ void execute(int slot_num);
+
+ void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+ /** Processes cache completion event. */
+ void processCacheCompletion(PacketPtr pkt);
+
+ void recvRetry();
+
+ /** Align a PC to the start of an I-cache block. */
+ Addr cacheBlockAlignPC(Addr addr)
+ {
+ //addr = TheISA::realPCToFetchPC(addr);
+ return (addr & ~(cacheBlkMask));
+ }
+
+ /** Returns a specific port. */
+ Port *getPort(const std::string &if_name, int idx);
+
+ /** Fetch on behalf of an instruction. Will check to see
+ * if instruction is actually in resource before
+ * trying to fetch.
+ */
+ //Fault doFetchAccess(DynInstPtr inst);
+
+ /** Read/Write on behalf of an instruction.
+ * curResSlot needs to be a valid value in instruction.
+ */
+ Fault doDataAccess(DynInstPtr inst);
+
+ uint64_t getMemData(Packet *packet);
+
+ protected:
+ /** Cache interface. */
+ CachePort *cachePort;
+
+ CachePortStatus cacheStatus;
+
+ CacheReqPtr retryReq;
+
+ PacketPtr retryPkt;
+
+ int retrySlot;
+
+ bool cacheBlocked;
+
+ std::vector<Addr> addrList;
+
+ std::map<Addr, InstSeqNum> addrMap;
+
+ public:
+ int cacheBlkSize;
+
+ int cacheBlkMask;
+
+ /** Align a PC to the start of the Cache block. */
+ Addr cacheBlockAlign(Addr addr)
+ {
+ return (addr & ~(cacheBlkMask));
+ }
+
+ /** THINGS USED FOR FETCH */
+ // NO LONGER USED BY COMMENT OUT UNTIL FULL VERIFICATION
+ /** The mem line being fetched. */
+ //uint8_t *cacheData[ThePipeline::MaxThreads];
+
+ /** The Addr of the cacheline that has been loaded. */
+ //Addr cacheBlockAddr[ThePipeline::MaxThreads];
+
+ //unsigned fetchOffset[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+};
+
+struct CacheSchedEntry : public ThePipeline::ScheduleEntry
+{
+ enum EntryType {
+ FetchAccess,
+ DataAccess
+ };
+
+ CacheSchedEntry(int stage_num, int _priority, int res_num,
+ MemCmd::Command pkt_cmd, EntryType _type = FetchAccess)
+ : ScheduleEntry(stage_num, _priority, res_num), pktCmd(pkt_cmd),
+ type(_type)
+ { }
+
+ MemCmd::Command pktCmd;
+ EntryType type;
+};
+
+class CacheRequest : public ResourceRequest
+{
+ public:
+ CacheRequest(CacheUnit *cres, DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd, int req_size,
+ MemCmd::Command pkt_cmd, unsigned flags, int cpu_id)
+ : ResourceRequest(cres, inst, stage_num, res_idx, slot_num, cmd),
+ pktCmd(pkt_cmd), memAccComplete(false), memAccPending(false)
+ {
+ memReq = inst->memReq;
+
+ reqData = new uint8_t[req_size];
+ retryPkt = NULL;
+ }
+
+ virtual ~CacheRequest()
+ {
+#if 0
+ delete reqData;
+
+ // Can get rid of packet and packet request now
+ if (*dataPkt) {
+ if (*dataPkt->req) {
+ delete dataPkt->req;
+ }
+ delete dataPkt;
+ }
+
+ // Can get rid of packet and packet request now
+ if (retryPkt) {
+ if (retryPkt->req) {
+ delete retryPkt->req;
+ }
+ delete retryPkt;
+ }
+#endif
+
+ if (memReq)
+ delete memReq;
+ }
+
+ virtual PacketDataPtr getData()
+ { return reqData; }
+
+ void
+ setMemAccCompleted(bool completed = true)
+ {
+ memAccComplete = completed;
+ }
+
+ bool isMemAccComplete() { return memAccComplete; }
+
+ void setMemAccPending(bool pending = true) { memAccPending = pending; }
+ bool isMemAccPending() { return memAccPending; }
+
+ //Make this data private/protected!
+ MemCmd::Command pktCmd;
+ RequestPtr memReq;
+ PacketDataPtr reqData;
+ PacketPtr dataPkt;
+ PacketPtr retryPkt;
+
+ bool memAccComplete;
+ bool memAccPending;
+};
+
+class CacheReqPacket : public Packet
+{
+ public:
+ CacheReqPacket(CacheRequest *_req,
+ Command _cmd, short _dest)
+ : Packet(_req->memReq, _cmd, _dest), cacheReq(_req)
+ {
+
+ }
+
+ CacheRequest *cacheReq;
+};
+
+#endif //__CPU_CACHE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/decode_unit.cc b/src/cpu/inorder/resources/decode_unit.cc
new file mode 100644
index 000000000..d95b1d4bb
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resources/decode_unit.hh"
+
+using namespace TheISA;
+using namespace ThePipeline;
+using namespace std;
+
+DecodeUnit::DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{
+ for (int tid = 0; tid < MaxThreads; tid++) {
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+void
+DecodeUnit::execute(int slot_num)
+{
+ ResourceRequest* decode_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid, seq_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ decode_req->fault = NoFault;
+
+ switch (decode_req->cmd)
+ {
+ case DecodeInst:
+ {
+ bool done_sked = ThePipeline::createBackEndSchedule(inst);
+
+ if (done_sked) {
+ DPRINTF(InOrderDecode, "[tid:%i]: Setting Destination Register(s) for [sn:%i].\n",
+ tid, seq_num);
+ regDepMap[tid]->insert(inst);
+ decode_req->done();
+ } else {
+ DPRINTF(Resource,"[tid:%i] Static Inst not available to decode. Unable to create "
+ "schedule for instruction [sn:%i] \n", tid, inst->seqNum);
+ DPRINTF(InOrderStall, "STALL: \n");
+ decode_req->done(false);
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+
+void
+DecodeUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(InOrderDecode, "[tid:%i]: Updating due to squash from stage %i after [sn:%i].\n",
+ tid, stage_num, squash_seq_num);
+
+ //cpu->removeInstsUntil(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/decode_unit.hh b/src/cpu/inorder/resources/decode_unit.hh
new file mode 100644
index 000000000..3813de6c4
--- /dev/null
+++ b/src/cpu/inorder/resources/decode_unit.hh
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_DECODE_UNIT_HH__
+#define __CPU_INORDER_DECODE_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class DecodeUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ DecodeUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~DecodeUnit() {}
+
+ enum Command {
+ DecodeInst
+ };
+
+ virtual void execute(int slot_num);
+
+ void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ protected:
+ /** @todo: Add Resource Stats Here */
+};
+
+#endif //__CPU_INORDER_DECODE_UNIT_HH__
diff --git a/src/cpu/inorder/resources/execution_unit.cc b/src/cpu/inorder/resources/execution_unit.cc
new file mode 100644
index 000000000..843adb5b0
--- /dev/null
+++ b/src/cpu/inorder/resources/execution_unit.cc
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+ExecutionUnit::ExecutionUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+ExecutionUnit::regStats()
+{
+ predictedTakenIncorrect
+ .name(name() + ".predictedTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Taken.");
+
+ predictedNotTakenIncorrect
+ .name(name() + ".predictedNotTakenIncorrect")
+ .desc("Number of Branches Incorrectly Predicted As Not Taken).");
+
+ Resource::regStats();
+}
+
+void
+ExecutionUnit::execute(int slot_num)
+{
+ ResourceRequest* exec_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ exec_req->fault = NoFault;
+
+ DPRINTF(InOrderExecute, "[tid:%i] Executing [sn:%i] [PC:%#x] .\n",
+ tid, seq_num, inst->readPC());
+
+ switch (exec_req->cmd)
+ {
+ case ExecuteInst:
+ {
+ if (inst->isMemRef()) {
+ fatal("%s not configured to handle memory ops.\n", resName);
+ } else if (inst->isControl()) {
+ // Evaluate Branch
+ fault = inst->execute();
+
+ inst->setExecuted();
+
+ if (fault == NoFault) {
+ // If branch is mispredicted, then signal squash
+ // throughout all stages behind the pipeline stage
+ // that got squashed.
+ if (inst->mispredicted()) {
+ int stage_num = exec_req->getStageNum();
+ int tid = inst->readTid();
+
+ // If it's a branch ...
+ if (inst->isDirectCtrl()) {
+ assert(!inst->isIndirectCtrl());
+
+ if (inst->predTaken() && inst->isCondDelaySlot()) {
+ inst->bdelaySeqNum = seq_num;
+ inst->setPredTarg(inst->nextPC);
+
+ DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst"
+ "[sn:%i] PC %#x mispredicted as taken.\n", tid,
+ seq_num, inst->PC);
+ } else if (!inst->predTaken() && inst->isCondDelaySlot()) {
+ inst->bdelaySeqNum = seq_num;
+ inst->setPredTarg(inst->nextPC);
+ inst->procDelaySlotOnMispred = true;
+
+ DPRINTF(InOrderExecute, "[tid:%i]: Conditional branch inst."
+ "[sn:%i] PC %#x mispredicted as not taken.\n", tid,
+ seq_num, inst->PC);
+ } else {
+ inst->bdelaySeqNum = seq_num + 1;
+
+ DPRINTF(InOrderExecute, "[tid:%i]: Misprediction detected at "
+ "[sn:%i] PC %#x,\n\t squashing after delay slot "
+ "instruction [sn:%i].\n",
+ tid, seq_num, inst->PC, inst->bdelaySeqNum);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: Branch "
+ "misprediction at %#x\n", tid, inst->PC);
+ inst->setPredTarg(inst->nextNPC);
+ }
+
+ DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+
+ } else if(inst->isIndirectCtrl()){
+ inst->setPredTarg(inst->nextNPC);
+ inst->bdelaySeqNum = seq_num + 1;
+ DPRINTF(InOrderExecute, "[tid:%i] Redirecting fetch to %#x.\n", tid,
+ inst->readPredTarg());
+ } else {
+ panic("Non-control instruction (%s) mispredicting?!!",
+ inst->staticInst->getName());
+ }
+
+ DPRINTF(InOrderExecute, "[tid:%i] Squashing will start from stage %i.\n",
+ tid, stage_num);
+
+ cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+
+ inst->squashingStage = stage_num;
+
+ // Squash throughout other resources
+ cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll,
+ inst, 0, 0, tid);
+
+ if (inst->predTaken()) {
+ predictedTakenIncorrect++;
+ } else {
+ predictedNotTakenIncorrect++;
+ }
+ }
+ exec_req->done();
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ }
+ } else {
+ // Regular ALU instruction
+ fault = inst->execute();
+
+ if (fault == NoFault) {
+ inst->setExecuted();
+ exec_req->done();
+
+ DPRINTF(InOrderExecute, "[tid:%i]: The result of execution is 0x%x.\n",
+ inst->readTid(), inst->readIntResult(0));
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ cpu->trap(fault, tid);
+ }
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+
diff --git a/src/cpu/inorder/resources/execution_unit.hh b/src/cpu/inorder/resources/execution_unit.hh
new file mode 100644
index 000000000..46691bbf2
--- /dev/null
+++ b/src/cpu/inorder/resources/execution_unit.hh
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_EXECUTION_UNIT_HH__
+#define __CPU_INORDER_EXECUTION_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+
+class ExecutionUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ExecuteInst
+ };
+
+ public:
+ ExecutionUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~ExecutionUnit() {}
+
+ public:
+ virtual void regStats();
+
+ /** Execute the function of this resource. The Default is action
+ * is to do nothing. More specific models will derive from this
+ * class and define their own execute function.
+ */
+ virtual void execute(int slot_num);
+
+ protected:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ Stats::Scalar predictedTakenIncorrect;
+ Stats::Scalar predictedNotTakenIncorrect;
+};
+
+
+#endif //__CPU_INORDER_EXCUTION_UNIT_HH__
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.cc b/src/cpu/inorder/resources/fetch_seq_unit.cc
new file mode 100644
index 000000000..444252e1b
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.cc
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resources/fetch_seq_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ instSize(sizeof(MachInst))
+{
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ pcValid[tid] = false;
+ pcBlockStage[tid] = 0;
+
+ squashSeqNum[tid] = (InstSeqNum)-1;
+ lastSquashCycle[tid] = 0;
+ }
+}
+
+void
+FetchSeqUnit::init()
+{
+ resourceEvent = new FetchSeqEvent[width];
+
+ initSlots();
+}
+
+void
+FetchSeqUnit::execute(int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ ResourceRequest* fs_req = reqMap[slot_num];
+ DynInstPtr inst = fs_req->inst;
+ int tid = inst->readTid();
+ int stage_num = fs_req->getStageNum();
+ int seq_num = inst->seqNum;
+
+ fs_req->fault = NoFault;
+
+ switch (fs_req->cmd)
+ {
+ case AssignNextPC:
+ {
+ if (pcValid[tid]) {
+
+ if (delaySlotInfo[tid].targetReady &&
+ delaySlotInfo[tid].numInsts == 0) {
+ // Set PC to target
+ PC[tid] = delaySlotInfo[tid].targetAddr; //next_PC
+ nextPC[tid] = PC[tid] + instSize; //next_NPC
+ nextNPC[tid] = PC[tid] + (2 * instSize);
+
+ delaySlotInfo[tid].targetReady = false;
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to delay slot target\n",tid);
+ }
+
+ inst->setPC(PC[tid]);
+ inst->setNextPC(PC[tid] + instSize);
+ inst->setNextNPC(PC[tid] + (instSize * 2));
+
+ inst->setPredTarg(inst->readNextNPC());
+
+ inst->setMemAddr(PC[tid]);
+ inst->setSeqNum(cpu->getAndIncrementInstSeq(tid));
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Assigning [sn:%i] to PC %08p\n", tid,
+ inst->seqNum, inst->readPC());
+
+ if (delaySlotInfo[tid].numInsts > 0) {
+ --delaySlotInfo[tid].numInsts;
+
+ // It's OK to set PC to target of branch
+ if (delaySlotInfo[tid].numInsts == 0) {
+ delaySlotInfo[tid].targetReady = true;
+ }
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: %i delay slot inst(s) left to"
+ " process.\n", tid, delaySlotInfo[tid].numInsts);
+ }
+
+ PC[tid] = nextPC[tid];
+ nextPC[tid] = nextNPC[tid];
+ nextNPC[tid] += instSize;
+
+ fs_req->done();
+ } else {
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: NPC not valid\n", tid);
+ fs_req->setCompleted(false);
+ }
+ }
+ break;
+
+ case UpdateTargetPC:
+ {
+ if (inst->isControl()) {
+ // If it's a return, then we must wait for resolved address.
+ if (inst->isReturn() && !inst->predTaken()) {
+ cpu->pipelineStage[stage_num]->toPrevStages->stageBlock[stage_num][tid] = true;
+ pcValid[tid] = false;
+ pcBlockStage[tid] = stage_num;
+ } else if (inst->isCondDelaySlot() && !inst->predTaken()) {
+ // Not-Taken AND Conditional Control
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: [PC:%08p] Predicted Not-Taken Cond. "
+ "Delay inst. Skipping delay slot and Updating PC to %08p\n",
+ tid, inst->seqNum, inst->readPC(), inst->readPredTarg());
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
+ tid, stage_num, seq_num);
+
+ inst->bdelaySeqNum = seq_num;
+ inst->squashingStage = stage_num;
+
+ squashAfterInst(inst, stage_num, tid);
+ } else if (!inst->isCondDelaySlot() && !inst->predTaken()) {
+ // Not-Taken Control
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Predicted Not-Taken Control "
+ "inst. updating PC to %08p\n", tid, inst->seqNum,
+ inst->readNextPC());
+
+ ++delaySlotInfo[tid].numInsts;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = inst->readNextNPC();
+
+ } else if (inst->predTaken()) {
+ // Taken Control
+ ++delaySlotInfo[tid].numInsts;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = inst->readPredTarg();
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i] Updating delay slot target "
+ "to PC %08p\n", tid, inst->seqNum, inst->readPredTarg());
+
+ // Set-Up Squash Through-Out Pipeline
+ DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to start from stage %i, after [sn:%i].\n",
+ tid, stage_num, seq_num + 1);
+ inst->bdelaySeqNum = seq_num + 1;
+ inst->squashingStage = stage_num;
+
+ // Do Squashing
+ squashAfterInst(inst, stage_num, tid);
+ }
+ } else {
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch target update "
+ "since then is not a control instruction.\n", tid, inst->seqNum);
+ }
+
+ fs_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+inline void
+FetchSeqUnit::squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid)
+{
+ // Squash In Pipeline Stage
+ cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+
+ // Squash inside current resource, so if there needs to be fetching on same cycle
+ // the fetch information will be correct.
+ // squash(inst, stage_num, inst->bdelaySeqNum, tid);
+
+ // Schedule Squash Through-out Resource Pool
+ cpu->resPool->scheduleEvent((InOrderCPU::CPUEventType)ResourcePool::SquashAll, inst, 0);
+}
+void
+FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Updating due to squash from stage %i.\n",
+ tid, squash_stage);
+
+ InstSeqNum done_seq_num = inst->bdelaySeqNum;
+ Addr new_PC = inst->readPredTarg();
+
+ if (squashSeqNum[tid] <= done_seq_num &&
+ lastSquashCycle[tid] == curTick) {
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, since"
+ "there is an outstanding squash that is older.\n",
+ tid, squash_stage);
+ } else {
+ squashSeqNum[tid] = done_seq_num;
+ lastSquashCycle[tid] = curTick;
+
+ // If The very next instruction number is the done seq. num,
+ // then we haven't seen the delay slot yet ... if it isn't
+ // the last done_seq_num then this is the delay slot inst.
+ if (cpu->nextInstSeqNum(tid) != done_seq_num &&
+ !inst->procDelaySlotOnMispred) {
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ // Reset PC
+ PC[tid] = new_PC;
+ nextPC[tid] = new_PC + instSize;
+ nextNPC[tid] = new_PC + (2 * instSize);
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %08p.\n",
+ tid, PC[tid]);
+ } else {
+ delaySlotInfo[tid].numInsts = 1;
+ delaySlotInfo[tid].targetReady = false;
+ delaySlotInfo[tid].targetAddr = (inst->procDelaySlotOnMispred) ? inst->branchTarget() : new_PC;
+
+ // Reset PC to Delay Slot Instruction
+ if (inst->procDelaySlotOnMispred) {
+ PC[tid] = new_PC;
+ nextPC[tid] = new_PC + instSize;
+ nextNPC[tid] = new_PC + (2 * instSize);
+ }
+
+ }
+
+ // Unblock Any Stages Waiting for this information to be updated ...
+ if (!pcValid[tid]) {
+ cpu->pipelineStage[pcBlockStage[tid]]->toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ }
+
+ pcValid[tid] = true;
+ }
+
+ Resource::squash(inst, squash_stage, squash_seq_num, tid);
+}
+
+FetchSeqUnit::FetchSeqEvent::FetchSeqEvent()
+ : ResourceEvent()
+{ }
+
+void
+FetchSeqUnit::FetchSeqEvent::process()
+{
+ FetchSeqUnit* fs_res = dynamic_cast<FetchSeqUnit*>(resource);
+ assert(fs_res);
+
+ for (int i=0; i < MaxThreads; i++) {
+ fs_res->PC[i] = fs_res->cpu->readPC(i);
+ fs_res->nextPC[i] = fs_res->cpu->readNextPC(i);
+ fs_res->nextNPC[i] = fs_res->cpu->readNextNPC(i);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC:%08p NPC:%08p NNPC:%08p.\n",
+ fs_res->PC[i], fs_res->nextPC[i], fs_res->nextNPC[i]);
+
+ fs_res->pcValid[i] = true;
+ }
+
+ //cpu->fetchPriorityList.push_back(tid);
+}
+
+
+void
+FetchSeqUnit::activateThread(unsigned tid)
+{
+ pcValid[tid] = true;
+
+ PC[tid] = cpu->readPC(tid);
+ nextPC[tid] = cpu->readNextPC(tid);
+ nextNPC[tid] = cpu->readNextNPC(tid);
+
+ cpu->fetchPriorityList.push_back(tid);
+
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Reading PC:%08p NPC:%08p NNPC:%08p.\n",
+ tid, PC[tid], nextPC[tid], nextNPC[tid]);
+}
+
+void
+FetchSeqUnit::deactivateThread(unsigned tid)
+{
+ delaySlotInfo[tid].numInsts = 0;
+ delaySlotInfo[tid].targetReady = false;
+
+ pcValid[tid] = false;
+ pcBlockStage[tid] = 0;
+
+ squashSeqNum[tid] = (InstSeqNum)-1;
+ lastSquashCycle[tid] = 0;
+
+ std::list<unsigned>::iterator thread_it = find(cpu->fetchPriorityList.begin(),
+ cpu->fetchPriorityList.end(),
+ tid);
+
+ if (thread_it != cpu->fetchPriorityList.end())
+ cpu->fetchPriorityList.erase(thread_it);
+}
diff --git a/src/cpu/inorder/resources/fetch_seq_unit.hh b/src/cpu/inorder/resources/fetch_seq_unit.hh
new file mode 100644
index 000000000..1885d1f11
--- /dev/null
+++ b/src/cpu/inorder/resources/fetch_seq_unit.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_FETCH_SEQ_UNIT_HH__
+#define __CPU_INORDER_FETCH_SEQ_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class FetchSeqUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ AssignNextPC,
+ UpdateTargetPC
+ };
+
+ public:
+ FetchSeqUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~FetchSeqUnit() {}
+
+ virtual void init();
+ virtual void activateThread(unsigned tid);
+ virtual void deactivateThread(unsigned tid);
+ virtual void execute(int slot_num);
+
+ /** Override default Resource squash sequence. This actually,
+ * looks in the global communication buffer to get squash
+ * info
+ */
+ virtual void squash(DynInstPtr inst, int squash_stage,
+ InstSeqNum squash_seq_num, unsigned tid);
+
+
+ inline void squashAfterInst(DynInstPtr inst, int stage_num, unsigned tid);
+
+ protected:
+ unsigned instSize;
+
+ bool pcValid[ThePipeline::MaxThreads];
+ int pcBlockStage[ThePipeline::MaxThreads];
+
+ TheISA::IntReg PC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextPC[ThePipeline::MaxThreads];
+ TheISA::IntReg nextNPC[ThePipeline::MaxThreads];
+
+ /** Tracks delay slot information for threads in ISAs which use
+ * delay slots;
+ */
+ struct DelaySlotInfo {
+ InstSeqNum delaySlotSeqNum;
+ InstSeqNum branchSeqNum;
+ int numInsts;
+ Addr targetAddr;
+ bool targetReady;
+ };
+
+ DelaySlotInfo delaySlotInfo[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ InstSeqNum squashSeqNum[ThePipeline::MaxThreads];
+
+ /** Squash Seq. Nums*/
+ Tick lastSquashCycle[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class FetchSeqEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ FetchSeqEvent();
+ virtual ~FetchSeqEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+ };
+
+};
+
+#endif
diff --git a/src/cpu/inorder/resources/graduation_unit.cc b/src/cpu/inorder/resources/graduation_unit.cc
new file mode 100644
index 000000000..569401e4f
--- /dev/null
+++ b/src/cpu/inorder/resources/graduation_unit.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "cpu/inorder/resources/graduation_unit.hh"
+
+using namespace ThePipeline;
+
+GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ lastCycleGrad(0), numCycleGrad(0)
+
+{
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
+ nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
+ }
+}
+
+void
+GraduationUnit::execute(int slot_num)
+{
+ ResourceRequest* grad_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid, seq_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ int stage_num = inst->resSched.top()->stageNum;
+
+ grad_req->fault = NoFault;
+
+ switch (grad_req->cmd)
+ {
+ case GraduateInst:
+ {
+ // @TODO: Instructions should never really get to this point since this should be handled
+ // through the request interface. Check to make sure this happens and delete this
+ // code.
+ if (lastCycleGrad != curTick) {
+ lastCycleGrad = curTick;
+ numCycleGrad = 0;
+ } else if (numCycleGrad > width) {
+ DPRINTF(InOrderGraduation, "Graduation bandwidth reached for this cycle.\n");
+ return;
+ }
+
+ // Make sure this is the last thing on the resource schedule
+ assert(inst->resSched.size() == 1);
+
+ DPRINTF(InOrderGraduation, "[tid:%i] Graduating instruction [sn:%i].\n",
+ tid, seq_num);
+
+ DPRINTF(RefCount, "Refcount = %i.\n", 0/*inst->curCount()*/);
+
+ // Release Non-Speculative "Block" on instructions that could not execute
+ // because there was a non-speculative inst. active.
+ // @TODO: Fix this functionality. Probably too conservative.
+ if (inst->isNonSpeculative()) {
+ *nonSpecInstActive[tid] = false;
+ DPRINTF(InOrderGraduation, "[tid:%i] Non-speculative instruction [sn:%i] has graduated.\n",
+ tid, seq_num);
+ }
+
+ if (inst->traceData) {
+ inst->traceData->setStageCycle(stage_num, curTick);
+ }
+
+ // Tell CPU that instruction is finished processing
+ cpu->instDone(inst, tid);
+
+ //cpu->pipelineStage[stage_num]->toPrevStages->
+ //stageInfo[stage_num][tid].doneSeqNum = inst->seqNum;
+
+ grad_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+}
diff --git a/src/cpu/o3/alpha/params.hh b/src/cpu/inorder/resources/graduation_unit.hh
index 164c25312..ad222b119 100644
--- a/src/cpu/o3/alpha/params.hh
+++ b/src/cpu/inorder/resources/graduation_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,37 +25,46 @@
* (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: Kevin Lim
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __CPU_O3_ALPHA_PARAMS_HH__
-#define __CPU_O3_ALPHA_PARAMS_HH__
-
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
-
-//Forward declarations
-namespace AlphaISA
-{
- class DTB;
- class ITB;
-}
-class MemObject;
-class Process;
-class System;
-
-/**
- * This file defines the parameters that will be used for the AlphaO3CPU.
- * This must be defined externally so that the Impl can have a params class
- * defined that it can pass to all of the individual stages.
- */
+#ifndef __CPU_INORDER_GRAD_UNIT_HH__
+#define __CPU_INORDER_GRAD_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
-class AlphaSimpleParams : public O3Params
-{
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class GraduationUnit : public Resource {
public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ GraduateInst
+ };
+
+ public:
+ GraduationUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~GraduationUnit() {}
+
+ virtual void execute(int slot_num);
+
+ protected:
+ Tick lastCycleGrad;
+ int numCycleGrad;
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
- AlphaISA::ITB *itb;
- AlphaISA::DTB *dtb;
+ /** @todo: Add Resource Stats Here */
};
-#endif // __CPU_O3_ALPHA_PARAMS_HH__
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer.cc b/src/cpu/inorder/resources/inst_buffer.cc
new file mode 100644
index 000000000..fafff1fa7
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+void
+InstBuffer::regStats()
+{
+ instsBypassed
+ .name(name() + ".instsBypassed")
+ .desc("Number of Instructions Bypassed.");
+
+ Resource::regStats();
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ ResReqPtr ib_req = reqMap[slot_idx];
+ DynInstPtr inst = ib_req->inst;
+ int tid, seq_num, stage_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ stage_num = ib_req->getStageNum();
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case ScheduleOrBypass:
+ {
+ int next_stage = stage_num + 1;
+ int bypass_stage = stage_num + 2;
+ bool do_bypass = true;
+
+ if (!instList.empty()) {
+ DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because buffer isn't empty.\n",
+ inst->seqNum, next_stage);
+ do_bypass = false;
+ } else if(cpu->pipelineStage[bypass_stage]->isBlocked(tid)) {
+ DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because stage %i is blocking.\n",
+ inst->seqNum, next_stage);
+ do_bypass = false;
+ } else if(cpu->pipelineStage[bypass_stage]->stageBufferAvail() <= 0) {
+ DPRINTF(InOrderInstBuffer, "[sn:%i] cannot bypass stage %i because there is no room in "
+ "stage %i incoming stage buffer.\n", inst->seqNum, next_stage);
+ do_bypass = false;
+ }
+
+ if (!do_bypass) { // SCHEDULE USAGE OF BUFFER
+ DPRINTF(InOrderInstBuffer, "Scheduling [sn:%i] for buffer insertion in stage %i\n",
+ inst->seqNum, next_stage);
+
+ // Add to schedule: Insert into buffer in next stage
+ int stage_pri = ThePipeline::getNextPriority(inst, next_stage);
+
+ inst->resSched.push(new ScheduleEntry(next_stage, stage_pri, id,
+ InstBuffer::InsertInst));
+
+ // Add to schedule: Remove from buffer in next next (bypass) stage
+ stage_pri = ThePipeline::getNextPriority(inst, bypass_stage);
+
+ inst->resSched.push(new ScheduleEntry(bypass_stage, stage_pri, id,
+ InstBuffer::RemoveInst));
+ } else { // BYPASS BUFFER & NEXT STAGE
+ DPRINTF(InOrderInstBuffer, "Setting [sn:%i] to bypass stage %i and enter stage %i.\n",
+ inst->seqNum, next_stage, bypass_stage);
+ inst->setNextStage(bypass_stage);
+ instsBypassed++;
+ }
+
+ ib_req->done();
+ }
+ break;
+
+ case InsertInst:
+ {
+ bool inserted = false;
+
+ if (instList.size() < width) {
+ DPRINTF(InOrderInstBuffer, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ inserted = true;
+ } else {
+ DPRINTF(InOrderInstBuffer, "[tid:%i]: Denying [sn:%i] request because "
+ "buffer is full.\n", tid, seq_num);
+
+
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ DPRINTF(Resource,"Serving [tid:%i] [sn:%i].\n", (*list_it)->readTid(), (*list_it)->seqNum);
+ list_it++;
+ }
+ }
+
+ ib_req->done(inserted);
+ }
+ break;
+
+ case RemoveInst:
+ {
+ DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing [sn:%i] from buffer.\n",
+ tid, seq_num);
+ remove(inst);
+ ib_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+ DPRINTF(InOrderInstBuffer, "Buffer now contains %i insts.\n", instList.size());
+}
+
+void
+InstBuffer::insert(DynInstPtr inst)
+{
+ instList.push_back(inst);
+}
+
+void
+InstBuffer::remove(DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ instList.erase(list_it);
+ break;
+ }
+ list_it++;
+ }
+}
+
+void
+InstBuffer::pop(unsigned tid)
+{
+ instList.pop_front();
+}
+
+ThePipeline::DynInstPtr
+InstBuffer::top(unsigned tid)
+{
+ return instList.front();
+}
+
+void
+InstBuffer::squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid)
+{
+ queue<list<DynInstPtr>::iterator> remove_list;
+ list<DynInstPtr>::iterator list_it = instList.begin();
+ list<DynInstPtr>::iterator list_end = instList.end();
+
+ // Collect All Instructions to be Removed in Remove List
+ while (list_it != list_end) {
+ if((*list_it)->readTid() == tid &&
+ (*list_it)->seqNum > squash_seq_num) {
+ (*list_it)->setSquashed();
+ remove_list.push(list_it);
+ }
+
+ list_it++;
+ }
+
+ // Removed Instructions from InstList & Clear Remove List
+ while (!remove_list.empty()) {
+ DPRINTF(InOrderInstBuffer, "[tid:%i]: Removing squashed [sn:%i] from buffer.\n",
+ tid, (*remove_list.front())->seqNum);
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(inst, stage_num, squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer.hh b/src/cpu/inorder/resources/inst_buffer.hh
new file mode 100644
index 000000000..baadd42ff
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer.hh
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr,
+ ScheduleOrBypass
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~InstBuffer() {}
+
+ virtual void regStats();
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop(unsigned tid);
+
+ virtual DynInstPtr top(unsigned tid);
+
+ virtual void squash(DynInstPtr inst, int stage_num,
+ InstSeqNum squash_seq_num, unsigned tid);
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ public:
+ /////////////////////////////////////////////////////////////////
+ //
+ // RESOURCE STATISTICS
+ //
+ /////////////////////////////////////////////////////////////////
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar instsBypassed;
+
+};
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/cpu/inorder/resources/inst_buffer_new.cc b/src/cpu/inorder/resources/inst_buffer_new.cc
new file mode 100644
index 000000000..7e2c98837
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+InstBuffer::InstBuffer(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu)
+{ }
+
+ResReqPtr
+InstBuffer::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferEntry* ib_entry = dynamic_cast<InstBufferEntry*>(inst->resSched.top());
+ assert(ib_entry);
+
+ return new InstBufferRequest(this, inst, stage_num, id, slot_num,
+ ib_entry->cmd);
+}
+
+void
+InstBuffer::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ InstBufferRequest* ib_req = dynamic_cast<InstBufferRequest*>(reqMap[slot_idx]);
+ assert(ib_req);
+
+ DynInstPtr inst = ib_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ ib_req->fault = NoFault;
+
+ switch (ib_req->cmd)
+ {
+ case InsertInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Inserting [sn:%i] into buffer.\n",
+ tid, seq_num);
+ insert(inst);
+ ib_req->done();
+ }
+ break;
+
+ case RemoveInst:
+ {
+ DPRINTF(Resource, "[tid:%i]: Removing [sn:%i] from buffer.\n",
+ tid, seq_num);
+ remove(inst);
+ ib_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+ DPRINTF(Resource, "Buffer now contains %i insts.\n", instList.size());
+}
+
+void
+InstBuffer::insert(DynInstPtr inst)
+{
+ instList.push_back(inst);
+}
+
+void
+InstBuffer::remove(DynInstPtr inst)
+{
+ std::list<DynInstPtr>::iterator list_it = instList.begin();
+ std::list<DynInstPtr>::iterator list_end = instList.end();
+
+ while (list_it != list_end) {
+ if((*list_it) == inst) {
+ instList.erase(list_it);
+ break;
+ }
+ list_it++;
+ }
+}
+
+void
+InstBuffer::pop()
+{ instList.pop_front(); }
+
+ThePipeline::DynInstPtr
+InstBuffer::top()
+{ return instList.front(); }
+
+void
+InstBuffer::squash(InstSeqNum squash_seq_num, unsigned tid)
+{
+ list<DynInstPtr>::iterator list_it = instList.begin();
+ list<DynInstPtr>::iterator list_end = instList.end();
+ queue<list<DynInstPtr>::iterator> remove_list;
+
+ // Collect All Instructions to be Removed in Remove List
+ while (list_it != list_end) {
+ if((*list_it)->seqNum > squash_seq_num) {
+ DPRINTF(Resource, "[tid:%i]: Squashing [sn:%i] in resource.\n",
+ tid, (*list_it)->seqNum);
+ (*list_it)->setSquashed();
+ remove_list.push(list_it);
+ }
+
+ list_it++;
+ }
+
+ // Removed Instructions from InstList & Clear Remove List
+ while (!remove_list.empty()) {
+ instList.erase(remove_list.front());
+ remove_list.pop();
+ }
+
+ Resource::squash(squash_seq_num, tid);
+}
diff --git a/src/cpu/inorder/resources/inst_buffer_new.hh b/src/cpu/inorder/resources/inst_buffer_new.hh
new file mode 100644
index 000000000..e374fa109
--- /dev/null
+++ b/src/cpu/inorder/resources/inst_buffer_new.hh
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_INST_BUFF_UNIT_HH__
+#define __CPU_INORDER_INST_BUFF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class InstBuffer : public Resource {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ enum Command {
+ InsertInst,
+ InsertAddr,
+ RemoveInst,
+ RemoveAddr
+ };
+
+ public:
+ InstBuffer(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~InstBuffer() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num);
+
+ virtual void execute(int slot_num);
+
+ virtual void insert(DynInstPtr inst);
+
+ virtual void remove(DynInstPtr inst);
+
+ virtual void pop();
+
+ virtual DynInstPtr top();
+
+ virtual void squash(InstSeqNum squash_seq_num, unsigned tid);
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+struct InstBufferEntry : public ThePipeline::ScheduleEntry {
+ InstBufferEntry(int stage_num, int res_num, InstBuffer::Command _cmd) :
+ ScheduleEntry(stage_num, res_num), cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+class InstBufferRequest : public ResourceRequest {
+ public:
+ typedef InOrderDynInst::DynInstPtr DynInstPtr;
+
+ public:
+ InstBufferRequest(InstBuffer *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ InstBuffer::Command _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num),
+ cmd(_cmd)
+ { }
+
+ InstBuffer::Command cmd;
+};
+
+
+#endif //__CPU_INORDER_INST_BUFF_UNIT_HH__
diff --git a/src/base/stats/statdb.hh b/src/cpu/inorder/resources/mem_dep_unit.hh
index a5b9be7eb..0bd850c5c 100644
--- a/src/base/stats/statdb.hh
+++ b/src/cpu/inorder/resources/mem_dep_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2007 MIPS Technologies, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,46 +25,42 @@
* (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
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __BASE_STATS_STATDB_HH__
-#define __BASE_STATS_STATDB_HH__
+#ifndef __CPU_INORDER_GRAD_UNIT_HH__
+#define __CPU_INORDER_GRAD_UNIT_HH__
-#include <iosfwd>
+#include <vector>
#include <list>
-#include <map>
#include <string>
-class Python;
-
-namespace Stats {
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
-class StatData;
+class MemDepUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
-namespace Database {
+ public:
+ MemDepUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu);
+ virtual ~MemDepUnit() {}
-typedef std::map<void *, StatData *> stat_map_t;
-typedef std::list<StatData *> stat_list_t;
+ virtual void execute(int slot_num);
-// We wrap the database in a struct to make sure it is built in time.
-struct TheDatabase
-{
- stat_map_t map;
- stat_list_t stats;
-};
+ protected:
+ Tick lastCycleGrad;
+ int numCycleGrad;
-TheDatabase &db();
-inline stat_map_t &map() { return db().map; }
-inline stat_list_t &stats() { return db().stats; }
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
-StatData *find(void *stat);
-void regStat(void *stat, StatData *data);
-void regPrint(void *stat);
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
-inline std::string name() { return "Statistics Database"; }
-
-/* namespace Database */ }
-/* namespace Stats */ }
+ /** @todo: Add Resource Stats Here */
+};
-#endif // __BASE_STATS_STATDB_HH__
+#endif //__CPU_INORDER_GRAD_UNIT_HH__
diff --git a/src/cpu/inorder/resources/mult_div_unit.cc b/src/cpu/inorder/resources/mult_div_unit.cc
new file mode 100644
index 000000000..b31d60ad5
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.cc
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "cpu/inorder/resources/mult_div_unit.hh"
+#include "cpu/inorder/resource_pool.hh"
+#include "cpu/inorder/cpu.hh"
+#include "cpu/op_class.hh"
+
+using namespace std;
+using namespace ThePipeline;
+
+MultDivUnit::MultDivUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ multRepeatRate(params->multRepeatRate), multLatency(params->multLatency),
+ div8RepeatRate(params->div8RepeatRate), div8Latency(params->div8Latency),
+ div16RepeatRate(params->div16RepeatRate), div16Latency(params->div16Latency),
+ div24RepeatRate(params->div24RepeatRate), div24Latency(params->div24Latency),
+ div32RepeatRate(params->div32RepeatRate), div32Latency(params->div32Latency),
+ lastMDUCycle(0)
+{ }
+
+void
+MultDivUnit::regStats()
+{
+ multInstReqsProcessed
+ .name(name() + ".multInstReqsProcessed")
+ .desc("Number of Multiply Requests Processed.");
+
+ divInstReqsProcessed
+ .name(name() + ".divInstReqsProcessed")
+ .desc("Number of Divide Requests Processed.");
+
+ Resource::regStats();
+}
+
+void
+MultDivUnit::init()
+{
+ // Set Up Resource Events to Appropriate Resource BandWidth
+ resourceEvent = new MDUEvent[width];
+
+ initSlots();
+}
+
+int
+MultDivUnit::findSlot(DynInstPtr inst)
+{
+ DPRINTF(InOrderMDU, "Finding slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
+ inst->seqNum, slotsAvail(), slotsInUse());
+
+ return Resource::findSlot(inst);
+}
+
+void
+MultDivUnit::freeSlot(int slot_idx)
+{
+ DPRINTF(InOrderMDU, "Freeing slot for inst:%i\n | slots-free:%i | slots-used:%i\n",
+ reqMap[slot_idx]->getInst()->seqNum, slotsAvail(), slotsInUse());
+
+ Resource::freeSlot(slot_idx);
+}
+
+
+int
+MultDivUnit::getSlot(DynInstPtr inst)
+{
+ // If MDU already has instruction, return current slot.
+ int slot_num = findSlot(inst);
+
+ // If we have this instruction's request already then return
+ if (slot_num != -1 &&
+ inst->resSched.top()->cmd == reqMap[slot_num]->cmd)
+ return slot_num;
+
+ unsigned repeat_rate = 0;
+
+ /** Enforce MDU dependencies after a multiply is seen last */
+ if (lastOpType == IntMultOp) {
+ repeat_rate = multRepeatRate;
+ }
+
+ /** Enforce dependencies after a divide is seen last */
+ if (lastOpType == IntDivOp) {
+ switch (lastDivSize) {
+ case 8:
+ repeat_rate = div8RepeatRate;
+ break;
+
+ case 16:
+ repeat_rate = div16RepeatRate;
+ break;
+
+ case 24:
+ repeat_rate = div24RepeatRate;
+ break;
+
+ case 32:
+ repeat_rate = div32RepeatRate;
+ break;
+ }
+ }
+
+ if (lastMDUCycle + repeat_rate > curTick) {
+ DPRINTF(InOrderMDU, "MDU not ready to process another inst. until %i, denying request.\n",
+ lastMDUCycle + repeat_rate);
+ return -1;
+ } else {
+ int rval = Resource::getSlot(inst);
+ DPRINTF(InOrderMDU, "MDU request should pass: %i.\n",
+ rval);
+
+ if (rval != -1) {
+ lastMDUCycle = curTick;
+ lastOpType = inst->opClass();
+ lastInstName = inst->staticInst->getName();
+ }
+
+ return rval;
+ }
+}
+
+int
+MultDivUnit::getDivOpSize(DynInstPtr inst)
+{
+ // Get RT Register from instruction (index #1)
+ uint32_t div_op = inst->readIntSrc(1);
+
+ if (div_op <= 0xFF) {
+ return 8;
+ } else if (div_op <= 0xFFFF) {
+ return 16;
+ } else if (div_op <= 0xFFFFFF) {
+ return 24;
+ } else {
+ return 32;
+ }
+}
+
+void
+MultDivUnit::execute(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+
+ //int tid = inst->readTid();
+ //int seq_num = inst->seqNum;
+
+ switch (mult_div_req->cmd)
+ {
+ case StartMultDiv:
+ DPRINTF(InOrderMDU, "Start MDU called ...\n");
+
+ if (inst->opClass() == IntMultOp) {
+ scheduleEvent(slot_num, multLatency);
+ multInstReqsProcessed++;
+ } else if (inst->opClass() == IntDivOp) {
+ int op_size = getDivOpSize(inst);
+
+ switch (op_size)
+ {
+ case 8:
+ scheduleEvent(slot_num, div8Latency);
+ break;
+
+ case 16:
+ scheduleEvent(slot_num, div16Latency);
+ break;
+
+ case 24:
+ scheduleEvent(slot_num, div24Latency);
+ break;
+
+ case 32:
+ scheduleEvent(slot_num, div32Latency);
+ break;
+ }
+
+ lastDivSize = op_size;
+
+ divInstReqsProcessed++;
+ }
+
+ // Allow to pass through to next stage while
+ // event processes
+ mult_div_req->setCompleted();
+ break;
+
+ case MultDiv:
+ DPRINTF(InOrderMDU, "Execute MDU called ...\n");
+ exeMulDiv(slot_num);
+ mult_div_req->done();
+ break;
+
+
+ case EndMultDiv:
+ //@TODO: Why not allow high-latency requests to sleep
+ // within stage until event wakes up????
+ // Seems wasteful to continually check to see if
+ // this is done when we have a event in parallel
+ // counting down the time
+ {
+ DPRINTF(InOrderMDU, "End MDU called ...\n");
+ if (mult_div_req->getInst()->isExecuted())
+ mult_div_req->done();
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+void
+MultDivUnit::exeMulDiv(int slot_num)
+{
+ ResourceRequest* mult_div_req = reqMap[slot_num];
+ DynInstPtr inst = reqMap[slot_num]->inst;
+ Fault fault = reqMap[slot_num]->fault;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+
+ fault = inst->execute();
+
+ if (fault == NoFault) {
+ inst->setExecuted();
+ mult_div_req->setCompleted();
+
+ DPRINTF(Resource, "[tid:%i]: The result of execution is 0x%x.\n",
+ inst->readTid(), inst->readIntResult(0));
+ } else {
+ warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ cpu->trap(fault, tid);
+ }
+}
+
+
+MDUEvent::MDUEvent()
+ : ResourceEvent()
+{ }
+
+void
+MDUEvent::process()
+{
+ MultDivUnit* mdu_res = reinterpret_cast<MultDivUnit*>(resource);
+
+ mdu_res->exeMulDiv(slotIdx);
+
+ ResourceRequest* mult_div_req = resource->reqMap[slotIdx];
+
+ mult_div_req->done();
+}
+
+
diff --git a/src/cpu/inorder/resources/mult_div_unit.hh b/src/cpu/inorder/resources/mult_div_unit.hh
new file mode 100644
index 000000000..76180714c
--- /dev/null
+++ b/src/cpu/inorder/resources/mult_div_unit.hh
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_MULT_DIV_UNIT_HH__
+#define __CPU_INORDER_MULT_DIV_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/op_class.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+
+class MDUEvent;
+
+class MultDivUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ StartMultDiv,
+ EndMultDiv,
+ MultDiv
+ };
+
+ public:
+ MultDivUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~MultDivUnit() {}
+
+ public:
+ /** Override default Resource getSlot(). Will only getSlot if
+ * valid mult/div sequence is being maintained
+ */
+ virtual int getSlot(DynInstPtr inst);
+
+ virtual int findSlot(DynInstPtr inst);
+
+ virtual void freeSlot(int slot_idx);
+
+ virtual void init();
+
+ /** Get Operand Size For A Division Operation */
+ int getDivOpSize(DynInstPtr inst);
+
+ /** Override default Resource execute */
+ virtual void execute(int slot_num);
+
+ void exeMulDiv(int slot_num);
+
+ /** Register extra resource stats */
+ virtual void regStats();
+
+ protected:
+ /** Latency & Repeat Rate for Multiply Insts */
+ unsigned multRepeatRate;
+ unsigned multLatency;
+
+ /** Latency & Repeat Rate for 8-bit Divide Insts */
+ unsigned div8RepeatRate;
+ unsigned div8Latency;
+
+ /** Latency & Repeat Rate for 16-bit Divide Insts */
+ unsigned div16RepeatRate;
+ unsigned div16Latency;
+
+ /** Latency & Repeat Rate for 24-bit Divide Insts */
+ unsigned div24RepeatRate;
+ unsigned div24Latency;
+
+ /** Latency & Repeat Rate for 32-bit Divide Insts */
+ unsigned div32RepeatRate;
+ unsigned div32Latency;
+
+ /** Last cycle that MDU was used */
+ Tick lastMDUCycle;
+
+ /** Last type of instruction MDU started processing */
+ OpClass lastOpType;
+
+ /** Last Division Operand of instruction MDU was processing */
+ uint32_t lastDivSize;
+
+ /** Last instruction name the MDU used */
+ std::string lastInstName;
+
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar multInstReqsProcessed;
+
+ /** Number of Instruction Requests the Resource Processes */
+ Stats::Scalar divInstReqsProcessed;
+
+ MDUEvent *mduEvent;
+};
+
+class MDUEvent : public ResourceEvent
+{
+ public:
+ MDUEvent();
+ virtual ~MDUEvent() { }
+
+
+ virtual void process();
+};
+
+
+#endif //__CPU_INORDER_MULT_DIV_UNIT_HH__
diff --git a/src/arch/mips/syscallreturn.hh b/src/cpu/inorder/resources/resource_list.hh
index 24a40ddcc..cbe2ad8c3 100644
--- a/src/arch/mips/syscallreturn.hh
+++ b/src/cpu/inorder/resources/resource_list.hh
@@ -25,31 +25,23 @@
* (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
- * Korey Sewell
+ * Authors: Korey Sewell
+ *
*/
-#ifndef __ARCH_MIPS_SYSCALLRETURN_HH__
-#define __ARCH_MIPS_SYSCALLRETURN_HH__
-
-#include "sim/syscallreturn.hh"
-#include "cpu/thread_context.hh"
+#ifndef CPU_INORDER_RESOURCE_LIST_HH
+#define CPU_INORDER_RESOURCE_LIST_HH
-namespace MipsISA
-{
- static inline void setSyscallReturn(SyscallReturn return_value,
- ThreadContext *tc)
- {
- if (return_value.successful()) {
- // no error
- tc->setIntReg(SyscallSuccessReg, 0);
- tc->setIntReg(ReturnValueReg1, return_value.value());
- } else {
- // got an error, return details
- tc->setIntReg(SyscallSuccessReg, (IntReg) -1);
- tc->setIntReg(ReturnValueReg1, -return_value.value());
- }
- }
-}
+#include "cpu/inorder/resources/cache_unit.hh"
+#include "cpu/inorder/resources/execution_unit.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/resources/decode_unit.hh"
+#include "cpu/inorder/resources/graduation_unit.hh"
+#include "cpu/inorder/resources/tlb_unit.hh"
+#include "cpu/inorder/resources/fetch_seq_unit.hh"
+#include "cpu/inorder/resources/branch_predictor.hh"
+#include "cpu/inorder/resources/agen_unit.hh"
+#include "cpu/inorder/resources/mult_div_unit.hh"
#endif
diff --git a/src/cpu/inorder/resources/tlb_unit.cc b/src/cpu/inorder/resources/tlb_unit.cc
new file mode 100644
index 000000000..8f8ba144e
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.cc
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/tlb_unit.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+TLBUnit::TLBUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : InstBuffer(res_name, res_id, res_width, res_latency, _cpu, params)
+{
+ for (int i=0; i < MaxThreads; i++) {
+ tlbBlocked[i] = false;
+ }
+}
+
+void
+TLBUnit::init()
+{
+ resourceEvent = new TLBUnitEvent[width];
+
+ initSlots();
+}
+
+int
+TLBUnit::getSlot(DynInstPtr inst)
+{
+ if (tlbBlocked[inst->threadNumber]) {
+ return -1;
+ } else {
+ return Resource::getSlot(inst);
+ }
+}
+
+ResourceRequest*
+TLBUnit::getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd)
+{
+ return new TLBUnitRequest(this, _inst, stage_num, res_idx, slot_num,
+ cmd);
+}
+
+void
+TLBUnit::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ TLBUnitRequest* tlb_req = dynamic_cast<TLBUnitRequest*>(reqMap[slot_idx]);
+ assert(tlb_req);
+
+ DynInstPtr inst = tlb_req->inst;
+ int tid, seq_num, stage_num;
+
+ tid = inst->readTid();
+ seq_num = inst->seqNum;
+ stage_num = tlb_req->getStageNum();
+
+ tlb_req->fault = NoFault;
+
+ switch (tlb_req->cmd)
+ {
+ case FetchLookup:
+ {
+ tlb_req->fault =
+ this->cpu->itb->translateAtomic(tlb_req->memReq,
+ cpu->thread[tid]->getTC());
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
+ "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
+ tlb_req->memReq->getVaddr(), seq_num);
+ //insert(inst);
+ cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
+ tlbBlocked[tid] = true;
+ scheduleEvent(slot_idx, 1);
+
+ // @TODO: SHOULDNT BREAK EXECUTION at misspeculated PC Fault
+ // Let CPU handle the fault
+ cpu->trap(tlb_req->fault, tid);
+ } else {
+ DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
+ "to phys. addr:%08p.\n", tid, seq_num,
+ tlb_req->memReq->getVaddr(),
+ tlb_req->memReq->getPaddr());
+ tlb_req->done();
+ }
+ }
+ break;
+
+ case DataLookup:
+ {
+ DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i]: Attempting to translate %08p.\n",
+ tid, seq_num, tlb_req->memReq->getVaddr());
+
+ tlb_req->fault =
+ this->cpu->itb->translateAtomic(tlb_req->memReq,
+ cpu->thread[tid]->getTC());
+
+ if (tlb_req->fault != NoFault) {
+ DPRINTF(InOrderTLB, "[tid:%i]: %s encountered while translating "
+ "addr:%08p for [sn:%i].\n", tid, tlb_req->fault->name(),
+ tlb_req->memReq->getVaddr(), seq_num);
+ //insert(inst);
+ cpu->pipelineStage[stage_num]->setResStall(tlb_req, tid);
+ tlbBlocked[tid] = true;
+ scheduleEvent(slot_idx, 1);
+
+ // Let CPU handle the fault
+ cpu->trap(tlb_req->fault, tid);
+ } else {
+ DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
+ "to phys. addr:%08p.\n", tid, seq_num,
+ tlb_req->memReq->getVaddr(),
+ tlb_req->memReq->getPaddr());
+ tlb_req->done();
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+}
+
+TLBUnitEvent::TLBUnitEvent()
+ : ResourceEvent()
+{ }
+
+void
+TLBUnitEvent::process()
+{
+ DynInstPtr inst = resource->reqMap[slotIdx]->inst;
+ int stage_num = resource->reqMap[slotIdx]->getStageNum();
+ int tid = inst->threadNumber;
+
+ DPRINTF(InOrderTLB, "Waking up from TLB Miss caused by [sn:%i].\n",
+ inst->seqNum);
+
+ TLBUnit* tlb_res = dynamic_cast<TLBUnit*>(resource);
+ assert(tlb_res);
+
+ tlb_res->tlbBlocked[tid] = false;
+
+ tlb_res->cpu->pipelineStage[stage_num]->unsetResStall(resource->reqMap[slotIdx], tid);
+
+ // Effectively NOP the instruction but still allow it
+ // to commit
+ //while (!inst->resSched.empty() &&
+ // inst->resSched.top()->stageNum != ThePipeline::NumStages - 1) {
+ //inst->resSched.pop();
+ //}
+}
diff --git a/src/cpu/inorder/resources/tlb_unit.hh b/src/cpu/inorder/resources/tlb_unit.hh
new file mode 100644
index 000000000..c7fee6030
--- /dev/null
+++ b/src/cpu/inorder/resources/tlb_unit.hh
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_TLB_UNIT_HH__
+#define __CPU_INORDER_TLB_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/inorder/resources/inst_buffer.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/cpu.hh"
+
+class TLBUnit : public InstBuffer {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum TLBCommand {
+ FetchLookup,
+ DataLookup
+ };
+
+ public:
+ TLBUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~TLBUnit() {}
+
+ void init();
+
+ int getSlot(DynInstPtr inst);
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual void execute(int slot_num);
+
+ bool tlbBlocked[ThePipeline::MaxThreads];
+
+ protected:
+ /** List of instructions this resource is currently
+ * processing.
+ */
+ std::list<DynInstPtr> instList;
+
+ /** @todo: Add Resource Stats Here */
+
+};
+
+class TLBUnitEvent : public ResourceEvent {
+ public:
+ /** Constructs a resource event. */
+ TLBUnitEvent();
+ virtual ~TLBUnitEvent() {}
+
+ /** Processes a resource event. */
+ virtual void process();
+};
+
+class TLBUnitRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ TLBUnitRequest(TLBUnit *res, DynInstPtr inst, int stage_num, int res_idx, int slot_num,
+ unsigned _cmd)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, _cmd)
+ {
+ Addr aligned_addr;
+ int req_size;
+ unsigned flags;
+
+ if (_cmd == TLBUnit::FetchLookup) {
+ aligned_addr = inst->getMemAddr();
+ req_size = sizeof(MachInst);
+ flags = 0;
+ } else {
+ aligned_addr = inst->getMemAddr();;
+ req_size = inst->getMemAccSize();
+ flags = inst->getMemFlags();
+ }
+
+ // @TODO: Add Vaddr & Paddr functions
+ inst->memReq = new Request(inst->readTid(), aligned_addr, req_size,
+ flags, inst->readPC(), res->cpu->readCpuId(), inst->readTid());
+
+ memReq = inst->memReq;
+ }
+
+ RequestPtr memReq;
+};
+
+
+#endif //__CPU_INORDER_TLB_UNIT_HH__
diff --git a/src/cpu/inorder/resources/use_def.cc b/src/cpu/inorder/resources/use_def.cc
new file mode 100644
index 000000000..a9281a18c
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.cc
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 <vector>
+#include <list>
+#include "arch/isa_traits.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/resources/use_def.hh"
+#include "cpu/inorder/cpu.hh"
+
+using namespace std;
+using namespace TheISA;
+using namespace ThePipeline;
+
+UseDefUnit::UseDefUnit(string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params)
+ : Resource(res_name, res_id, res_width, res_latency, _cpu),
+ maxSeqNum((InstSeqNum)-1)
+{
+ for (int tid = 0; tid < ThePipeline::MaxThreads; tid++) {
+ nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
+ nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
+
+ outReadSeqNum[tid] = maxSeqNum;
+ outWriteSeqNum[tid] = maxSeqNum;
+
+ regDepMap[tid] = &cpu->archRegDepMap[tid];
+ }
+}
+
+ResReqPtr
+UseDefUnit::getRequest(DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd)
+{
+ return new UseDefRequest(this, inst, stage_num, id, slot_num, cmd,
+ inst->resSched.top()->idx);
+}
+
+
+ResReqPtr
+UseDefUnit::findRequest(DynInstPtr inst)
+{
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>((*map_it).second);
+ assert(ud_req);
+
+ if (ud_req &&
+ ud_req->getInst() == inst &&
+ ud_req->cmd == inst->resSched.top()->cmd &&
+ ud_req->useDefIdx == inst->resSched.top()->idx) {
+ return ud_req;
+ }
+ map_it++;
+ }
+
+ return NULL;
+}
+
+void
+UseDefUnit::execute(int slot_idx)
+{
+ // After this is working, change this to a reinterpret cast
+ // for performance considerations
+ UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqMap[slot_idx]);
+ assert(ud_req);
+
+ DynInstPtr inst = ud_req->inst;
+ int tid = inst->readTid();
+ int seq_num = inst->seqNum;
+ int ud_idx = ud_req->useDefIdx;
+
+ // If there is a non-speculative instruction
+ // in the pipeline then stall instructions here
+ if (*nonSpecInstActive[tid] == true &&
+ seq_num > *nonSpecSeqNum[tid]) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: [sn:%i] cannot execute because there is "
+ "non-speculative instruction [sn:%i] has not graduated.\n",
+ tid, seq_num, *nonSpecSeqNum[tid]);
+ return;
+ } else if (inst->isNonSpeculative()) {
+ *nonSpecInstActive[tid] = true;
+ *nonSpecSeqNum[tid] = seq_num;
+ }
+
+ switch (ud_req->cmd)
+ {
+ case ReadSrcReg:
+ {
+ int reg_idx = inst->_srcRegIdx[ud_idx];
+
+ DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to read source register idx %i.\n",
+ tid, ud_idx);
+
+ // Ask register dependency map if it is OK to read from Arch. Reg. File
+ if (regDepMap[tid]->canRead(reg_idx, inst)) {
+ // Read From Register File
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Reading Int Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx,
+ cpu->readIntReg(reg_idx,inst->readTid()));
+ } else if (reg_idx <= Ctrl_Base_DepTag) {
+ reg_idx -= FP_Base_DepTag;
+ DPRINTF(InOrderUseDef, "[tid:%i]: Reading Float Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx, // Always Read FloatRegBits For Now
+ cpu->readFloatRegBits(reg_idx, inst->readTid()));
+ } else {
+ reg_idx -= Ctrl_Base_DepTag;
+ DPRINTF(InOrderUseDef, "[tid:%i]: Reading Misc Reg %i from Register File.\n",
+ tid, reg_idx);
+ inst->setIntSrc(ud_idx,
+ cpu->readMiscReg(reg_idx, inst->readTid()));
+ }
+
+ outReadSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum[tid]);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to write\n",
+ tid, outReadSeqNum[tid]);
+ }
+
+ } else {
+ DynInstPtr forward_inst = regDepMap[tid]->canForward(reg_idx, ud_idx, inst);
+
+ if (forward_inst) {
+
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ int dest_reg_idx = forward_inst->getDestIdxNum(reg_idx);
+
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readIntResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
+ } else if (reg_idx <= Ctrl_Base_DepTag) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readFloatResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setFloatSrc(ud_idx, forward_inst->readFloatResult(dest_reg_idx));
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Forwarding dest. reg value 0x%x from "
+ "[sn:%i] to [sn:%i] source #%i.\n",
+ tid, forward_inst->readIntResult(dest_reg_idx) ,
+ forward_inst->seqNum, inst->seqNum, ud_idx);
+ inst->setIntSrc(ud_idx, forward_inst->readIntResult(dest_reg_idx));
+ }
+
+ outReadSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Unable to read because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum[tid]);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to forward\n",
+ tid, outReadSeqNum[tid]);
+ }
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Source register idx: %i is not ready to read.\n",
+ tid, reg_idx);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to read register (idx=%i)\n",
+ tid, reg_idx);
+ outReadSeqNum[tid] = inst->seqNum;
+ }
+ }
+ }
+ break;
+
+ case WriteDestReg:
+ {
+ int reg_idx = inst->_destRegIdx[ud_idx];
+
+ if (regDepMap[tid]->canWrite(reg_idx, inst)) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Attempting to write to Register File.\n",
+ tid);
+
+ if (inst->seqNum <= outReadSeqNum[tid]) {
+ if (reg_idx <= FP_Base_DepTag) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Writing 0x%x to register idx %i.\n",
+ tid, inst->readIntResult(ud_idx), reg_idx);
+
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ cpu->setIntReg(reg_idx,
+ inst->readIntResult(ud_idx),
+ inst->readTid());
+ } else if(reg_idx <= Ctrl_Base_DepTag) {
+
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ reg_idx -= FP_Base_DepTag;
+
+ cpu->setFloatReg(reg_idx, // Check for FloatRegBits Here
+ inst->readFloatResult(ud_idx),
+ inst->readTid());
+ } else {
+ // Remove Dependencies
+ regDepMap[tid]->removeFront(reg_idx, inst);
+
+ reg_idx -= Ctrl_Base_DepTag;
+ cpu->setMiscReg(reg_idx,
+ inst->readIntResult(ud_idx),
+ inst->readTid());
+ }
+
+ outWriteSeqNum[tid] = maxSeqNum;
+
+ ud_req->done();
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Unable to write because of [sn:%i] hasnt read it's"
+ " registers yet.\n", tid, outReadSeqNum);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting for [sn:%i] to read\n",
+ tid, outReadSeqNum);
+ }
+ } else {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Dest. register idx: %i is not ready to write.\n",
+ tid, reg_idx);
+ DPRINTF(InOrderStall, "STALL: [tid:%i]: waiting to write register (idx=%i)\n",
+ tid, reg_idx);
+ outWriteSeqNum[tid] = inst->seqNum;
+ }
+ }
+ break;
+
+ default:
+ fatal("Unrecognized command to %s", resName);
+ }
+
+}
+
+void
+UseDefUnit::squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid)
+{
+ DPRINTF(InOrderUseDef, "[tid:%i]: Updating Due To Squash After [sn:%i].\n",
+ tid, squash_seq_num);
+
+ std::vector<int> slot_remove_list;
+
+ map<int, ResReqPtr>::iterator map_it = reqMap.begin();
+ map<int, ResReqPtr>::iterator map_end = reqMap.end();
+
+ while (map_it != map_end) {
+ ResReqPtr req_ptr = (*map_it).second;
+
+ if (req_ptr &&
+ req_ptr->getInst()->readTid() == tid &&
+ req_ptr->getInst()->seqNum > squash_seq_num) {
+
+ DPRINTF(InOrderUseDef, "[tid:%i]: Squashing [sn:%i].\n",
+ req_ptr->getInst()->readTid(),
+ req_ptr->getInst()->seqNum);
+
+ regDepMap[tid]->remove(req_ptr->getInst());
+
+ int req_slot_num = req_ptr->getSlot();
+
+ if (latency > 0)
+ unscheduleEvent(req_slot_num);
+
+ // Mark slot for removal from resource
+ slot_remove_list.push_back(req_ptr->getSlot());
+ }
+
+ map_it++;
+ }
+
+ // Now Delete Slot Entry from Req. Map
+ for (int i = 0; i < slot_remove_list.size(); i++) {
+ freeSlot(slot_remove_list[i]);
+ }
+
+ if (outReadSeqNum[tid] >= squash_seq_num) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Read Seq Num Reset.\n", tid);
+ outReadSeqNum[tid] = maxSeqNum;
+ } else if (outReadSeqNum[tid] != maxSeqNum) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Read Seq Num %i\n",
+ tid, outReadSeqNum[tid]);
+ }
+
+ if (outWriteSeqNum[tid] >= squash_seq_num) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: Outstanding Write Seq Num Reset.\n", tid);
+ outWriteSeqNum[tid] = maxSeqNum;
+ } else if (outWriteSeqNum[tid] != maxSeqNum) {
+ DPRINTF(InOrderUseDef, "[tid:%i]: No need to reset Outstanding Write Seq Num %i\n",
+ tid, outWriteSeqNum[tid]);
+ }
+}
diff --git a/src/cpu/inorder/resources/use_def.hh b/src/cpu/inorder/resources/use_def.hh
new file mode 100644
index 000000000..238591117
--- /dev/null
+++ b/src/cpu/inorder/resources/use_def.hh
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_USE_DEF_UNIT_HH__
+#define __CPU_INORDER_USE_DEF_UNIT_HH__
+
+#include <vector>
+#include <list>
+#include <string>
+
+#include "cpu/func_unit.hh"
+#include "cpu/inorder/first_stage.hh"
+#include "cpu/inorder/resource.hh"
+#include "cpu/inorder/inorder_dyn_inst.hh"
+#include "cpu/inorder/pipeline_traits.hh"
+#include "cpu/inorder/reg_dep_map.hh"
+
+class UseDefUnit : public Resource {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ enum Command {
+ ReadSrcReg,
+ WriteDestReg
+ };
+
+ public:
+ UseDefUnit(std::string res_name, int res_id, int res_width,
+ int res_latency, InOrderCPU *_cpu, ThePipeline::Params *params);
+ virtual ~UseDefUnit() {}
+
+ virtual ResourceRequest* getRequest(DynInstPtr _inst, int stage_num,
+ int res_idx, int slot_num,
+ unsigned cmd);
+
+ virtual ResReqPtr findRequest(DynInstPtr inst);
+
+ virtual void execute(int slot_num);
+
+ virtual void squash(DynInstPtr inst, int stage_num, InstSeqNum squash_seq_num, unsigned tid);
+
+ const InstSeqNum maxSeqNum;
+
+ protected:
+ RegDepMap *regDepMap[ThePipeline::MaxThreads];
+
+ /** Outstanding Seq. Num. Trying to Read from Register File */
+ InstSeqNum outReadSeqNum[ThePipeline::MaxThreads];
+
+ InstSeqNum outWriteSeqNum[ThePipeline::MaxThreads];
+
+ bool *nonSpecInstActive[ThePipeline::MaxThreads];
+
+ InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
+
+ /** @todo: Add Resource Stats Here */
+
+ public:
+ class UseDefRequest : public ResourceRequest {
+ public:
+ typedef ThePipeline::DynInstPtr DynInstPtr;
+
+ public:
+ UseDefRequest(UseDefUnit *res, DynInstPtr inst, int stage_num, int res_idx,
+ int slot_num, unsigned cmd, int use_def_idx)
+ : ResourceRequest(res, inst, stage_num, res_idx, slot_num, cmd),
+ useDefIdx(use_def_idx)
+ { }
+
+ int useDefIdx;
+ };
+};
+
+#endif //__CPU_INORDER_USE_DEF_UNIT_HH__
diff --git a/src/cpu/inorder/thread_context.cc b/src/cpu/inorder/thread_context.cc
new file mode 100644
index 000000000..13f8ecdad
--- /dev/null
+++ b/src/cpu/inorder/thread_context.cc
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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/isa_traits.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/inorder/thread_context.hh"
+
+using namespace TheISA;
+
+void
+InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
+{
+ // some things should already be set up
+ assert(getProcessPtr() == old_context->getProcessPtr());
+
+ // copy over functional state
+ setStatus(old_context->status());
+ copyArchRegs(old_context);
+
+ thread->funcExeInst = old_context->readFuncExeInst();
+ old_context->setStatus(ThreadContext::Unallocated);
+ thread->inSyscall = false;
+ thread->trapPending = false;
+}
+
+void
+InOrderThreadContext::activate(int delay)
+{
+ DPRINTF(InOrderCPU, "Calling activate on Thread Context %d\n",
+ getThreadNum());
+
+ if (thread->status() == ThreadContext::Active)
+ return;
+
+ thread->setStatus(ThreadContext::Active);
+
+ cpu->activateContext(thread->readTid(), delay);
+}
+
+
+void
+InOrderThreadContext::suspend(int delay)
+{
+ DPRINTF(InOrderCPU, "Calling suspend on Thread Context %d\n",
+ getThreadNum());
+
+ if (thread->status() == ThreadContext::Suspended)
+ return;
+
+ thread->setStatus(ThreadContext::Suspended);
+ cpu->suspendContext(thread->readTid(), delay);
+}
+
+void
+InOrderThreadContext::deallocate(int delay)
+{
+ DPRINTF(InOrderCPU, "Calling deallocate on Thread Context %d\n",
+ getThreadNum());
+
+ if (thread->status() == ThreadContext::Unallocated)
+ return;
+
+ thread->setStatus(ThreadContext::Unallocated);
+ cpu->deallocateContext(thread->readTid(), delay);
+}
+
+void
+InOrderThreadContext::halt(int delay)
+{
+ DPRINTF(InOrderCPU, "Calling halt on Thread Context %d\n",
+ getThreadNum());
+
+ if (thread->status() == ThreadContext::Halted)
+ return;
+
+ thread->setStatus(ThreadContext::Halted);
+ cpu->haltContext(thread->readTid(), delay);
+}
+
+
+void
+InOrderThreadContext::regStats(const std::string &name)
+{
+#if FULL_SYSTEM
+ thread->kernelStats = new Kernel::Statistics(cpu->system);
+ thread->kernelStats->regStats(name + ".kern");
+#endif
+ ;
+}
+
+
+void
+InOrderThreadContext::serialize(std::ostream &os)
+{
+#if FULL_SYSTEM
+ if (thread->kernelStats)
+ thread->kernelStats->serialize(os);
+#endif
+ ;
+}
+
+
+void
+InOrderThreadContext::unserialize(Checkpoint *cp, const std::string &section)
+{
+#if FULL_SYSTEM
+ if (thread->kernelStats)
+ thread->kernelStats->unserialize(cp, section);
+#endif
+ ;
+}
+
+TheISA::MachInst
+InOrderThreadContext:: getInst()
+{
+ return thread->getInst();
+}
+
+
+void
+InOrderThreadContext::copyArchRegs(ThreadContext *src_tc)
+{
+ TheISA::copyRegs(src_tc, this);
+}
+
+
+void
+InOrderThreadContext::clearArchRegs()
+{}
+
+
+uint64_t
+InOrderThreadContext::readIntReg(int reg_idx)
+{
+ return cpu->readIntReg(reg_idx, thread->readTid());
+}
+
+FloatReg
+InOrderThreadContext::readFloatReg(int reg_idx, int width)
+{
+ return cpu->readFloatReg(reg_idx, thread->readTid(), width);
+}
+
+FloatReg
+InOrderThreadContext::readFloatReg(int reg_idx)
+{
+ return cpu->readFloatReg(reg_idx, thread->readTid());
+}
+
+FloatRegBits
+InOrderThreadContext::readFloatRegBits(int reg_idx, int width)
+{
+ return cpu->readFloatRegBits(reg_idx, thread->readTid(), width);
+}
+
+FloatRegBits
+InOrderThreadContext::readFloatRegBits(int reg_idx)
+{
+ return cpu->readFloatRegBits(reg_idx, thread->readTid());
+}
+
+uint64_t
+InOrderThreadContext::readRegOtherThread(int reg_idx, unsigned tid)
+{
+ return cpu->readRegOtherThread(reg_idx, tid);
+}
+
+void
+InOrderThreadContext::setIntReg(int reg_idx, uint64_t val)
+{
+ cpu->setIntReg(reg_idx, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ cpu->setFloatReg(reg_idx, val, thread->readTid(), width);
+}
+
+void
+InOrderThreadContext::setFloatReg(int reg_idx, FloatReg val)
+{
+ cpu->setFloatReg(reg_idx, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val,
+ int width)
+{
+ cpu->setFloatRegBits(reg_idx, val, thread->readTid(), width);
+}
+
+void
+InOrderThreadContext::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ cpu->setFloatRegBits(reg_idx, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid)
+{
+ cpu->setRegOtherThread(misc_reg, val, tid);
+}
+
+void
+InOrderThreadContext::setPC(uint64_t val)
+{
+ DPRINTF(InOrderCPU, "Setting PC to %08p\n", val);
+ cpu->setPC(val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setNextPC(uint64_t val)
+{
+ DPRINTF(InOrderCPU, "Setting NPC to %08p\n", val);
+ cpu->setNextPC(val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setNextNPC(uint64_t val)
+{
+ DPRINTF(InOrderCPU, "Setting NNPC to %08p\n", val);
+ cpu->setNextNPC(val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+{
+ cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
+}
+
+void
+InOrderThreadContext::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ cpu->setMiscReg(misc_reg, val, thread->readTid());
+}
diff --git a/src/cpu/inorder/thread_context.hh b/src/cpu/inorder/thread_context.hh
new file mode 100644
index 000000000..2fb2ed85f
--- /dev/null
+++ b/src/cpu/inorder/thread_context.hh
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2007 MIPS Technologies, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 __CPU_INORDER_THREAD_CONTEXT_HH__
+#define __CPU_INORDER_THREAD_CONTEXT_HH__
+
+#include "cpu/exetrace.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/inorder/thread_state.hh"
+#include "cpu/inorder/cpu.hh"
+
+class TranslatingPort;
+
+/**
+ * Derived ThreadContext class for use with the InOrderCPU. It
+ * provides the interface for any external objects to access a
+ * single thread's state and some general CPU state. Any time
+ * external objects try to update state through this interface,
+ * the CPU will create an event to squash all in-flight
+ * instructions in order to ensure state is maintained correctly.
+ * It must be defined specifically for the InOrderCPU because
+ * not all architectural state is located within the O3ThreadState
+ * (such as the commit PC, and registers), and specific actions
+ * must be taken when using this interface (such as squashing all
+ * in-flight instructions when doing a write to this interface).
+ */
+class InOrderThreadContext : public ThreadContext
+{
+ public:
+ InOrderThreadContext() { }
+
+ /** Pointer to the CPU. */
+ InOrderCPU *cpu;
+
+ /** Pointer to the thread state that this TC corrseponds to. */
+ InOrderThreadState *thread;
+
+
+ /** Returns a pointer to the ITB. */
+ TheISA::ITB *getITBPtr() { return cpu->itb; }
+
+ /** Returns a pointer to the DTB. */
+ TheISA::DTB *getDTBPtr() { return cpu->dtb; }
+
+ System *getSystemPtr() { return cpu->system; }
+
+ /** Returns a pointer to this CPU. */
+ virtual BaseCPU *getCpuPtr() { return cpu; }
+
+ /** Returns a pointer to this CPU. */
+ virtual std::string getCpuName() { return cpu->name(); }
+
+ /** Reads this CPU's ID. */
+ virtual int cpuId() { return cpu->cpuId(); }
+
+ virtual int contextId() { return thread->contextId(); }
+
+ virtual void setContextId(int id) { thread->setContextId(id); }
+
+ /** Returns this thread's ID number. */
+ virtual int threadId() { return thread->threadId(); }
+ virtual void setThreadId(int id) { return thread->setThreadId(id); }
+
+ virtual uint64_t readMicroPC()
+ { return 0; }
+
+ virtual void setMicroPC(uint64_t val) { };
+
+ virtual uint64_t readNextMicroPC()
+ { return 0; }
+
+ virtual void setNextMicroPC(uint64_t val) { };
+
+ virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
+
+ /** Returns a pointer to this thread's process. */
+ virtual Process *getProcessPtr() { return thread->getProcessPtr(); }
+
+ /** Returns this thread's status. */
+ virtual Status status() const { return thread->status(); }
+
+ /** Sets this thread's 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(int delay = 0);
+
+ /** Set the status to Unallocated. */
+ virtual void deallocate(int delay = 1);
+
+ /** Set the status to Halted. */
+ virtual void halt(int delay = 0);
+
+ /** Takes over execution of a thread from another CPU. */
+ virtual void takeOverFrom(ThreadContext *old_context);
+
+ /** Registers statistics associated with this TC. */
+ virtual void regStats(const std::string &name);
+
+ /** Serializes state. */
+ virtual void serialize(std::ostream &os);
+
+ /** Unserializes state. */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ /** Returns this thread's ID number. */
+ virtual int getThreadNum() { return thread->readTid(); }
+
+ /** Returns the instruction this thread is currently committing.
+ * Only used when an instruction faults.
+ */
+ virtual TheISA::MachInst getInst();
+
+ /** Copies the architectural registers from another TC into this TC. */
+ virtual void copyArchRegs(ThreadContext *src_tc);
+
+ /** Resets all architectural registers to 0. */
+ virtual void clearArchRegs();
+
+ /** Reads an integer register. */
+ virtual uint64_t readIntReg(int reg_idx);
+
+ virtual FloatReg readFloatReg(int reg_idx, int width);
+
+ virtual FloatReg readFloatReg(int reg_idx);
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx, int width);
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx);
+
+ virtual uint64_t readRegOtherThread(int misc_reg, unsigned tid);
+
+ /** Sets an integer register to a value. */
+ virtual void setIntReg(int reg_idx, uint64_t val);
+
+ virtual void setFloatReg(int reg_idx, FloatReg val, int width);
+
+ virtual void setFloatReg(int reg_idx, FloatReg val);
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val);
+
+ virtual void setRegOtherThread(int misc_reg, const MiscReg &val, unsigned tid);
+
+ /** Reads this thread's PC. */
+ virtual uint64_t readPC()
+ { return cpu->readPC(thread->readTid()); }
+
+ /** Sets this thread's PC. */
+ virtual void setPC(uint64_t val);
+
+ /** Reads this thread's next PC. */
+ virtual uint64_t readNextPC()
+ { return cpu->readNextPC(thread->readTid()); }
+
+ /** Sets this thread's next PC. */
+ virtual void setNextPC(uint64_t val);
+
+ virtual uint64_t readNextNPC()
+ { return cpu->readNextNPC(thread->readTid()); }
+
+ virtual void setNextNPC(uint64_t val);
+
+ /** Reads a miscellaneous register. */
+ virtual MiscReg readMiscRegNoEffect(int misc_reg)
+ { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); }
+
+ /** Reads a misc. register, including any side-effects the
+ * read might have as defined by the architecture. */
+ virtual MiscReg readMiscReg(int misc_reg)
+ { return cpu->readMiscReg(misc_reg, thread->readTid()); }
+
+ /** Sets a misc. register. */
+ virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
+
+ /** Sets a misc. register, including any side-effects the
+ * write might have as defined by the architecture. */
+ virtual void setMiscReg(int misc_reg, const MiscReg &val);
+
+ virtual void activateContext(int delay)
+ { cpu->activateContext(thread->readTid(), delay); }
+
+ virtual void deallocateContext()
+ { cpu->deallocateContext(thread->readTid()); }
+
+ /** Returns the number of consecutive store conditional failures. */
+ // @todo: Figure out where these store cond failures should go.
+ virtual unsigned readStCondFailures()
+ { return thread->storeCondFailures; }
+
+ /** Sets the number of consecutive store conditional failures. */
+ virtual void setStCondFailures(unsigned sc_failures)
+ { thread->storeCondFailures = sc_failures; }
+
+ // 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.
+ /** Checks if the thread is misspeculating. Because it is
+ * very difficult to determine if the thread is
+ * misspeculating, this is set as false. */
+ virtual bool misspeculating() { return false; }
+
+ /** Executes a syscall in SE mode. */
+ virtual void syscall(int64_t callnum)
+ { return cpu->syscall(callnum, thread->readTid()); }
+
+ /** Reads the funcExeInst counter. */
+ virtual Counter readFuncExeInst() { return thread->funcExeInst; }
+
+ virtual void changeRegFileContext(unsigned param,
+ unsigned val)
+ { panic("Not supported!"); }
+
+ /** This function exits the thread context in the CPU and returns
+ * 1 if the CPU has no more active threads (meaning it's OK to exit);
+ * Used in syscall-emulation mode when a thread executes the 'exit'
+ * syscall.
+ */
+ virtual int exit()
+ {
+ this->deallocate();
+
+ // If there are still threads executing in the system (for now
+ // this single cpu)
+ if (this->cpu->numActiveThreads() - 1 > 0)
+ return 0; // don't exit simulation
+ else
+ return 1; // exit simulation
+ }
+
+ virtual void setThreadRescheduleCondition(uint64_t cond)
+ {
+ this->deallocate();
+
+ this->setStatus(ThreadContext::Suspended);
+
+ activateContext(cond);
+ }
+};
+
+#endif
diff --git a/src/cpu/inorder/thread_state.hh b/src/cpu/inorder/thread_state.hh
new file mode 100644
index 000000000..eb4fe40b2
--- /dev/null
+++ b/src/cpu/inorder/thread_state.hh
@@ -0,0 +1,90 @@
+/*
+ * 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: Kevin Lim
+ */
+
+#ifndef __CPU_INORDER_THREAD_STATE_HH__
+#define __CPU_INORDER_THREAD_STATE_HH__
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/thread_state.hh"
+
+class Event;
+class FunctionalMemory;
+class Process;
+class InOrderCPU;
+
+/**
+ * Class that has various thread state, such as the status, the
+ * current instruction being processed, whether or not the thread has
+ * a trap pending or is being externally updated, the ThreadContext
+ * pointer, etc. It also handles anything related to a specific
+ * thread's process, such as syscalls and checking valid addresses.
+ */
+class InOrderThreadState : public ThreadState {
+ typedef ThreadContext::Status Status;
+
+ private:
+ /** Pointer to the CPU. */
+ InOrderCPU *cpu;
+
+ public:
+ /** Whether or not the thread is currently in syscall mode, and
+ * thus able to be externally updated without squashing.
+ */
+ bool inSyscall;
+
+ /** Whether or not the thread is currently waiting on a trap, and
+ * thus able to be externally updated without squashing.
+ */
+ bool trapPending;
+
+
+ InOrderThreadState(InOrderCPU *_cpu, int _thread_num, Process *_process, int _asid)
+ : ThreadState(reinterpret_cast<BaseCPU*>(_cpu), 0/*_thread_num*/, _process, 0/*_asid*/),
+ cpu(_cpu), inSyscall(0), trapPending(0)
+ { }
+
+ /** Handles the syscall. */
+ void syscall(int64_t callnum) { process->syscall(callnum, tc); }
+
+ /** Pointer to the ThreadContext of this thread. */
+ ThreadContext *tc;
+
+ /** Returns a pointer to the TC of this thread. */
+ ThreadContext *getTC() { return tc; }
+
+ int readTid() { return 0; }
+
+ /** Pointer to the last graduated instruction in the thread */
+ //DynInstPtr lastGradInst;
+};
+
+#endif // __CPU_INORDER_THREAD_STATE_HH__
diff --git a/src/cpu/inteltrace.hh b/src/cpu/inteltrace.hh
index 5d5bcda8e..e34658b58 100644
--- a/src/cpu/inteltrace.hh
+++ b/src/cpu/inteltrace.hh
@@ -47,8 +47,10 @@ class IntelTraceRecord : public InstRecord
{
public:
IntelTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
@@ -64,7 +66,8 @@ class IntelTrace : public InstTracer
IntelTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (!IsOn(ExecEnable))
return NULL;
@@ -76,7 +79,7 @@ class IntelTrace : public InstTracer
return NULL;
return new IntelTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
index c3a11ad91..de7f9245e 100644
--- a/src/cpu/intr_control.cc
+++ b/src/cpu/intr_control.cc
@@ -50,7 +50,7 @@ IntrControl::post(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->post_interrupt(int_num, index);
+ cpu->postInterrupt(int_num, index);
}
void
@@ -59,7 +59,7 @@ IntrControl::clear(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->clear_interrupt(int_num, index);
+ cpu->clearInterrupt(int_num, index);
}
IntrControl *
diff --git a/src/cpu/legiontrace.hh b/src/cpu/legiontrace.hh
index 97193ff1a..9962063e4 100644
--- a/src/cpu/legiontrace.hh
+++ b/src/cpu/legiontrace.hh
@@ -46,8 +46,10 @@ class LegionTraceRecord : public InstRecord
{
public:
LegionTraceRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc)
{
}
@@ -63,13 +65,14 @@ class LegionTrace : public InstTracer
LegionTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (tc->misspeculating())
return NULL;
return new LegionTraceRecord(when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
};
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
index 42889163a..3c57f85b7 100644
--- a/src/cpu/memtest/memtest.cc
+++ b/src/cpu/memtest/memtest.cc
@@ -152,7 +152,7 @@ MemTest::MemTest(const Params *p)
// set up counters
noResponseCycles = 0;
numReads = 0;
- tickEvent.schedule(0);
+ schedule(tickEvent, 0);
id = TESTER_ALLOCATOR++;
@@ -262,7 +262,7 @@ void
MemTest::tick()
{
if (!tickEvent.scheduled())
- tickEvent.schedule(curTick + ticks(1));
+ schedule(tickEvent, curTick + ticks(1));
if (++noResponseCycles >= 500000) {
cerr << name() << ": deadlocked at cycle " << curTick << endl;
@@ -279,7 +279,7 @@ MemTest::tick()
unsigned base = random() % 2;
uint64_t data = random();
unsigned access_size = random() % 4;
- unsigned cacheable = random() % 100;
+ bool uncacheable = (random() % 100) < percentUncacheable;
//If we aren't doing copies, use id as offset, and do a false sharing
//mem tester
@@ -290,17 +290,16 @@ MemTest::tick()
access_size = 0;
Request *req = new Request();
- uint32_t flags = 0;
+ Request::Flags flags;
Addr paddr;
- if (cacheable < percentUncacheable) {
- flags |= UNCACHEABLE;
+ if (uncacheable) {
+ flags.set(Request::UNCACHEABLE);
paddr = uncacheAddr + offset;
} else {
paddr = ((base) ? baseAddr1 : baseAddr2) + offset;
}
- bool probe = (random() % 100 < percentFunctional) && !(flags & UNCACHEABLE);
- //bool probe = false;
+ bool probe = (random() % 100 < percentFunctional) && !uncacheable;
paddr &= ~((1 << access_size) - 1);
req->setPhys(paddr, 1 << access_size, flags);
diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh
index ac2d0a058..907659f69 100644
--- a/src/cpu/memtest/memtest.hh
+++ b/src/cpu/memtest/memtest.hh
@@ -35,6 +35,7 @@
#include <set>
#include "base/statistics.hh"
+#include "base/fast_alloc.hh"
#include "params/MemTest.hh"
#include "sim/eventq.hh"
#include "sim/sim_exit.hh"
@@ -73,10 +74,10 @@ class MemTest : public MemObject
{
private:
MemTest *cpu;
+
public:
- TickEvent(MemTest *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c) {}
- void process() {cpu->tick();}
+ TickEvent(MemTest *c) : Event(CPU_Tick_Pri), cpu(c) {}
+ void process() { cpu->tick(); }
virtual const char *description() const { return "MemTest tick"; }
};
@@ -116,7 +117,7 @@ class MemTest : public MemObject
bool snoopRangeSent;
- class MemTestSenderState : public Packet::SenderState
+ class MemTestSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Constructor. */
@@ -132,10 +133,10 @@ class MemTest : public MemObject
bool accessRetry;
- unsigned size; // size of testing memory region
+ unsigned size; // size of testing memory region
- unsigned percentReads; // target percentage of read accesses
- unsigned percentFunctional; // target percentage of functional accesses
+ unsigned percentReads; // target percentage of read accesses
+ unsigned percentFunctional; // target percentage of functional accesses
unsigned percentUncacheable;
int id;
@@ -153,12 +154,12 @@ class MemTest : public MemObject
Addr traceBlockAddr;
- Addr baseAddr1; // fix this to option
- Addr baseAddr2; // fix this to option
+ Addr baseAddr1; // fix this to option
+ Addr baseAddr2; // fix this to option
Addr uncacheAddr;
- unsigned progressInterval; // frequency of progress reports
- Tick nextProgressMessage; // access # for next progress report
+ unsigned progressInterval; // frequency of progress reports
+ Tick nextProgressMessage; // access # for next progress report
unsigned percentSourceUnaligned;
unsigned percentDestUnaligned;
@@ -170,9 +171,9 @@ class MemTest : public MemObject
bool atomic;
- Stats::Scalar<> numReadsStat;
- Stats::Scalar<> numWritesStat;
- Stats::Scalar<> numCopiesStat;
+ Stats::Scalar numReadsStat;
+ Stats::Scalar numWritesStat;
+ Stats::Scalar numCopiesStat;
// called by MemCompleteEvent::process()
void completeRequest(PacketPtr pkt);
diff --git a/src/cpu/nativetrace.cc b/src/cpu/nativetrace.cc
index 7152602fe..c23a9e4ad 100644
--- a/src/cpu/nativetrace.cc
+++ b/src/cpu/nativetrace.cc
@@ -50,8 +50,12 @@ using namespace TheISA;
namespace Trace {
-NativeTrace::NativeTrace(const Params *p) : InstTracer(p)
+NativeTrace::NativeTrace(const Params *p)
+ : InstTracer(p)
{
+ if (ListenSocket::allDisabled())
+ fatal("All listeners are disabled!");
+
int port = 8000;
while(!native_listener.listen(port, true))
{
diff --git a/src/cpu/nativetrace.hh b/src/cpu/nativetrace.hh
index ab038c4c3..9e912d92f 100644
--- a/src/cpu/nativetrace.hh
+++ b/src/cpu/nativetrace.hh
@@ -54,8 +54,11 @@ class NativeTraceRecord : public InstRecord
public:
NativeTraceRecord(NativeTrace * _parent,
Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst, Addr _pc, bool spec)
- : InstRecord(_when, _thread, _staticInst, _pc, spec), parent(_parent)
+ const StaticInstPtr _staticInst, Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL, MicroPC _upc = 0)
+ : InstRecord(_when, _thread, _staticInst, _pc, spec,
+ _macroStaticInst, _upc),
+ parent(_parent)
{
}
@@ -192,13 +195,14 @@ class NativeTrace : public InstTracer
NativeTraceRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc)
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL, MicroPC upc = 0)
{
if (tc->misspeculating())
return NULL;
return new NativeTraceRecord(this, when, tc,
- staticInst, pc, tc->misspeculating());
+ staticInst, pc, tc->misspeculating(), macroStaticInst, upc);
}
void
diff --git a/src/cpu/o3/O3CPU.py b/src/cpu/o3/O3CPU.py
index f0284b2cf..56e537ad2 100644
--- a/src/cpu/o3/O3CPU.py
+++ b/src/cpu/o3/O3CPU.py
@@ -38,10 +38,7 @@ if build_env['USE_CHECKER']:
class DerivO3CPU(BaseCPU):
type = 'DerivO3CPU'
activity = Param.Unsigned(0, "Initial count")
- numThreads = Param.Unsigned(1, "number of HW thread contexts")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
if build_env['USE_CHECKER']:
if not build_env['FULL_SYSTEM']:
checker = Param.BaseCPU(O3Checker(workload=Parent.workload,
@@ -134,9 +131,6 @@ class DerivO3CPU(BaseCPU):
instShiftAmt = Param.Unsigned(2, "Number of bits to shift instructions by")
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
-
smtNumFetchingThreads = Param.Unsigned(1, "SMT Number of Fetching Threads")
smtFetchPolicy = Param.String('SingleThread', "SMT Fetch policy")
smtLSQPolicy = Param.String('Partitioned', "SMT LSQ Sharing Policy")
diff --git a/src/cpu/o3/O3Checker.py b/src/cpu/o3/O3Checker.py
index 43a71d67b..edc6dc9b6 100644
--- a/src/cpu/o3/O3Checker.py
+++ b/src/cpu/o3/O3Checker.py
@@ -39,5 +39,3 @@ class O3Checker(BaseCPU):
"If a load result is incorrect, only print a warning and do not exit")
function_trace = Param.Bool(False, "Enable function trace")
function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript
index 2de106d8b..f05986bf5 100755
--- a/src/cpu/o3/SConscript
+++ b/src/cpu/o3/SConscript
@@ -51,7 +51,9 @@ if 'O3CPU' in env['CPU_MODELS']:
Source('bpred_unit.cc')
Source('commit.cc')
Source('cpu.cc')
+ Source('cpu_builder.cc')
Source('decode.cc')
+ Source('dyn_inst.cc')
Source('fetch.cc')
Source('free_list.cc')
Source('fu_pool.cc')
@@ -65,6 +67,7 @@ if 'O3CPU' in env['CPU_MODELS']:
Source('rob.cc')
Source('scoreboard.cc')
Source('store_set.cc')
+ Source('thread_context.cc')
TraceFlag('FreeList')
TraceFlag('LSQ')
@@ -81,24 +84,6 @@ if 'O3CPU' in env['CPU_MODELS']:
'IQ', 'ROB', 'FreeList', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit',
'DynInst', 'O3CPU', 'Activity', 'Scoreboard', 'Writeback' ])
- if env['TARGET_ISA'] == 'alpha':
- Source('alpha/cpu.cc')
- Source('alpha/cpu_builder.cc')
- Source('alpha/dyn_inst.cc')
- Source('alpha/thread_context.cc')
- elif env['TARGET_ISA'] == 'mips':
- Source('mips/cpu.cc')
- Source('mips/cpu_builder.cc')
- Source('mips/dyn_inst.cc')
- Source('mips/thread_context.cc')
- elif env['TARGET_ISA'] == 'sparc':
- Source('sparc/cpu.cc')
- Source('sparc/cpu_builder.cc')
- Source('sparc/dyn_inst.cc')
- Source('sparc/thread_context.cc')
- else:
- sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA'])
-
if env['USE_CHECKER']:
SimObject('O3Checker.py')
Source('checker_builder.cc')
diff --git a/src/cpu/o3/alpha/cpu.cc b/src/cpu/o3/alpha/cpu.cc
deleted file mode 100644
index ed10b2fd1..000000000
--- a/src/cpu/o3/alpha/cpu.cc
+++ /dev/null
@@ -1,38 +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.
- *
- * Authors: Kevin Lim
- */
-
-#include "cpu/o3/alpha/impl.hh"
-#include "cpu/o3/alpha/cpu_impl.hh"
-#include "cpu/o3/alpha/dyn_inst.hh"
-
-// Force instantiation of AlphaO3CPU for all the implemntations that are
-// needed. Consider merging this and alpha_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (alpha_impl.cc?).
-template class AlphaO3CPU<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh
deleted file mode 100644
index ebc4e7b23..000000000
--- a/src/cpu/o3/alpha/cpu.hh
+++ /dev/null
@@ -1,149 +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.
- *
- * Authors: Kevin Lim
- */
-
-#ifndef __CPU_O3_ALPHA_CPU_HH__
-#define __CPU_O3_ALPHA_CPU_HH__
-
-#include "arch/regfile.hh"
-#include "arch/types.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * AlphaO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class AlphaO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an AlphaO3CPU with the given parameters. */
- AlphaO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val,
- unsigned tid);
-
- /** Sets a misc. register, including any side effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const TheISA::MiscReg &val,
- unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
-#if FULL_SYSTEM
- /** Posts an interrupt. */
- void post_interrupt(int int_num, int index);
- /** HW return from error interrupt. */
- Fault hwrei(unsigned tid);
-
- bool simPalCheck(int palFunc, unsigned tid);
-
- /** Returns the Fault for any valid interrupt. */
- Fault getInterrupts();
-
- /** Processes any an interrupt fault. */
- void processInterrupts(Fault interrupt);
-
- /** Halts the CPU. */
- void halt() { panic("Halt not implemented!\n"); }
-#endif
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
-#if !FULL_SYSTEM
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-#endif
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_ALPHA_CPU_HH__
diff --git a/src/cpu/o3/alpha/cpu_builder.cc b/src/cpu/o3/alpha/cpu_builder.cc
deleted file mode 100644
index f569c048b..000000000
--- a/src/cpu/o3/alpha/cpu_builder.cc
+++ /dev/null
@@ -1,199 +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.
- *
- * Authors: Kevin Lim
- */
-
-#include <string>
-
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/alpha/cpu.hh"
-#include "cpu/o3/alpha/impl.hh"
-#include "cpu/o3/alpha/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public AlphaO3CPU<AlphaSimpleImpl>
-{
- public:
- DerivO3CPU(AlphaSimpleParams *p)
- : AlphaO3CPU<AlphaSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
-#if FULL_SYSTEM
- // Full-system only supports a single thread for the moment.
- int actual_num_threads = 1;
-#else
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-#endif
-
- AlphaSimpleParams *params = new AlphaSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->itb = itb;
- params->dtb = dtb;
-
- params->system = system;
-#if FULL_SYSTEM
- params->profile = profile;
-
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
- params->workload = workload;
-#endif // FULL_SYSTEM
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- 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->progress_interval = progress_interval;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh
deleted file mode 100644
index 7f8f0547b..000000000
--- a/src/cpu/o3/alpha/cpu_impl.hh
+++ /dev/null
@@ -1,314 +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.
- *
- * Authors: Kevin Lim
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/alpha/faults.hh"
-#include "arch/alpha/isa_traits.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.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/alpha/thread_context.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 "arch/kernel_stats.hh"
-#include "cpu/quiesce_event.hh"
-#include "sim/sim_exit.hh"
-#include "sim/system.hh"
-#endif
-
-template <class Impl>
-AlphaO3CPU<Impl>::AlphaO3CPU(Params *params) : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating AlphaO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
-#if FULL_SYSTEM
- // SMT is not supported in FS mode yet.
- assert(this->numThreads == 1);
- this->thread[i] = new Thread(this, 0);
- this->thread[i]->setStatus(ThreadContext::Suspended);
-#else
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread 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
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- AlphaTC<Impl> *alpha_tc =
- new AlphaTC<Impl>;
-
- tc = alpha_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<AlphaTC<Impl> >(
- alpha_tc, this->checker);
- }
-#endif
-
- alpha_tc->cpu = this;
- alpha_tc->thread = this->thread[i];
-
-#if FULL_SYSTEM
- // Setup quiesce event.
- this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
-#endif
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-AlphaO3CPU<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();
-}
-
-
-template <class Impl>
-TheISA::MiscReg
-AlphaO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-TheISA::MiscReg
-AlphaO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val,
- unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setMiscReg(int misc_reg,
- const TheISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-#if FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::post_interrupt(int int_num, int index)
-{
- BaseCPU::post_interrupt(int_num, index);
-
- if (this->thread[0]->status() == ThreadContext::Suspended) {
- DPRINTF(IPI,"Suspended Processor awoke\n");
- this->threadContexts[0]->activate();
- }
-}
-
-template <class Impl>
-Fault
-AlphaO3CPU<Impl>::hwrei(unsigned tid)
-{
- // Need to clear the lock flag upon returning from an interrupt.
- this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
-
- this->thread[tid]->kernelStats->hwrei();
-
- // FIXME: XXX check for interrupts? XXX
- return NoFault;
-}
-
-template <class Impl>
-bool
-AlphaO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
-{
- if (this->thread[tid]->kernelStats)
- this->thread[tid]->kernelStats->callpal(palFunc,
- this->threadContexts[tid]);
-
- switch (palFunc) {
- case PAL::halt:
- halt();
- if (--System::numSystemsRunning == 0)
- exitSimLoop("all cpus halted");
- break;
-
- case PAL::bpt:
- case PAL::bugchk:
- if (this->system->breakpoint())
- return false;
- break;
- }
-
- return true;
-}
-
-template <class Impl>
-Fault
-AlphaO3CPU<Impl>::getInterrupts()
-{
- // Check if there are any outstanding interrupts
- return this->interrupts.getInterrupt(this->threadContexts[0]);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::processInterrupts(Fault interrupt)
-{
- // 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.
-
- assert(interrupt != NoFault);
- this->interrupts.updateIntrInfo(this->threadContexts[0]);
-
- DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
- this->trap(interrupt, 0);
-}
-
-#endif // FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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(callnum);
-
- // Decrease funcExeInst by one as the normal commit will handle
- // incrementing it.
- --(this->thread[tid]->funcExeInst);
-}
-
-template <class Impl>
-TheISA::IntReg
-AlphaO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- return this->readArchIntReg(AlphaISA::ArgumentReg[i], tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- this->setArchIntReg(AlphaISA::ArgumentReg[i], val, tid);
-}
-
-template <class Impl>
-void
-AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/alpha/dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc
deleted file mode 100644
index 97d2f3d08..000000000
--- a/src/cpu/o3/alpha/dyn_inst.cc
+++ /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.
- *
- * Authors: Kevin Lim
- */
-
-#include "cpu/o3/alpha/dyn_inst_impl.hh"
-#include "cpu/o3/alpha/impl.hh"
-
-// Force instantiation of AlphaDynInst for all the implementations that
-// are needed.
-template class AlphaDynInst<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha/dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh
deleted file mode 100644
index a6fb7b885..000000000
--- a/src/cpu/o3/alpha/dyn_inst.hh
+++ /dev/null
@@ -1,277 +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.
- *
- * Authors: Kevin Lim
- */
-
-#ifndef __CPU_O3_ALPHA_DYN_INST_HH__
-#define __CPU_O3_ALPHA_DYN_INST_HH__
-
-#include "arch/isa_traits.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/alpha/cpu.hh"
-#include "cpu/o3/alpha/impl.hh"
-
-class Packet;
-
-/**
- * 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::O3CPU O3CPU;
-
- /** 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;
- typedef TheISA::FloatReg FloatReg;
- typedef TheISA::FloatRegBits FloatRegBits;
- /** 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(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- AlphaDynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *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(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- MiscReg readMiscRegNoEffect(int misc_reg)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- MiscReg readMiscReg(int misc_reg)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const MiscReg &val)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscRegNoEffect(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscRegOperand(const StaticInst *si, int idx,
- const MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
-#if FULL_SYSTEM
- /** Calls hardware return from error interrupt. */
- Fault hwrei();
- /** Traps to handle specified fault. */
- void trap(Fault fault);
- bool simPalCheck(int palFunc);
-#else
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-#endif
-
- 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 readIntRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readIntReg(this->_srcRegIdx[idx]);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
- int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
- int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- 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/src/cpu/o3/alpha/impl.hh b/src/cpu/o3/alpha/impl.hh
deleted file mode 100644
index b928ae654..000000000
--- a/src/cpu/o3/alpha/impl.hh
+++ /dev/null
@@ -1,92 +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.
- *
- * Authors: Kevin Lim
- */
-
-#ifndef __CPU_O3_ALPHA_IMPL_HH__
-#define __CPU_O3_ALPHA_IMPL_HH__
-
-#include "arch/alpha/isa_traits.hh"
-
-#include "cpu/o3/alpha/params.hh"
-#include "cpu/o3/cpu_policy.hh"
-
-
-// Forward declarations.
-template <class Impl>
-class AlphaDynInst;
-
-template <class Impl>
-class AlphaO3CPU;
-
-/** Implementation specific struct that defines several key types to the
- * CPU, the stages within the CPU, the time buffers, and the DynInst.
- * The struct defines the ISA, the CPU policy, the specific DynInst, the
- * specific O3CPU, and all of the structs from the time buffers to do
- * communication.
- * This is one of the key things that must be defined for each hardware
- * specific CPU implementation.
- */
-struct AlphaSimpleImpl
-{
- /** The type of MachInst. */
- typedef TheISA::MachInst MachInst;
-
- /** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol;
-
- /** The DynInst type to be used. */
- typedef AlphaDynInst<AlphaSimpleImpl> DynInst;
-
- /** The refcounted DynInst pointer to be used. In most cases this is
- * what should be used, and not DynInst *.
- */
- typedef RefCountingPtr<DynInst> DynInstPtr;
-
- /** The O3CPU type to be used. */
- typedef AlphaO3CPU<AlphaSimpleImpl> O3CPU;
-
- /** Same typedef, but for CPUType. BaseDynInst may not always use
- * an O3 CPU, so it's clearer to call it CPUType instead in that
- * case.
- */
- typedef O3CPU CPUType;
-
- /** The Params to be passed to each stage. */
- typedef AlphaSimpleParams Params;
-
- enum {
- MaxWidth = 8,
- MaxThreads = 4
- };
-};
-
-/** The O3Impl to be used. */
-typedef AlphaSimpleImpl O3CPUImpl;
-
-#endif // __CPU_O3_ALPHA_IMPL_HH__
diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc
index 0979c5c8f..510109d8a 100644
--- a/src/cpu/o3/base_dyn_inst.cc
+++ b/src/cpu/o3/base_dyn_inst.cc
@@ -29,11 +29,8 @@
*/
#include "cpu/base_dyn_inst_impl.hh"
+#include "cpu/o3/cpu.hh"
#include "cpu/o3/isa_specific.hh"
// Explicit instantiation
template class BaseDynInst<O3CPUImpl>;
-
-template <>
-int
-BaseDynInst<O3CPUImpl>::instcount = 0;
diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh
index 3c4c8e478..b32d2bd23 100644
--- a/src/cpu/o3/bpred_unit.hh
+++ b/src/cpu/o3/bpred_unit.hh
@@ -43,6 +43,8 @@
#include <list>
+class DerivO3CPUParams;
+
/**
* Basically a wrapper class to hold both the branch predictor
* and the BTB.
@@ -51,7 +53,6 @@ template<class Impl>
class BPredUnit
{
private:
- typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
enum PredType {
@@ -61,12 +62,16 @@ class BPredUnit
PredType predictor;
+ const std::string _name;
+
public:
/**
* @param params The params object, that has the size of the BP and BTB.
*/
- BPredUnit(Params *params);
+ BPredUnit(DerivO3CPUParams *params);
+
+ const std::string &name() const { return _name; }
/**
* Registers statistics.
@@ -236,21 +241,21 @@ class BPredUnit
ReturnAddrStack RAS[Impl::MaxThreads];
/** Stat for number of BP lookups. */
- Stats::Scalar<> lookups;
+ Stats::Scalar lookups;
/** Stat for number of conditional branches predicted. */
- Stats::Scalar<> condPredicted;
+ Stats::Scalar condPredicted;
/** Stat for number of conditional branches predicted incorrectly. */
- Stats::Scalar<> condIncorrect;
+ Stats::Scalar condIncorrect;
/** Stat for number of BTB lookups. */
- Stats::Scalar<> BTBLookups;
+ Stats::Scalar BTBLookups;
/** Stat for number of BTB hits. */
- Stats::Scalar<> BTBHits;
+ Stats::Scalar BTBHits;
/** Stat for number of times the BTB is correct. */
- Stats::Scalar<> BTBCorrect;
+ Stats::Scalar BTBCorrect;
/** Stat for number of times the RAS is used to get a target. */
- Stats::Scalar<> usedRAS;
+ Stats::Scalar usedRAS;
/** Stat for number of times the RAS is incorrect. */
- Stats::Scalar<> RASIncorrect;
+ Stats::Scalar RASIncorrect;
};
#endif // __CPU_O3_BPRED_UNIT_HH__
diff --git a/src/cpu/o3/bpred_unit_impl.hh b/src/cpu/o3/bpred_unit_impl.hh
index 84c50b4da..2fa59280d 100644
--- a/src/cpu/o3/bpred_unit_impl.hh
+++ b/src/cpu/o3/bpred_unit_impl.hh
@@ -34,11 +34,14 @@
#include "base/traceflags.hh"
#include "cpu/o3/bpred_unit.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
-BPredUnit<Impl>::BPredUnit(Params *params)
- : BTB(params->BTBEntries,
- params->BTBTagSize,
- params->instShiftAmt)
+BPredUnit<Impl>::BPredUnit(DerivO3CPUParams *params)
+ : _name(params->name + ".BPredUnit"),
+ BTB(params->BTBEntries,
+ params->BTBTagSize,
+ params->instShiftAmt)
{
// Setup the selected predictor.
if (params->predType == "local") {
@@ -71,43 +74,43 @@ void
BPredUnit<Impl>::regStats()
{
lookups
- .name(name() + ".BPredUnit.lookups")
+ .name(name() + ".lookups")
.desc("Number of BP lookups")
;
condPredicted
- .name(name() + ".BPredUnit.condPredicted")
+ .name(name() + ".condPredicted")
.desc("Number of conditional branches predicted")
;
condIncorrect
- .name(name() + ".BPredUnit.condIncorrect")
+ .name(name() + ".condIncorrect")
.desc("Number of conditional branches incorrect")
;
BTBLookups
- .name(name() + ".BPredUnit.BTBLookups")
+ .name(name() + ".BTBLookups")
.desc("Number of BTB lookups")
;
BTBHits
- .name(name() + ".BPredUnit.BTBHits")
+ .name(name() + ".BTBHits")
.desc("Number of BTB hits")
;
BTBCorrect
- .name(name() + ".BPredUnit.BTBCorrect")
+ .name(name() + ".BTBCorrect")
.desc("Number of correct BTB predictions (this stat may not "
"work properly.")
;
usedRAS
- .name(name() + ".BPredUnit.usedRAS")
+ .name(name() + ".usedRAS")
.desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
- .name(name() + ".BPredUnit.RASInCorrect")
+ .name(name() + ".RASInCorrect")
.desc("Number of incorrect RAS predictions.")
;
}
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 80e42fa8b..f21c14569 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -37,6 +37,8 @@
#include "cpu/exetrace.hh"
#include "cpu/inst_seq.hh"
+class DerivO3CPUParams;
+
template <class>
class O3ThreadState;
@@ -69,7 +71,6 @@ class DefaultCommit
// Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol CPUPol;
typedef typename CPUPol::RenameMap RenameMap;
@@ -136,7 +137,7 @@ class DefaultCommit
public:
/** Construct a DefaultCommit with the given parameters. */
- DefaultCommit(O3CPU *_cpu, Params *params);
+ DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of the DefaultCommit. */
std::string name() const;
@@ -451,40 +452,40 @@ class DefaultCommit
void updateComInstStats(DynInstPtr &inst);
/** Stat for the total number of committed instructions. */
- Stats::Scalar<> commitCommittedInsts;
+ Stats::Scalar commitCommittedInsts;
/** Stat for the total number of squashed instructions discarded by commit.
*/
- Stats::Scalar<> commitSquashedInsts;
+ Stats::Scalar commitSquashedInsts;
/** Stat for the total number of times commit is told to squash.
* @todo: Actually increment this stat.
*/
- Stats::Scalar<> commitSquashEvents;
+ Stats::Scalar commitSquashEvents;
/** Stat for the total number of times commit has had to stall due to a non-
* speculative instruction reaching the head of the ROB.
*/
- Stats::Scalar<> commitNonSpecStalls;
+ Stats::Scalar commitNonSpecStalls;
/** Stat for the total number of branch mispredicts that caused a squash. */
- Stats::Scalar<> branchMispredicts;
+ Stats::Scalar branchMispredicts;
/** Distribution of the number of committed instructions each cycle. */
- Stats::Distribution<> numCommittedDist;
+ Stats::Distribution numCommittedDist;
/** Total number of instructions committed. */
- Stats::Vector<> statComInst;
+ Stats::Vector statComInst;
/** Total number of software prefetches committed. */
- Stats::Vector<> statComSwp;
+ Stats::Vector statComSwp;
/** Stat for the total number of committed memory references. */
- Stats::Vector<> statComRefs;
+ Stats::Vector statComRefs;
/** Stat for the total number of committed loads. */
- Stats::Vector<> statComLoads;
+ Stats::Vector statComLoads;
/** Total number of committed memory barriers. */
- Stats::Vector<> statComMembars;
+ Stats::Vector statComMembars;
/** Total number of committed branches. */
- Stats::Vector<> statComBranches;
+ Stats::Vector statComBranches;
/** Number of cycles where the commit bandwidth limit is reached. */
- Stats::Scalar<> commitEligibleSamples;
+ Stats::Scalar commitEligibleSamples;
/** Number of instructions not committed due to bandwidth limits. */
- Stats::Vector<> commitEligible;
+ Stats::Vector commitEligible;
};
#endif // __CPU_O3_COMMIT_HH__
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index ee0f2bb59..7cd88b49b 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -36,6 +36,7 @@
#include <string>
#include "arch/utility.hh"
+#include "base/cp_annotate.hh"
#include "base/loader/symtab.hh"
#include "base/timebuf.hh"
#include "cpu/exetrace.hh"
@@ -46,12 +47,14 @@
#include "cpu/checker/cpu.hh"
#endif
+#include "params/DerivO3CPU.hh"
+
template <class Impl>
DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
unsigned _tid)
- : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
+ : Event(CPU_Tick_Pri), commit(_commit), tid(_tid)
{
- this->setFlags(Event::AutoDelete);
+ this->setFlags(AutoDelete);
}
template <class Impl>
@@ -71,7 +74,7 @@ DefaultCommit<Impl>::TrapEvent::description() const
}
template <class Impl>
-DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params)
+DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
squashCounter(0),
iewToCommitDelay(params->iewToCommitDelay),
@@ -80,7 +83,7 @@ DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params)
fetchToCommitDelay(params->commitToFetchDelay),
renameWidth(params->renameWidth),
commitWidth(params->commitWidth),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
drainPending(false),
switchedOut(false),
trapLatency(params->trapLatency)
@@ -460,7 +463,7 @@ DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
TrapEvent *trap = new TrapEvent(this, tid);
- trap->schedule(curTick + trapLatency);
+ cpu->schedule(trap, curTick + trapLatency);
trapInFlight[tid] = true;
}
@@ -663,7 +666,7 @@ DefaultCommit<Impl>::handleInterrupt()
DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
}
} else if (commitStatus[0] != TrapPending &&
- cpu->check_interrupts(cpu->tcBase(0)) &&
+ cpu->checkInterrupts(cpu->tcBase(0)) &&
!trapSquash[0] &&
!tcSquash[0]) {
// Process interrupts if interrupts are enabled, not in PAL
@@ -693,7 +696,7 @@ DefaultCommit<Impl>::commit()
// Check for any interrupt, and start processing it. Or if we
// have an outstanding interrupt and are at a point when it is
// valid to take an interrupt, process it.
- if (cpu->check_interrupts(cpu->tcBase(0))) {
+ if (cpu->checkInterrupts(cpu->tcBase(0))) {
handleInterrupt();
}
#endif // FULL_SYSTEM
@@ -812,7 +815,7 @@ DefaultCommit<Impl>::commit()
// @todo: Make this handle multi-cycle communication between
// commit and IEW.
if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
- !iewStage->hasStoresToWB() && !committedStores[tid]) {
+ !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
checkEmptyROB[tid] = false;
toIEW->commitInfo[tid].usedROB = true;
toIEW->commitInfo[tid].emptyROB = true;
@@ -966,7 +969,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
"instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
head_inst->seqNum, head_inst->readPC());
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
+ if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
DPRINTF(Commit, "Waiting for all stores to writeback.\n");
return false;
}
@@ -981,7 +984,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
return false;
} else if (head_inst->isLoad()) {
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
+ if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
DPRINTF(Commit, "Waiting for all stores to writeback.\n");
return false;
}
@@ -1036,7 +1039,7 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
head_inst->seqNum, head_inst->readPC());
- if (iewStage->hasStoresToWB() || inst_num > 0) {
+ if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
return false;
}
@@ -1095,6 +1098,12 @@ DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
if (node)
thread[tid]->profileNode = node;
}
+ if (CPA::available()) {
+ if (head_inst->isControl()) {
+ ThreadContext *tc = thread[tid]->getTC();
+ CPA::cpa()->swAutoBegin(tc, head_inst->readNextPC());
+ }
+ }
#endif
if (head_inst->traceData) {
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index c75a08213..1d7fb97c0 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -37,6 +37,7 @@
#include "cpu/thread_context.hh"
#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/cpu.hh"
+#include "cpu/o3/thread_context.hh"
#include "enums/MemoryMode.hh"
#include "sim/core.hh"
#include "sim/stat_control.hh"
@@ -52,10 +53,16 @@
#include "cpu/checker/cpu.hh"
#endif
+#if THE_ISA == ALPHA_ISA
+#include "arch/alpha/osfpal.hh"
+#endif
+
+class BaseCPUParams;
+
using namespace TheISA;
-BaseO3CPU::BaseO3CPU(Params *params)
- : BaseCPU(params), cpu_id(0)
+BaseO3CPU::BaseO3CPU(BaseCPUParams *params)
+ : BaseCPU(params)
{
}
@@ -67,7 +74,7 @@ BaseO3CPU::regStats()
template <class Impl>
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+ : Event(CPU_Tick_Pri), cpu(c)
{
}
@@ -87,7 +94,7 @@ FullO3CPU<Impl>::TickEvent::description() const
template <class Impl>
FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
- : Event(&mainEventQueue, CPU_Switch_Pri)
+ : Event(CPU_Switch_Pri)
{
}
@@ -116,7 +123,7 @@ FullO3CPU<Impl>::ActivateThreadEvent::description() const
template <class Impl>
FullO3CPU<Impl>::DeallocateContextEvent::DeallocateContextEvent()
- : Event(&mainEventQueue, CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
+ : Event(CPU_Tick_Pri), tid(0), remove(false), cpu(NULL)
{
}
@@ -147,31 +154,34 @@ FullO3CPU<Impl>::DeallocateContextEvent::description() const
}
template <class Impl>
-FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
+FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
: BaseO3CPU(params),
itb(params->itb),
dtb(params->dtb),
tickEvent(this),
+#ifndef NDEBUG
+ instcount(0),
+#endif
removeInstsThisCycle(false),
- fetch(o3_cpu, params),
- decode(o3_cpu, params),
- rename(o3_cpu, params),
- iew(o3_cpu, params),
- commit(o3_cpu, params),
+ fetch(this, params),
+ decode(this, params),
+ rename(this, params),
+ iew(this, params),
+ commit(this, params),
- regFile(o3_cpu, params->numPhysIntRegs,
+ regFile(this, params->numPhysIntRegs,
params->numPhysFloatRegs),
- freeList(params->numberOfThreads,
+ freeList(params->numThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs),
- rob(o3_cpu,
+ rob(this,
params->numROBEntries, params->squashWidth,
params->smtROBPolicy, params->smtROBThreshold,
- params->numberOfThreads),
+ params->numThreads),
- scoreboard(params->numberOfThreads,
+ scoreboard(params->numThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs,
TheISA::NumMiscRegs * number_of_threads,
@@ -182,7 +192,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
decodeQueue(params->backComSize, params->forwardComSize),
renameQueue(params->backComSize, params->forwardComSize),
iewQueue(params->backComSize, params->forwardComSize),
- activityRec(NumStages,
+ activityRec(name(), NumStages,
params->backComSize + params->forwardComSize,
params->activity),
@@ -192,7 +202,7 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
physmem(system->physmem),
#endif // FULL_SYSTEM
drainCount(0),
- deferRegistration(params->deferRegistration),
+ deferRegistration(params->defer_registration),
numThreads(number_of_threads)
{
if (!deferRegistration) {
@@ -336,6 +346,78 @@ FullO3CPU<Impl>::FullO3CPU(O3CPU *o3_cpu, Params *params)
//}
contextSwitch = false;
+ DPRINTF(O3CPU, "Creating O3CPU object.\n");
+
+ // Setup any thread state.
+ this->thread.resize(this->numThreads);
+
+ for (int i = 0; i < this->numThreads; ++i) {
+#if FULL_SYSTEM
+ // SMT is not supported in FS mode yet.
+ assert(this->numThreads == 1);
+ this->thread[i] = new Thread(this, 0);
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+#else
+ if (i < params->workload.size()) {
+ DPRINTF(O3CPU, "Workload[%i] process is %#x",
+ i, this->thread[i]);
+ this->thread[i] = new typename FullO3CPU<Impl>::Thread(
+ (typename Impl::O3CPU *)(this),
+ i, params->workload[i], i);
+
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+
+ //usedTids[i] = true;
+ //threadMap[i] = i;
+ } else {
+ //Allocate Empty thread so M5 can use later
+ //when scheduling threads to CPU
+ Process* dummy_proc = NULL;
+
+ this->thread[i] = new typename FullO3CPU<Impl>::Thread(
+ (typename Impl::O3CPU *)(this),
+ i, dummy_proc, i);
+ //usedTids[i] = false;
+ }
+#endif // !FULL_SYSTEM
+
+ ThreadContext *tc;
+
+ // Setup the TC that will serve as the interface to the threads/CPU.
+ O3ThreadContext<Impl> *o3_tc = new O3ThreadContext<Impl>;
+
+ tc = o3_tc;
+
+ // If we're using a checker, then the TC should be the
+ // CheckerThreadContext.
+#if USE_CHECKER
+ if (params->checker) {
+ tc = new CheckerThreadContext<O3ThreadContext<Impl> >(
+ o3_tc, this->checker);
+ }
+#endif
+
+ o3_tc->cpu = (typename Impl::O3CPU *)(this);
+ assert(o3_tc->cpu);
+ o3_tc->thread = this->thread[i];
+
+#if FULL_SYSTEM
+ // Setup quiesce event.
+ this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
+#endif
+ // Give the thread the TC.
+ this->thread[i]->tc = tc;
+
+ // Add the TC to the CPU's list of TC's.
+ this->threadContexts.push_back(tc);
+ }
+
+ for (int i=0; i < this->numThreads; i++) {
+ this->thread[i]->setFuncExeInst(0);
+ }
+
+ lockAddr = 0;
+ lockFlag = false;
}
template <class Impl>
@@ -345,7 +427,7 @@ FullO3CPU<Impl>::~FullO3CPU()
template <class Impl>
void
-FullO3CPU<Impl>::fullCPURegStats()
+FullO3CPU<Impl>::regStats()
{
BaseO3CPU::regStats();
@@ -399,6 +481,11 @@ FullO3CPU<Impl>::fullCPURegStats()
.precision(6);
totalIpc = totalCommittedInsts / numCycles;
+ this->fetch.regStats();
+ this->decode.regStats();
+ this->rename.regStats();
+ this->iew.regStats();
+ this->commit.regStats();
}
template <class Impl>
@@ -463,7 +550,7 @@ FullO3CPU<Impl>::tick()
lastRunningCycle = curTick;
timesIdled++;
} else {
- tickEvent.schedule(nextCycle(curTick + ticks(1)));
+ schedule(tickEvent, nextCycle(curTick + ticks(1)));
DPRINTF(O3CPU, "Scheduling next tick!\n");
}
}
@@ -471,16 +558,13 @@ FullO3CPU<Impl>::tick()
#if !FULL_SYSTEM
updateThreadPriority();
#endif
-
}
template <class Impl>
void
FullO3CPU<Impl>::init()
{
- if (!deferRegistration) {
- registerThreadContexts();
- }
+ BaseCPU::init();
// Set inSyscall so that the CPU doesn't squash when initially
// setting up registers.
@@ -499,7 +583,7 @@ FullO3CPU<Impl>::init()
}
#if FULL_SYSTEM
- TheISA::initCPU(src_tc, src_tc->readCpuId());
+ TheISA::initCPU(src_tc, src_tc->contextId());
#endif
}
@@ -602,7 +686,7 @@ FullO3CPU<Impl>::suspendContext(int tid)
DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
bool deallocated = deallocateContext(tid, false, 1);
// If this was the last thread then unschedule the tick event.
- if (activeThreads.size() == 1 && !deallocated ||
+ if ((activeThreads.size() == 1 && !deallocated) ||
activeThreads.size() == 0)
unscheduleTickEvent();
_status = Idle;
@@ -782,18 +866,116 @@ FullO3CPU<Impl>::activateWhenReady(int tid)
#if FULL_SYSTEM
template <class Impl>
+Fault
+FullO3CPU<Impl>::hwrei(unsigned tid)
+{
+#if THE_ISA == ALPHA_ISA
+ // Need to clear the lock flag upon returning from an interrupt.
+ this->setMiscRegNoEffect(AlphaISA::MISCREG_LOCKFLAG, false, tid);
+
+ this->thread[tid]->kernelStats->hwrei();
+
+ // FIXME: XXX check for interrupts? XXX
+#endif
+ return NoFault;
+}
+
+template <class Impl>
+bool
+FullO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
+{
+#if THE_ISA == ALPHA_ISA
+ if (this->thread[tid]->kernelStats)
+ this->thread[tid]->kernelStats->callpal(palFunc,
+ this->threadContexts[tid]);
+
+ switch (palFunc) {
+ case PAL::halt:
+ halt();
+ if (--System::numSystemsRunning == 0)
+ exitSimLoop("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (this->system->breakpoint())
+ return false;
+ break;
+ }
+#endif
+ return true;
+}
+
+template <class Impl>
+Fault
+FullO3CPU<Impl>::getInterrupts()
+{
+ // Check if there are any outstanding interrupts
+ return this->interrupts->getInterrupt(this->threadContexts[0]);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::processInterrupts(Fault interrupt)
+{
+ // 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.
+
+ assert(interrupt != NoFault);
+ this->interrupts->updateIntrInfo(this->threadContexts[0]);
+
+ DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
+ this->trap(interrupt, 0);
+}
+
+template <class Impl>
void
FullO3CPU<Impl>::updateMemPorts()
{
// Update all ThreadContext's memory ports (Functional/Virtual
// Ports)
for (int i = 0; i < thread.size(); ++i)
- thread[i]->connectMemPorts();
+ thread[i]->connectMemPorts(thread[i]->getTC());
}
#endif
template <class Impl>
void
+FullO3CPU<Impl>::trap(Fault fault, unsigned tid)
+{
+ // Pass the thread's TC into the invoke method.
+ fault->invoke(this->threadContexts[tid]);
+}
+
+#if !FULL_SYSTEM
+
+template <class Impl>
+void
+FullO3CPU<Impl>::syscall(int64_t callnum, int tid)
+{
+ DPRINTF(O3CPU, "[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(callnum);
+
+ // Decrease funcExeInst by one as the normal commit will handle
+ // incrementing it.
+ --(this->thread[tid]->funcExeInst);
+}
+
+#endif
+
+template <class Impl>
+void
FullO3CPU<Impl>::serialize(std::ostream &os)
{
SimObject::State so_state = SimObject::getState();
@@ -891,7 +1073,7 @@ FullO3CPU<Impl>::resume()
#endif
if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
_status = Running;
}
@@ -984,11 +1166,41 @@ FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
ThreadContext *tc = threadContexts[i];
if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
}
}
if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
+}
+
+template <class Impl>
+TheISA::MiscReg
+FullO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
+{
+ return this->regFile.readMiscRegNoEffect(misc_reg, tid);
+}
+
+template <class Impl>
+TheISA::MiscReg
+FullO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
+{
+ return this->regFile.readMiscReg(misc_reg, tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
+ const TheISA::MiscReg &val, unsigned tid)
+{
+ this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setMiscReg(int misc_reg,
+ const TheISA::MiscReg &val, unsigned tid)
+{
+ this->regFile.setMiscReg(misc_reg, val, tid);
}
template <class Impl>
@@ -1210,6 +1422,14 @@ FullO3CPU<Impl>::setNextMicroPC(Addr new_PC,unsigned tid)
}
template <class Impl>
+void
+FullO3CPU<Impl>::squashFromTC(unsigned tid)
+{
+ this->thread[tid]->inSyscall = true;
+ this->commit.generateTCEvent(tid);
+}
+
+template <class Impl>
typename FullO3CPU<Impl>::ListIt
FullO3CPU<Impl>::addInst(DynInstPtr &inst)
{
@@ -1419,9 +1639,24 @@ FullO3CPU<Impl>::wakeCPU()
idleCycles += tickToCycles((curTick - 1) - lastRunningCycle);
numCycles += tickToCycles((curTick - 1) - lastRunningCycle);
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
}
+#if FULL_SYSTEM
+template <class Impl>
+void
+FullO3CPU<Impl>::wakeup()
+{
+ if (this->thread[0]->status() != ThreadContext::Suspended)
+ return;
+
+ this->wakeCPU();
+
+ DPRINTF(Quiesce, "Suspended Processor woken\n");
+ this->threadContexts[0]->activate();
+}
+#endif
+
template <class Impl>
int
FullO3CPU<Impl>::getFreeTid()
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index 61d7dcf22..942970f5f 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -53,6 +53,8 @@
//#include "cpu/o3/thread_context.hh"
#include "sim/process.hh"
+#include "params/DerivO3CPU.hh"
+
template <class>
class Checker;
class ThreadContext;
@@ -63,24 +65,15 @@ class Checkpoint;
class MemObject;
class Process;
+class BaseCPUParams;
+
class BaseO3CPU : public BaseCPU
{
//Stuff that's pretty ISA independent will go here.
public:
- typedef BaseCPU::Params Params;
-
- BaseO3CPU(Params *params);
+ BaseO3CPU(BaseCPUParams *params);
void regStats();
-
- /** Sets this CPU's ID. */
- void setCpuId(int id) { cpu_id = id; }
-
- /** Reads this CPU's ID. */
- int readCpuId() { return cpu_id; }
-
- protected:
- int cpu_id;
};
/**
@@ -96,8 +89,8 @@ class FullO3CPU : public BaseO3CPU
typedef typename Impl::CPUPol CPUPolicy;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
+ typedef O3ThreadState<Impl> ImplState;
typedef O3ThreadState<Impl> Thread;
typedef typename std::list<DynInstPtr>::iterator ListIt;
@@ -146,9 +139,9 @@ class FullO3CPU : public BaseO3CPU
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
- tickEvent.reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(tickEvent, nextCycle(curTick + ticks(delay)));
else if (!tickEvent.scheduled())
- tickEvent.schedule(nextCycle(curTick + ticks(delay)));
+ schedule(tickEvent, nextCycle(curTick + ticks(delay)));
}
/** Unschedule tick event, regardless of its current state. */
@@ -186,11 +179,11 @@ class FullO3CPU : public BaseO3CPU
{
// Schedule thread to activate, regardless of its current state.
if (activateThreadEvent[tid].squashed())
- activateThreadEvent[tid].
- reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(activateThreadEvent[tid],
+ nextCycle(curTick + ticks(delay)));
else if (!activateThreadEvent[tid].scheduled())
- activateThreadEvent[tid].
- schedule(nextCycle(curTick + ticks(delay)));
+ schedule(activateThreadEvent[tid],
+ nextCycle(curTick + ticks(delay)));
}
/** Unschedule actiavte thread event, regardless of its current state. */
@@ -237,11 +230,11 @@ class FullO3CPU : public BaseO3CPU
{
// Schedule thread to activate, regardless of its current state.
if (deallocateContextEvent[tid].squashed())
- deallocateContextEvent[tid].
- reschedule(nextCycle(curTick + ticks(delay)));
+ reschedule(deallocateContextEvent[tid],
+ nextCycle(curTick + ticks(delay)));
else if (!deallocateContextEvent[tid].scheduled())
- deallocateContextEvent[tid].
- schedule(nextCycle(curTick + ticks(delay)));
+ schedule(deallocateContextEvent[tid],
+ nextCycle(curTick + ticks(delay)));
}
/** Unschedule thread deallocation in CPU */
@@ -256,12 +249,12 @@ class FullO3CPU : public BaseO3CPU
public:
/** Constructs a CPU with the given parameters. */
- FullO3CPU(O3CPU *o3_cpu, Params *params);
+ FullO3CPU(DerivO3CPUParams *params);
/** Destructor. */
~FullO3CPU();
/** Registers statistics. */
- void fullCPURegStats();
+ void regStats();
void demapPage(Addr vaddr, uint64_t asn)
{
@@ -279,24 +272,6 @@ class FullO3CPU : public BaseO3CPU
this->dtb->demapPage(vaddr, asn);
}
- /** Translates instruction requestion. */
- Fault translateInstReq(RequestPtr &req, Thread *thread)
- {
- return this->itb->translate(req, thread->getTC());
- }
-
- /** Translates data read request. */
- Fault translateDataReadReq(RequestPtr &req, Thread *thread)
- {
- return this->dtb->translate(req, thread->getTC(), false);
- }
-
- /** Translates data write request. */
- Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
- {
- return this->dtb->translate(req, thread->getTC(), true);
- }
-
/** Returns a specific port. */
Port *getPort(const std::string &if_name, int idx);
@@ -367,12 +342,12 @@ class FullO3CPU : public BaseO3CPU
virtual void unserialize(Checkpoint *cp, const std::string &section);
public:
- /** Executes a syscall on this cycle.
- * ---------------------------------------
- * Note: this is a virtual function. CPU-Specific
- * functionality defined in derived classes
+#if !FULL_SYSTEM
+ /** Executes a syscall.
+ * @todo: Determine if this needs to be virtual.
*/
- virtual void syscall(int tid) { panic("Unimplemented!"); }
+ void syscall(int64_t callnum, int tid);
+#endif
/** Starts draining the CPU's pipeline of all instructions in
* order to stop all memory accesses. */
@@ -394,7 +369,24 @@ class FullO3CPU : public BaseO3CPU
InstSeqNum getAndIncrementInstSeq()
{ return globalSeqNum++; }
+ /** Traps to handle given fault. */
+ void trap(Fault fault, unsigned tid);
+
#if FULL_SYSTEM
+ /** HW return from error interrupt. */
+ Fault hwrei(unsigned tid);
+
+ bool simPalCheck(int palFunc, unsigned tid);
+
+ /** Returns the Fault for any valid interrupt. */
+ Fault getInterrupts();
+
+ /** Processes any an interrupt fault. */
+ void processInterrupts(Fault interrupt);
+
+ /** Halts the CPU. */
+ void halt() { panic("Halt not implemented!\n"); }
+
/** Update the Virt and Phys ports of all ThreadContexts to
* reflect change in memory connections. */
void updateMemPorts();
@@ -424,6 +416,24 @@ class FullO3CPU : public BaseO3CPU
#endif
/** Register accessors. Index refers to the physical register index. */
+
+ /** Reads a miscellaneous register. */
+ TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
+
+ /** Reads a misc. register, including any side effects the read
+ * might have as defined by the architecture.
+ */
+ TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
+
+ /** Sets a miscellaneous register. */
+ void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid);
+
+ /** Sets a misc. register, including any side effects the write
+ * might have as defined by the architecture.
+ */
+ void setMiscReg(int misc_reg, const TheISA::MiscReg &val,
+ unsigned tid);
+
uint64_t readIntReg(int reg_idx);
TheISA::FloatReg readFloatReg(int reg_idx);
@@ -495,6 +505,12 @@ class FullO3CPU : public BaseO3CPU
/** Sets the commit next micro PC of a specific thread. */
void setNextMicroPC(Addr val, unsigned tid);
+ /** Initiates a squash of all in-flight instructions for a given
+ * thread. The source of the squash is an external update of
+ * state through the TC.
+ */
+ void squashFromTC(unsigned tid);
+
/** Function to add instruction onto the head of the list of the
* instructions. Used when new instructions are fetched.
*/
@@ -528,6 +544,11 @@ class FullO3CPU : public BaseO3CPU
void dumpInsts();
public:
+#ifndef NDEBUG
+ /** Count of total number of dynamic instructions in flight. */
+ int instcount;
+#endif
+
/** List of all the instructions in flight. */
std::list<DynInstPtr> instList;
@@ -648,6 +669,10 @@ class FullO3CPU : public BaseO3CPU
/** Wakes the CPU, rescheduling the CPU if it's not already active. */
void wakeCPU();
+#if FULL_SYSTEM
+ virtual void wakeup();
+#endif
+
/** Gets a free thread id. Use if thread ids change across system. */
int getFreeTid();
@@ -710,14 +735,33 @@ class FullO3CPU : public BaseO3CPU
/** Available thread ids in the cpu*/
std::vector<unsigned> tids;
+ /** CPU read function, forwards read to LSQ. */
+ template <class T>
+ Fault read(RequestPtr &req, T &data, int load_idx)
+ {
+ return this->iew.ldstQueue.read(req, data, load_idx);
+ }
+
+ /** CPU write function, forwards write to LSQ. */
+ template <class T>
+ Fault write(RequestPtr &req, T &data, int store_idx)
+ {
+ return this->iew.ldstQueue.write(req, data, store_idx);
+ }
+
+ Addr lockAddr;
+
+ /** Temporary fix for the lock flag, works in the UP case. */
+ bool lockFlag;
+
/** Stat for total number of times the CPU is descheduled. */
- Stats::Scalar<> timesIdled;
+ Stats::Scalar timesIdled;
/** Stat for total number of cycles the CPU spends descheduled. */
- Stats::Scalar<> idleCycles;
+ Stats::Scalar idleCycles;
/** Stat for the number of committed instructions per thread. */
- Stats::Vector<> committedInsts;
+ Stats::Vector committedInsts;
/** Stat for the total number of committed instructions. */
- Stats::Scalar<> totalCommittedInsts;
+ Stats::Scalar totalCommittedInsts;
/** Stat for the CPI per thread. */
Stats::Formula cpi;
/** Stat for the total CPI. */
diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/cpu_builder.cc
index 6d61501ac..77d7091ad 100644
--- a/src/cpu/o3/alpha/thread_context.hh
+++ b/src/cpu/o3/cpu_builder.cc
@@ -28,49 +28,51 @@
* Authors: Kevin Lim
*/
-#include "arch/alpha/types.hh"
-#include "cpu/o3/thread_context.hh"
+#include <string>
-template <class Impl>
-class AlphaTC : public O3ThreadContext<Impl>
+#include "config/full_system.hh"
+#include "config/use_checker.hh"
+#include "cpu/o3/cpu.hh"
+#include "cpu/o3/impl.hh"
+#include "params/DerivO3CPU.hh"
+
+class DerivO3CPU : public FullO3CPU<O3CPUImpl>
{
public:
+ DerivO3CPU(DerivO3CPUParams *p)
+ : FullO3CPU<O3CPUImpl>(p)
+ { }
+};
+
+DerivO3CPU *
+DerivO3CPUParams::create()
+{
#if FULL_SYSTEM
- /** Returns pointer to the quiesce event. */
- virtual EndQuiesceEvent *getQuiesceEvent()
- {
- return this->thread->quiesceEvent;
- }
-#endif
+ // Full-system only supports a single thread for the moment.
+ int actual_num_threads = 1;
+#else
+ // In non-full-system mode, we infer the number of threads from
+ // the workload if it's not explicitly specified.
+ int actual_num_threads =
+ (numThreads >= workload.size()) ? numThreads : workload.size();
- virtual uint64_t readNextNPC()
- {
- return this->readNextPC() + sizeof(TheISA::MachInst);
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
}
+#endif
- virtual void setNextNPC(uint64_t val)
- {
- panic("Alpha has no NextNPC!");
- }
+ numThreads = actual_num_threads;
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Alpha!"); }
+ // Default smtFetchPolicy to "RoundRobin", if necessary.
+ std::string round_robin_policy = "RoundRobin";
+ std::string single_thread = "SingleThread";
+ if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
+ smtFetchPolicy = round_robin_policy;
+ else
+ smtFetchPolicy = smtFetchPolicy;
- /** This function exits the thread context in the CPU and returns
- * 1 if the CPU has no more active threads (meaning it's OK to exit);
- * Used in syscall-emulation mode when a thread executes the 'exit'
- * syscall.
- */
- virtual int exit()
- {
- this->deallocate();
+ instShiftAmt = 2;
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
- }
-};
+ return new DerivO3CPU(this);
+}
diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh
index 32a0adcf1..c06c9a201 100644
--- a/src/cpu/o3/cpu_policy.hh
+++ b/src/cpu/o3/cpu_policy.hh
@@ -65,7 +65,7 @@ struct SimpleCPUPolicy
/** Typedef for the branch prediction unit (which includes the BP,
* RAS, and BTB).
*/
- typedef BPredUnit<Impl> BPredUnit;
+ typedef ::BPredUnit<Impl> BPredUnit;
/** Typedef for the register file. Most classes assume a unified
* physical register file.
*/
@@ -75,15 +75,15 @@ struct SimpleCPUPolicy
/** Typedef for the rename map. */
typedef SimpleRenameMap RenameMap;
/** Typedef for the ROB. */
- typedef ROB<Impl> ROB;
+ typedef ::ROB<Impl> ROB;
/** Typedef for the instruction queue/scheduler. */
typedef InstructionQueue<Impl> IQ;
/** Typedef for the memory dependence unit. */
- typedef MemDepUnit<StoreSet, Impl> MemDepUnit;
+ typedef ::MemDepUnit<StoreSet, Impl> MemDepUnit;
/** Typedef for the LSQ. */
- typedef LSQ<Impl> LSQ;
+ typedef ::LSQ<Impl> LSQ;
/** Typedef for the thread-specific LSQ units. */
- typedef LSQUnit<Impl> LSQUnit;
+ typedef ::LSQUnit<Impl> LSQUnit;
/** Typedef for fetch. */
typedef DefaultFetch<Impl> Fetch;
@@ -109,7 +109,7 @@ struct SimpleCPUPolicy
typedef DefaultIEWDefaultCommit<Impl> IEWStruct;
/** The struct for communication within the IEW stage. */
- typedef IssueStruct<Impl> IssueStruct;
+ typedef ::IssueStruct<Impl> IssueStruct;
/** The struct for all backwards communication. */
typedef TimeBufStruct<Impl> TimeStruct;
diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh
index 3e82033ca..294b5b623 100644
--- a/src/cpu/o3/decode.hh
+++ b/src/cpu/o3/decode.hh
@@ -36,6 +36,8 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
+class DerivO3CPUParams;
+
/**
* DefaultDecode class handles both single threaded and SMT
* decode. Its width is specified by the parameters; each cycles it
@@ -50,7 +52,6 @@ class DefaultDecode
// Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol CPUPol;
// Typedefs from the CPU policy.
@@ -86,7 +87,7 @@ class DefaultDecode
public:
/** DefaultDecode constructor. */
- DefaultDecode(O3CPU *_cpu, Params *params);
+ DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of decode. */
std::string name() const;
@@ -287,27 +288,27 @@ class DefaultDecode
/** Stat for total number of idle cycles. */
- Stats::Scalar<> decodeIdleCycles;
+ Stats::Scalar decodeIdleCycles;
/** Stat for total number of blocked cycles. */
- Stats::Scalar<> decodeBlockedCycles;
+ Stats::Scalar decodeBlockedCycles;
/** Stat for total number of normal running cycles. */
- Stats::Scalar<> decodeRunCycles;
+ Stats::Scalar decodeRunCycles;
/** Stat for total number of unblocking cycles. */
- Stats::Scalar<> decodeUnblockCycles;
+ Stats::Scalar decodeUnblockCycles;
/** Stat for total number of squashing cycles. */
- Stats::Scalar<> decodeSquashCycles;
+ Stats::Scalar decodeSquashCycles;
/** Stat for number of times a branch is resolved at decode. */
- Stats::Scalar<> decodeBranchResolved;
+ Stats::Scalar decodeBranchResolved;
/** Stat for number of times a branch mispredict is detected. */
- Stats::Scalar<> decodeBranchMispred;
+ Stats::Scalar decodeBranchMispred;
/** Stat for number of times decode detected a non-control instruction
* incorrectly predicted as a branch.
*/
- Stats::Scalar<> decodeControlMispred;
+ Stats::Scalar decodeControlMispred;
/** Stat for total number of decoded instructions. */
- Stats::Scalar<> decodeDecodedInsts;
+ Stats::Scalar decodeDecodedInsts;
/** Stat for total number of squashed instructions. */
- Stats::Scalar<> decodeSquashedInsts;
+ Stats::Scalar decodeSquashedInsts;
};
#endif // __CPU_O3_DECODE_HH__
diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh
index ce6738456..015bc8d7f 100644
--- a/src/cpu/o3/decode_impl.hh
+++ b/src/cpu/o3/decode_impl.hh
@@ -30,15 +30,17 @@
#include "cpu/o3/decode.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
-DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, Params *params)
+DefaultDecode<Impl>::DefaultDecode(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
renameToDecodeDelay(params->renameToDecodeDelay),
iewToDecodeDelay(params->iewToDecodeDelay),
commitToDecodeDelay(params->commitToDecodeDelay),
fetchToDecodeDelay(params->fetchToDecodeDelay),
decodeWidth(params->decodeWidth),
- numThreads(params->numberOfThreads)
+ numThreads(params->numThreads)
{
_status = Inactive;
diff --git a/src/cpu/o3/sparc/dyn_inst.cc b/src/cpu/o3/dyn_inst.cc
index 984b58f4b..d828ef1b0 100644
--- a/src/cpu/o3/sparc/dyn_inst.cc
+++ b/src/cpu/o3/dyn_inst.cc
@@ -28,9 +28,9 @@
* Authors: Gabe Black
*/
-#include "cpu/o3/sparc/dyn_inst_impl.hh"
-#include "cpu/o3/sparc/impl.hh"
+#include "cpu/o3/dyn_inst_impl.hh"
+#include "cpu/o3/impl.hh"
-// Force instantiation of SparcDynInst for all the implementations that
+// Force instantiation of BaseO3DynInst for all the implementations that
// are needed.
-template class SparcDynInst<SparcSimpleImpl>;
+template class BaseO3DynInst<O3CPUImpl>;
diff --git a/src/cpu/o3/dyn_inst.hh b/src/cpu/o3/dyn_inst.hh
index a1f9e0591..292547b6b 100644
--- a/src/cpu/o3/dyn_inst.hh
+++ b/src/cpu/o3/dyn_inst.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * 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
@@ -25,36 +25,266 @@
* (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
+ * Authors: Kevin Lim
*/
#ifndef __CPU_O3_DYN_INST_HH__
#define __CPU_O3_DYN_INST_HH__
-#include "arch/isa_specific.hh"
-
-#if THE_ISA == ALPHA_ISA
- template <class Impl> class AlphaDynInst;
- struct AlphaSimpleImpl;
- typedef AlphaDynInst<AlphaSimpleImpl> O3DynInst;
-#elif THE_ISA == MIPS_ISA
- template <class Impl> class MipsDynInst;
- struct MipsSimpleImpl;
- typedef MipsDynInst<MipsSimpleImpl> O3DynInst;
-#elif THE_ISA == SPARC_ISA
- template <class Impl> class SparcDynInst;
- struct SparcSimpleImpl;
- typedef SparcDynInst<SparcSimpleImpl> O3DynInst;
-#elif THE_ISA == X86_ISA
- template <class Impl> class X86DynInst;
- struct X86SimpleImpl;
- typedef X86DynInst<X86SimpleImpl> O3DynInst;
-#elif THE_ISA == ARM_ISA
- template <class Impl> class ArmDynInst;
- struct ArmSimpleImpl;
- typedef ArmDynInst<ArmSimpleImpl> O3DynInst;
+#include "arch/isa_traits.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/cpu.hh"
+#include "cpu/o3/isa_specific.hh"
+
+class Packet;
+
+/**
+ * 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 BaseO3DynInst : public BaseDynInst<Impl>
+{
+ public:
+ /** Typedef for the CPU. */
+ typedef typename Impl::O3CPU O3CPU;
+
+ /** 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;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ /** 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. */
+ BaseO3DynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu);
+
+ /** BaseDynInst constructor given a binary instruction. */
+ BaseO3DynInst(ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu);
+
+ /** BaseDynInst constructor given a static inst pointer. */
+ BaseO3DynInst(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(PacketPtr pkt);
+
+ private:
+ /** Initializes variables. */
+ void initVars();
+
+ public:
+ /** Reads a miscellaneous register. */
+ MiscReg readMiscRegNoEffect(int misc_reg)
+ {
+ return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
+ }
+
+ /** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return this->cpu->readMiscReg(misc_reg, this->threadNumber);
+ }
+
+ /** Sets a misc. register. */
+ void setMiscRegNoEffect(int misc_reg, const MiscReg &val)
+ {
+ this->instResult.integer = val;
+ return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
+ }
+
+ /** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+ void setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ return this->cpu->setMiscReg(misc_reg, val,
+ this->threadNumber);
+ }
+
+ /** Reads a miscellaneous register. */
+ TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx)
+ {
+ return this->cpu->readMiscRegNoEffect(
+ si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ this->threadNumber);
+ }
+
+ /** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
+ TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readMiscReg(
+ si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ this->threadNumber);
+ }
+
+ /** Sets a misc. register. */
+ void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
+ {
+ this->instResult.integer = val;
+ return this->cpu->setMiscRegNoEffect(
+ si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ val, this->threadNumber);
+ }
+
+ /** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
+ void setMiscRegOperand(const StaticInst *si, int idx,
+ const MiscReg &val)
+ {
+ return this->cpu->setMiscReg(
+ si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
+ val, this->threadNumber);
+ }
+
+#if FULL_SYSTEM
+ /** Calls hardware return from error interrupt. */
+ Fault hwrei();
+ /** Traps to handle specified fault. */
+ void trap(Fault fault);
+ bool simPalCheck(int palFunc);
#else
- #error "O3DynInst not defined for this ISA"
+ /** Calls a syscall. */
+ void syscall(int64_t callnum);
#endif
-#endif // __CPU_O3_DYN_INST_HH__
+ 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 readIntRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readIntReg(this->_srcRegIdx[idx]);
+ }
+
+ FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
+ {
+ return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
+ }
+
+ FloatReg readFloatRegOperand(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
+ }
+
+ FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
+ int width)
+ {
+ return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
+ }
+
+ FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
+ {
+ return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
+ }
+
+ /** @todo: Make results into arrays so they can handle multiple dest
+ * registers.
+ */
+ void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
+ {
+ this->cpu->setIntReg(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
+ }
+
+ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
+ int width)
+ {
+ this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
+ BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
+ }
+
+ void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
+ {
+ this->cpu->setFloatReg(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
+ }
+
+ void setFloatRegOperandBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+ {
+ this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
+ BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
+ }
+
+ void setFloatRegOperandBits(const StaticInst *si, int idx,
+ FloatRegBits val)
+ {
+ this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
+ BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
+ }
+
+#if THE_ISA == MIPS_ISA
+ uint64_t readRegOtherThread(int misc_reg)
+ {
+ panic("MIPS MT not defined for O3 CPU.\n");
+ return 0;
+ }
+
+ void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
+ {
+ panic("MIPS MT not defined for O3 CPU.\n");
+ }
+#endif
+
+ 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/src/cpu/o3/alpha/dyn_inst_impl.hh b/src/cpu/o3/dyn_inst_impl.hh
index 6dfe0ccdd..8d391ceaf 100644
--- a/src/cpu/o3/alpha/dyn_inst_impl.hh
+++ b/src/cpu/o3/dyn_inst_impl.hh
@@ -28,34 +28,35 @@
* Authors: Kevin Lim
*/
-#include "cpu/o3/alpha/dyn_inst.hh"
+#include "base/cp_annotate.hh"
+#include "cpu/o3/dyn_inst.hh"
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
+BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr staticInst,
+ Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC,
+ Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu)
: BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
{
initVars();
}
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC,
- Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
+BaseO3DynInst<Impl>::BaseO3DynInst(ExtMachInst inst,
+ Addr PC, Addr NPC, Addr microPC,
+ Addr Pred_PC, Addr Pred_NPC,
+ Addr Pred_MicroPC,
+ InstSeqNum seq_num, O3CPU *cpu)
: BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
+ Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
{
initVars();
}
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
+BaseO3DynInst<Impl>::BaseO3DynInst(StaticInstPtr &_staticInst)
: BaseDynInst<Impl>(_staticInst)
{
initVars();
@@ -63,7 +64,7 @@ AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
template <class Impl>
void
-AlphaDynInst<Impl>::initVars()
+BaseO3DynInst<Impl>::initVars()
{
// Make sure to have the renamed register entries set to the same
// as the normal register entries. It will allow the IQ to work
@@ -80,7 +81,7 @@ AlphaDynInst<Impl>::initVars()
template <class Impl>
Fault
-AlphaDynInst<Impl>::execute()
+BaseO3DynInst<Impl>::execute()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
@@ -98,7 +99,7 @@ AlphaDynInst<Impl>::execute()
template <class Impl>
Fault
-AlphaDynInst<Impl>::initiateAcc()
+BaseO3DynInst<Impl>::initiateAcc()
{
// @todo: Pretty convoluted way to avoid squashing from happening
// when using the TC during an instruction's execution
@@ -116,7 +117,7 @@ AlphaDynInst<Impl>::initiateAcc()
template <class Impl>
Fault
-AlphaDynInst<Impl>::completeAcc(PacketPtr pkt)
+BaseO3DynInst<Impl>::completeAcc(PacketPtr pkt)
{
this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
@@ -126,8 +127,9 @@ AlphaDynInst<Impl>::completeAcc(PacketPtr pkt)
#if FULL_SYSTEM
template <class Impl>
Fault
-AlphaDynInst<Impl>::hwrei()
+BaseO3DynInst<Impl>::hwrei()
{
+#if THE_ISA == ALPHA_ISA
// Can only do a hwrei when in pal mode.
if (!(this->readPC() & 0x3))
return new AlphaISA::UnimplementedOpcodeFault;
@@ -135,33 +137,50 @@ AlphaDynInst<Impl>::hwrei()
// Set the next PC based on the value of the EXC_ADDR IPR.
this->setNextPC(this->cpu->readMiscRegNoEffect(AlphaISA::IPR_EXC_ADDR,
this->threadNumber));
+ if (CPA::available()) {
+ ThreadContext *tc = this->cpu->tcBase(this->threadNumber);
+ CPA::cpa()->swAutoBegin(tc, this->readNextPC());
+ }
// Tell CPU to clear any state it needs to if a hwrei is taken.
this->cpu->hwrei(this->threadNumber);
+#else
+#endif
// FIXME: XXX check for interrupts? XXX
return NoFault;
}
template <class Impl>
void
-AlphaDynInst<Impl>::trap(Fault fault)
+BaseO3DynInst<Impl>::trap(Fault fault)
{
this->cpu->trap(fault, this->threadNumber);
}
template <class Impl>
bool
-AlphaDynInst<Impl>::simPalCheck(int palFunc)
+BaseO3DynInst<Impl>::simPalCheck(int palFunc)
{
+#if THE_ISA != ALPHA_ISA
+ panic("simPalCheck called, but PAL only exists in Alpha!\n");
+#endif
return this->cpu->simPalCheck(palFunc, this->threadNumber);
}
#else
template <class Impl>
void
-AlphaDynInst<Impl>::syscall(int64_t callnum)
+BaseO3DynInst<Impl>::syscall(int64_t callnum)
{
+ // HACK: check CPU's nextPC before and after syscall. If it
+ // changes, update this instruction's nextPC because the syscall
+ // must have changed the nextPC.
+ Addr cpu_next_pc = this->cpu->readNextPC(this->threadNumber);
this->cpu->syscall(callnum, this->threadNumber);
+ Addr new_next_pc = this->cpu->readNextPC(this->threadNumber);
+ if (cpu_next_pc != new_next_pc) {
+ this->setNextPC(new_next_pc);
+ }
}
#endif
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
index d954bd1e7..08ccb094b 100644
--- a/src/cpu/o3/fetch.hh
+++ b/src/cpu/o3/fetch.hh
@@ -41,6 +41,8 @@
#include "mem/port.hh"
#include "sim/eventq.hh"
+class DerivO3CPUParams;
+
/**
* DefaultFetch class handles both single threaded and SMT fetch. Its
* width is specified by the parameters; each cycle it tries to fetch
@@ -58,7 +60,6 @@ class DefaultFetch
typedef typename Impl::DynInst DynInst;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
/** Typedefs from the CPU policy. */
typedef typename CPUPol::BPredUnit BPredUnit;
@@ -81,7 +82,7 @@ class DefaultFetch
public:
/** Default constructor. */
IcachePort(DefaultFetch<Impl> *_fetch)
- : Port(_fetch->name() + "-iport"), fetch(_fetch)
+ : Port(_fetch->name() + "-iport", _fetch->cpu), fetch(_fetch)
{ }
bool snoopRangeSent;
@@ -160,7 +161,7 @@ class DefaultFetch
public:
/** DefaultFetch constructor. */
- DefaultFetch(O3CPU *_cpu, Params *params);
+ DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of fetch. */
std::string name() const;
@@ -447,33 +448,33 @@ class DefaultFetch
// @todo: Consider making these vectors and tracking on a per thread basis.
/** Stat for total number of cycles stalled due to an icache miss. */
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
/** Stat for total number of fetched instructions. */
- Stats::Scalar<> fetchedInsts;
+ Stats::Scalar fetchedInsts;
/** Total number of fetched branches. */
- Stats::Scalar<> fetchedBranches;
+ Stats::Scalar fetchedBranches;
/** Stat for total number of predicted branches. */
- Stats::Scalar<> predictedBranches;
+ Stats::Scalar predictedBranches;
/** Stat for total number of cycles spent fetching. */
- Stats::Scalar<> fetchCycles;
+ Stats::Scalar fetchCycles;
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> fetchSquashCycles;
+ Stats::Scalar fetchSquashCycles;
/** Stat for total number of cycles spent blocked due to other stages in
* the pipeline.
*/
- Stats::Scalar<> fetchIdleCycles;
+ Stats::Scalar fetchIdleCycles;
/** Total number of cycles spent blocked. */
- Stats::Scalar<> fetchBlockedCycles;
+ Stats::Scalar fetchBlockedCycles;
/** Total number of cycles spent in any other state. */
- Stats::Scalar<> fetchMiscStallCycles;
+ Stats::Scalar fetchMiscStallCycles;
/** Stat for total number of fetched cache lines. */
- Stats::Scalar<> fetchedCacheLines;
+ Stats::Scalar fetchedCacheLines;
/** Total number of outstanding icache accesses that were dropped
* due to a squash.
*/
- Stats::Scalar<> fetchIcacheSquashes;
+ Stats::Scalar fetchIcacheSquashes;
/** Distribution of number of instructions fetched each cycle. */
- Stats::Distribution<> fetchNisnDist;
+ Stats::Distribution fetchNisnDist;
/** Rate of how often fetch was idle. */
Stats::Formula idleRate;
/** Number of branch fetches per cycle. */
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index 7d344fa33..79a4f2b7a 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -51,6 +51,8 @@
#include "sim/system.hh"
#endif // FULL_SYSTEM
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
void
DefaultFetch<Impl>::IcachePort::setPeer(Port *port)
@@ -111,7 +113,7 @@ DefaultFetch<Impl>::IcachePort::recvRetry()
}
template<class Impl>
-DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
+DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
branchPred(params),
predecoder(NULL),
@@ -123,14 +125,16 @@ DefaultFetch<Impl>::DefaultFetch(O3CPU *_cpu, Params *params)
cacheBlocked(false),
retryPkt(NULL),
retryTid(-1),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
numFetchingThreads(params->smtNumFetchingThreads),
interruptPending(false),
drainPending(false),
switchedOut(false)
{
if (numThreads > Impl::MaxThreads)
- fatal("numThreads is not a valid value\n");
+ fatal("numThreads (%d) is larger than compiled limit (%d),\n"
+ "\tincrease MaxThreads in src/cpu/o3/impl.hh\n",
+ numThreads, static_cast<int>(Impl::MaxThreads));
// Set fetch stage's status to inactive.
_status = Inactive;
@@ -360,7 +364,7 @@ template<class Impl>
void
DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
{
- unsigned tid = pkt->req->getThreadNum();
+ unsigned tid = pkt->req->threadId();
DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
@@ -591,12 +595,13 @@ DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid
// Set the appropriate read size and flags as well.
// Build request here.
RequestPtr mem_req = new Request(tid, block_PC, cacheBlkSize, 0,
- fetch_PC, cpu->readCpuId(), tid);
+ fetch_PC, cpu->thread[tid]->contextId(),
+ tid);
memReq[tid] = mem_req;
// Translate the instruction request.
- fault = cpu->translateInstReq(mem_req, cpu->thread[tid]);
+ fault = cpu->itb->translateAtomic(mem_req, cpu->thread[tid]->getTC());
// In the case of faults, the fetch stage may need to stall and wait
// for the ITB miss to be handled.
diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh
index 457e2a024..3458f09d6 100644
--- a/src/cpu/o3/iew.hh
+++ b/src/cpu/o3/iew.hh
@@ -41,6 +41,7 @@
#include "cpu/o3/scoreboard.hh"
#include "cpu/o3/lsq.hh"
+class DerivO3CPUParams;
class FUPool;
/**
@@ -70,7 +71,6 @@ class DefaultIEW
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
typedef typename CPUPol::IQ IQ;
typedef typename CPUPol::RenameMap RenameMap;
@@ -115,7 +115,7 @@ class DefaultIEW
public:
/** Constructs a DefaultIEW with the given parameters. */
- DefaultIEW(O3CPU *_cpu, Params *params);
+ DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of the DefaultIEW stage. */
std::string name() const;
@@ -208,6 +208,9 @@ class DefaultIEW
/** Returns if the LSQ has any stores to writeback. */
bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); }
+ /** Returns if the LSQ has any stores to writeback. */
+ bool hasStoresToWB(unsigned tid) { return ldstQueue.hasStoresToWB(tid); }
+
void incrWb(InstSeqNum &sn)
{
if (++wbOutstanding == wbMax)
@@ -462,69 +465,69 @@ class DefaultIEW
bool switchedOut;
/** Stat for total number of idle cycles. */
- Stats::Scalar<> iewIdleCycles;
+ Stats::Scalar iewIdleCycles;
/** Stat for total number of squashing cycles. */
- Stats::Scalar<> iewSquashCycles;
+ Stats::Scalar iewSquashCycles;
/** Stat for total number of blocking cycles. */
- Stats::Scalar<> iewBlockCycles;
+ Stats::Scalar iewBlockCycles;
/** Stat for total number of unblocking cycles. */
- Stats::Scalar<> iewUnblockCycles;
+ Stats::Scalar iewUnblockCycles;
/** Stat for total number of instructions dispatched. */
- Stats::Scalar<> iewDispatchedInsts;
+ Stats::Scalar iewDispatchedInsts;
/** Stat for total number of squashed instructions dispatch skips. */
- Stats::Scalar<> iewDispSquashedInsts;
+ Stats::Scalar iewDispSquashedInsts;
/** Stat for total number of dispatched load instructions. */
- Stats::Scalar<> iewDispLoadInsts;
+ Stats::Scalar iewDispLoadInsts;
/** Stat for total number of dispatched store instructions. */
- Stats::Scalar<> iewDispStoreInsts;
+ Stats::Scalar iewDispStoreInsts;
/** Stat for total number of dispatched non speculative instructions. */
- Stats::Scalar<> iewDispNonSpecInsts;
+ Stats::Scalar iewDispNonSpecInsts;
/** Stat for number of times the IQ becomes full. */
- Stats::Scalar<> iewIQFullEvents;
+ Stats::Scalar iewIQFullEvents;
/** Stat for number of times the LSQ becomes full. */
- Stats::Scalar<> iewLSQFullEvents;
+ Stats::Scalar iewLSQFullEvents;
/** Stat for total number of memory ordering violation events. */
- Stats::Scalar<> memOrderViolationEvents;
+ Stats::Scalar memOrderViolationEvents;
/** Stat for total number of incorrect predicted taken branches. */
- Stats::Scalar<> predictedTakenIncorrect;
+ Stats::Scalar predictedTakenIncorrect;
/** Stat for total number of incorrect predicted not taken branches. */
- Stats::Scalar<> predictedNotTakenIncorrect;
+ Stats::Scalar predictedNotTakenIncorrect;
/** Stat for total number of mispredicted branches detected at execute. */
Stats::Formula branchMispredicts;
/** Stat for total number of executed instructions. */
- Stats::Scalar<> iewExecutedInsts;
+ Stats::Scalar iewExecutedInsts;
/** Stat for total number of executed load instructions. */
- Stats::Vector<> iewExecLoadInsts;
+ Stats::Vector iewExecLoadInsts;
/** Stat for total number of executed store instructions. */
-// Stats::Scalar<> iewExecStoreInsts;
+// Stats::Scalar iewExecStoreInsts;
/** Stat for total number of squashed instructions skipped at execute. */
- Stats::Scalar<> iewExecSquashedInsts;
+ Stats::Scalar iewExecSquashedInsts;
/** Number of executed software prefetches. */
- Stats::Vector<> iewExecutedSwp;
+ Stats::Vector iewExecutedSwp;
/** Number of executed nops. */
- Stats::Vector<> iewExecutedNop;
+ Stats::Vector iewExecutedNop;
/** Number of executed meomory references. */
- Stats::Vector<> iewExecutedRefs;
+ Stats::Vector iewExecutedRefs;
/** Number of executed branches. */
- Stats::Vector<> iewExecutedBranches;
+ Stats::Vector iewExecutedBranches;
/** Number of executed store instructions. */
Stats::Formula iewExecStoreInsts;
/** Number of instructions executed per cycle. */
Stats::Formula iewExecRate;
/** Number of instructions sent to commit. */
- Stats::Vector<> iewInstsToCommit;
+ Stats::Vector iewInstsToCommit;
/** Number of instructions that writeback. */
- Stats::Vector<> writebackCount;
+ Stats::Vector writebackCount;
/** Number of instructions that wake consumers. */
- Stats::Vector<> producerInst;
+ Stats::Vector producerInst;
/** Number of instructions that wake up from producers. */
- Stats::Vector<> consumerInst;
+ Stats::Vector consumerInst;
/** Number of instructions that were delayed in writing back due
* to resource contention.
*/
- Stats::Vector<> wbPenalized;
+ Stats::Vector wbPenalized;
/** Number of instructions per cycle written back. */
Stats::Formula wbRate;
/** Average number of woken instructions per writeback. */
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
index 84d10e966..1daecd669 100644
--- a/src/cpu/o3/iew_impl.hh
+++ b/src/cpu/o3/iew_impl.hh
@@ -37,9 +37,10 @@
#include "base/timebuf.hh"
#include "cpu/o3/fu_pool.hh"
#include "cpu/o3/iew.hh"
+#include "params/DerivO3CPU.hh"
template<class Impl>
-DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params)
+DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, DerivO3CPUParams *params)
: issueToExecQueue(params->backComSize, params->forwardComSize),
cpu(_cpu),
instQueue(_cpu, this, params),
@@ -52,7 +53,7 @@ DefaultIEW<Impl>::DefaultIEW(O3CPU *_cpu, Params *params)
issueWidth(params->issueWidth),
wbOutstanding(0),
wbWidth(params->wbWidth),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
switchedOut(false)
{
_status = Active;
diff --git a/src/cpu/o3/sparc/impl.hh b/src/cpu/o3/impl.hh
index 0a970c2f0..4b29b4daa 100644
--- a/src/cpu/o3/sparc/impl.hh
+++ b/src/cpu/o3/impl.hh
@@ -25,24 +25,23 @@
* (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
+ * Authors: Kevin Lim
*/
-#ifndef __CPU_O3_SPARC_IMPL_HH__
-#define __CPU_O3_SPARC_IMPL_HH__
+#ifndef __CPU_O3_IMPL_HH__
+#define __CPU_O3_IMPL_HH__
-#include "arch/sparc/isa_traits.hh"
+#include "arch/isa_traits.hh"
-#include "cpu/o3/sparc/params.hh"
#include "cpu/o3/cpu_policy.hh"
// Forward declarations.
template <class Impl>
-class SparcDynInst;
+class BaseO3DynInst;
template <class Impl>
-class SparcO3CPU;
+class FullO3CPU;
/** Implementation specific struct that defines several key types to the
* CPU, the stages within the CPU, the time buffers, and the DynInst.
@@ -52,16 +51,16 @@ class SparcO3CPU;
* This is one of the key things that must be defined for each hardware
* specific CPU implementation.
*/
-struct SparcSimpleImpl
+struct O3CPUImpl
{
/** The type of MachInst. */
typedef TheISA::MachInst MachInst;
/** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<SparcSimpleImpl> CPUPol;
+ typedef SimpleCPUPolicy<O3CPUImpl> CPUPol;
/** The DynInst type to be used. */
- typedef SparcDynInst<SparcSimpleImpl> DynInst;
+ typedef BaseO3DynInst<O3CPUImpl> DynInst;
/** The refcounted DynInst pointer to be used. In most cases this is
* what should be used, and not DynInst *.
@@ -69,7 +68,7 @@ struct SparcSimpleImpl
typedef RefCountingPtr<DynInst> DynInstPtr;
/** The O3CPU type to be used. */
- typedef SparcO3CPU<SparcSimpleImpl> O3CPU;
+ typedef FullO3CPU<O3CPUImpl> O3CPU;
/** Same typedef, but for CPUType. BaseDynInst may not always use
* an O3 CPU, so it's clearer to call it CPUType instead in that
@@ -77,16 +76,10 @@ struct SparcSimpleImpl
*/
typedef O3CPU CPUType;
- /** The Params to be passed to each stage. */
- typedef SparcSimpleParams Params;
-
enum {
MaxWidth = 8,
MaxThreads = 4
};
};
-/** The O3Impl to be used. */
-typedef SparcSimpleImpl O3CPUImpl;
-
#endif // __CPU_O3_SPARC_IMPL_HH__
diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh
index d0f503977..0c3f44436 100644
--- a/src/cpu/o3/inst_queue.hh
+++ b/src/cpu/o3/inst_queue.hh
@@ -41,8 +41,10 @@
#include "cpu/inst_seq.hh"
#include "cpu/o3/dep_graph.hh"
#include "cpu/op_class.hh"
+#include "sim/eventq.hh"
#include "sim/host.hh"
+class DerivO3CPUParams;
class FUPool;
class MemInterface;
@@ -70,7 +72,6 @@ class InstructionQueue
//Typedefs from the Impl.
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::Params Params;
typedef typename Impl::CPUPol::IEW IEW;
typedef typename Impl::CPUPol::MemDepUnit MemDepUnit;
@@ -110,7 +111,7 @@ class InstructionQueue
};
/** Constructs an IQ. */
- InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params);
+ InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params);
/** Destructs the IQ. */
~InstructionQueue();
@@ -442,58 +443,58 @@ class InstructionQueue
void dumpInsts();
/** Stat for number of instructions added. */
- Stats::Scalar<> iqInstsAdded;
+ Stats::Scalar iqInstsAdded;
/** Stat for number of non-speculative instructions added. */
- Stats::Scalar<> iqNonSpecInstsAdded;
+ Stats::Scalar iqNonSpecInstsAdded;
- Stats::Scalar<> iqInstsIssued;
+ Stats::Scalar iqInstsIssued;
/** Stat for number of integer instructions issued. */
- Stats::Scalar<> iqIntInstsIssued;
+ Stats::Scalar iqIntInstsIssued;
/** Stat for number of floating point instructions issued. */
- Stats::Scalar<> iqFloatInstsIssued;
+ Stats::Scalar iqFloatInstsIssued;
/** Stat for number of branch instructions issued. */
- Stats::Scalar<> iqBranchInstsIssued;
+ Stats::Scalar iqBranchInstsIssued;
/** Stat for number of memory instructions issued. */
- Stats::Scalar<> iqMemInstsIssued;
+ Stats::Scalar iqMemInstsIssued;
/** Stat for number of miscellaneous instructions issued. */
- Stats::Scalar<> iqMiscInstsIssued;
+ Stats::Scalar iqMiscInstsIssued;
/** Stat for number of squashed instructions that were ready to issue. */
- Stats::Scalar<> iqSquashedInstsIssued;
+ Stats::Scalar iqSquashedInstsIssued;
/** Stat for number of squashed instructions examined when squashing. */
- Stats::Scalar<> iqSquashedInstsExamined;
+ Stats::Scalar iqSquashedInstsExamined;
/** Stat for number of squashed instruction operands examined when
* squashing.
*/
- Stats::Scalar<> iqSquashedOperandsExamined;
+ Stats::Scalar iqSquashedOperandsExamined;
/** Stat for number of non-speculative instructions removed due to a squash.
*/
- Stats::Scalar<> iqSquashedNonSpecRemoved;
+ Stats::Scalar iqSquashedNonSpecRemoved;
// Also include number of instructions rescheduled and replayed.
/** Distribution of number of instructions in the queue.
* @todo: Need to create struct to track the entry time for each
* instruction. */
-// Stats::VectorDistribution<> queueResDist;
+// Stats::VectorDistribution queueResDist;
/** Distribution of the number of instructions issued. */
- Stats::Distribution<> numIssuedDist;
+ Stats::Distribution numIssuedDist;
/** Distribution of the cycles it takes to issue an instruction.
* @todo: Need to create struct to track the ready time for each
* instruction. */
-// Stats::VectorDistribution<> issueDelayDist;
+// Stats::VectorDistribution issueDelayDist;
/** Number of times an instruction could not be issued because a
* FU was busy.
*/
- Stats::Vector<> statFuBusy;
-// Stats::Vector<> dist_unissued;
+ Stats::Vector statFuBusy;
+// Stats::Vector dist_unissued;
/** Stat for total number issued for each instruction type. */
- Stats::Vector2d<> statIssuedInstType;
+ Stats::Vector2d statIssuedInstType;
/** Number of instructions issued per cycle. */
Stats::Formula issueRate;
/** Number of times the FU was busy. */
- Stats::Vector<> fuBusy;
+ Stats::Vector fuBusy;
/** Number of times the FU was busy per instruction issued. */
Stats::Formula fuBusyRate;
};
diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh
index fb06f20df..1d0f4b9f6 100644
--- a/src/cpu/o3/inst_queue_impl.hh
+++ b/src/cpu/o3/inst_queue_impl.hh
@@ -37,12 +37,13 @@
#include "enums/OpClass.hh"
#include "sim/core.hh"
+#include "params/DerivO3CPU.hh"
+
template <class Impl>
InstructionQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
- int fu_idx,
- InstructionQueue<Impl> *iq_ptr)
- : Event(&mainEventQueue, Stat_Event_Pri),
- inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr), freeFU(false)
+ int fu_idx, InstructionQueue<Impl> *iq_ptr)
+ : Event(Stat_Event_Pri), inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr),
+ freeFU(false)
{
this->setFlags(Event::AutoDelete);
}
@@ -65,7 +66,7 @@ InstructionQueue<Impl>::FUCompletion::description() const
template <class Impl>
InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
- Params *params)
+ DerivO3CPUParams *params)
: cpu(cpu_ptr),
iewStage(iew_ptr),
fuPool(params->fuPool),
@@ -79,7 +80,7 @@ InstructionQueue<Impl>::InstructionQueue(O3CPU *cpu_ptr, IEW *iew_ptr,
switchedOut = false;
- numThreads = params->numberOfThreads;
+ numThreads = params->numThreads;
// Set the number of physical registers as the number of int + float
numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
@@ -752,7 +753,7 @@ InstructionQueue<Impl>::scheduleReadyInsts()
FUCompletion *execution = new FUCompletion(issuing_inst,
idx, this);
- execution->schedule(curTick + cpu->ticks(op_latency - 1));
+ cpu->schedule(execution, curTick + cpu->ticks(op_latency - 1));
// @todo: Enforce that issue_latency == 1 or op_latency
if (issue_latency > 1) {
diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh
index 72a8d4021..e9347af91 100755
--- a/src/cpu/o3/isa_specific.hh
+++ b/src/cpu/o3/isa_specific.hh
@@ -30,21 +30,5 @@
#include "cpu/base.hh"
-#if THE_ISA == ALPHA_ISA
- #include "cpu/o3/alpha/cpu.hh"
- #include "cpu/o3/alpha/impl.hh"
- #include "cpu/o3/alpha/params.hh"
- #include "cpu/o3/alpha/dyn_inst.hh"
-#elif THE_ISA == MIPS_ISA
- #include "cpu/o3/mips/cpu.hh"
- #include "cpu/o3/mips/impl.hh"
- #include "cpu/o3/mips/params.hh"
- #include "cpu/o3/mips/dyn_inst.hh"
-#elif THE_ISA == SPARC_ISA
- #include "cpu/o3/sparc/cpu.hh"
- #include "cpu/o3/sparc/impl.hh"
- #include "cpu/o3/sparc/params.hh"
- #include "cpu/o3/sparc/dyn_inst.hh"
-#else
- #error "ISA-specific header files O3CPU not defined ISA"
-#endif
+#include "cpu/o3/impl.hh"
+#include "cpu/o3/dyn_inst.hh"
diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh
index 06de608e0..cf27552d4 100644
--- a/src/cpu/o3/lsq.hh
+++ b/src/cpu/o3/lsq.hh
@@ -40,10 +40,11 @@
#include "mem/port.hh"
#include "sim/sim_object.hh"
+class DerivO3CPUParams;
+
template <class Impl>
class LSQ {
public:
- typedef typename Impl::Params Params;
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::CPUPol::IEW IEW;
@@ -57,7 +58,7 @@ class LSQ {
};
/** Constructs an LSQ with the given parameters. */
- LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params);
+ LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params);
/** Returns the name of the LSQ. */
std::string name() const;
@@ -297,7 +298,7 @@ class LSQ {
public:
/** Default constructor. */
DcachePort(LSQ *_lsq)
- : Port(_lsq->name() + "-dport"), lsq(_lsq)
+ : Port(_lsq->name() + "-dport", _lsq->cpu), lsq(_lsq)
{ }
bool snoopRangeSent;
@@ -370,7 +371,7 @@ template <class T>
Fault
LSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
{
- unsigned tid = req->getThreadNum();
+ unsigned tid = req->threadId();
return thread[tid].read(req, data, load_idx);
}
@@ -380,7 +381,7 @@ template <class T>
Fault
LSQ<Impl>::write(RequestPtr req, T &data, int store_idx)
{
- unsigned tid = req->getThreadNum();
+ unsigned tid = req->threadId();
return thread[tid].write(req, data, store_idx);
}
diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh
index 8ed6f7f54..8f9f63081 100644
--- a/src/cpu/o3/lsq_impl.hh
+++ b/src/cpu/o3/lsq_impl.hh
@@ -34,6 +34,8 @@
#include "cpu/o3/lsq.hh"
+#include "params/DerivO3CPU.hh"
+
template<class Impl>
void
LSQ<Impl>::DcachePort::setPeer(Port *port)
@@ -83,7 +85,7 @@ LSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
if (pkt->isError())
DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr());
if (pkt->isResponse()) {
- lsq->thread[pkt->req->getThreadNum()].completeDataAccess(pkt);
+ lsq->thread[pkt->req->threadId()].completeDataAccess(pkt);
}
else {
// must be a snoop
@@ -111,11 +113,11 @@ LSQ<Impl>::DcachePort::recvRetry()
}
template <class Impl>
-LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params)
+LSQ<Impl>::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params)
: cpu(cpu_ptr), iewStage(iew_ptr), dcachePort(this),
LQEntries(params->LQEntries),
SQEntries(params->SQEntries),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
retryTid(-1)
{
dcachePort.snoopRangeSent = false;
@@ -582,17 +584,14 @@ LSQ<Impl>::hasStoresToWB()
std::list<unsigned>::iterator threads = activeThreads->begin();
std::list<unsigned>::iterator end = activeThreads->end();
- if (threads == end)
- return false;
-
while (threads != end) {
unsigned tid = *threads++;
- if (!hasStoresToWB(tid))
- return false;
+ if (hasStoresToWB(tid))
+ return true;
}
- return true;
+ return false;
}
template<class Impl>
@@ -605,11 +604,11 @@ LSQ<Impl>::willWB()
while (threads != end) {
unsigned tid = *threads++;
- if (!willWB(tid))
- return false;
+ if (willWB(tid))
+ return true;
}
- return true;
+ return false;
}
template<class Impl>
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
index 128a71dbc..5323e3a47 100644
--- a/src/cpu/o3/lsq_unit.hh
+++ b/src/cpu/o3/lsq_unit.hh
@@ -40,11 +40,14 @@
#include "arch/faults.hh"
#include "arch/locked_mem.hh"
#include "config/full_system.hh"
+#include "base/fast_alloc.hh"
#include "base/hashmap.hh"
#include "cpu/inst_seq.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
+class DerivO3CPUParams;
+
/**
* Class that implements the actual LQ and SQ for each specific
* thread. Both are circular queues; load entries are freed upon
@@ -62,7 +65,6 @@ class LSQUnit {
protected:
typedef TheISA::IntReg IntReg;
public:
- typedef typename Impl::Params Params;
typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::CPUPol::IEW IEW;
@@ -74,8 +76,9 @@ class LSQUnit {
LSQUnit();
/** Initializes the LSQ unit with the specified number of entries. */
- void init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,
- unsigned maxLQEntries, unsigned maxSQEntries, unsigned id);
+ void init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
+ LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries,
+ unsigned id);
/** Returns the name of the LSQ unit. */
std::string name() const;
@@ -245,7 +248,7 @@ class LSQUnit {
Port *dcachePort;
/** Derived class to hold any sender state the LSQ needs. */
- class LSQSenderState : public Packet::SenderState
+ class LSQSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Default constructor. */
@@ -406,35 +409,35 @@ class LSQUnit {
// of that in stage that is one level up, and only call executeLoad/Store
// the appropriate number of times.
/** Total number of loads forwaded from LSQ stores. */
- Stats::Scalar<> lsqForwLoads;
+ Stats::Scalar lsqForwLoads;
/** Total number of loads ignored due to invalid addresses. */
- Stats::Scalar<> invAddrLoads;
+ Stats::Scalar invAddrLoads;
/** Total number of squashed loads. */
- Stats::Scalar<> lsqSquashedLoads;
+ Stats::Scalar lsqSquashedLoads;
/** Total number of responses from the memory system that are
* ignored due to the instruction already being squashed. */
- Stats::Scalar<> lsqIgnoredResponses;
+ Stats::Scalar lsqIgnoredResponses;
/** Tota number of memory ordering violations. */
- Stats::Scalar<> lsqMemOrderViolation;
+ Stats::Scalar lsqMemOrderViolation;
/** Total number of squashed stores. */
- Stats::Scalar<> lsqSquashedStores;
+ Stats::Scalar lsqSquashedStores;
/** Total number of software prefetches ignored due to invalid addresses. */
- Stats::Scalar<> invAddrSwpfs;
+ Stats::Scalar invAddrSwpfs;
/** Ready loads blocked due to partial store-forwarding. */
- Stats::Scalar<> lsqBlockedLoads;
+ Stats::Scalar lsqBlockedLoads;
/** Number of loads that were rescheduled. */
- Stats::Scalar<> lsqRescheduledLoads;
+ Stats::Scalar lsqRescheduledLoads;
/** Number of times the LSQ is blocked due to the cache. */
- Stats::Scalar<> lsqCacheBlocked;
+ Stats::Scalar lsqCacheBlocked;
public:
/** Executes the load at the given index. */
@@ -581,7 +584,7 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
// We'll say this has a 1 cycle load-store forwarding latency
// for now.
// @todo: Need to make this a parameter.
- wb->schedule(curTick);
+ cpu->schedule(wb, curTick);
++lsqForwLoads;
return NoFault;
diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh
index e6ff5e931..85662d496 100644
--- a/src/cpu/o3/lsq_unit_impl.hh
+++ b/src/cpu/o3/lsq_unit_impl.hh
@@ -45,7 +45,7 @@
template<class Impl>
LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
LSQUnit *lsq_ptr)
- : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
+ : inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
{
this->setFlags(Event::AutoDelete);
}
@@ -112,8 +112,9 @@ LSQUnit<Impl>::LSQUnit()
template<class Impl>
void
-LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,
- unsigned maxLQEntries, unsigned maxSQEntries, unsigned id)
+LSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params,
+ LSQ *lsq_ptr, unsigned maxLQEntries, unsigned maxSQEntries,
+ unsigned id)
{
cpu = cpu_ptr;
iewStage = iew_ptr;
@@ -683,7 +684,7 @@ LSQUnit<Impl>::writebackStores()
"Instantly completing it.\n",
inst->seqNum);
WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
- wb->schedule(curTick + 1);
+ cpu->schedule(wb, curTick + 1);
completeStore(storeWBIdx);
incrStIdx(storeWBIdx);
continue;
diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh
index a12a3001b..4f9e7c9f7 100644
--- a/src/cpu/o3/mem_dep_unit.hh
+++ b/src/cpu/o3/mem_dep_unit.hh
@@ -48,6 +48,8 @@ struct SNHash {
}
};
+class DerivO3CPUParams;
+
template <class Impl>
class InstructionQueue;
@@ -63,25 +65,28 @@ class InstructionQueue;
* dependence prediction schemes.
*/
template <class MemDepPred, class Impl>
-class MemDepUnit {
+class MemDepUnit
+{
+ protected:
+ std::string _name;
+
public:
- typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
/** Empty constructor. Must call init() prior to using in this case. */
MemDepUnit();
/** Constructs a MemDepUnit with given parameters. */
- MemDepUnit(Params *params);
+ MemDepUnit(DerivO3CPUParams *params);
/** Frees up any memory allocated. */
~MemDepUnit();
/** Returns the name of the memory dependence unit. */
- std::string name() const;
+ std::string name() const { return _name; }
/** Initializes the unit with parameters and a thread id. */
- void init(Params *params, int tid);
+ void init(DerivO3CPUParams *params, int tid);
/** Registers statistics. */
void regStats();
@@ -252,13 +257,13 @@ class MemDepUnit {
int id;
/** Stat for number of inserted loads. */
- Stats::Scalar<> insertedLoads;
+ Stats::Scalar insertedLoads;
/** Stat for number of inserted stores. */
- Stats::Scalar<> insertedStores;
+ Stats::Scalar insertedStores;
/** Stat for number of conflicting loads that had to wait for a store. */
- Stats::Scalar<> conflictingLoads;
+ Stats::Scalar conflictingLoads;
/** Stat for number of conflicting stores that had to wait for a store. */
- Stats::Scalar<> conflictingStores;
+ Stats::Scalar conflictingStores;
};
#endif // __CPU_O3_MEM_DEP_UNIT_HH__
diff --git a/src/cpu/o3/mem_dep_unit_impl.hh b/src/cpu/o3/mem_dep_unit_impl.hh
index 64558efaa..8754539f9 100644
--- a/src/cpu/o3/mem_dep_unit_impl.hh
+++ b/src/cpu/o3/mem_dep_unit_impl.hh
@@ -33,6 +33,8 @@
#include "cpu/o3/inst_queue.hh"
#include "cpu/o3/mem_dep_unit.hh"
+#include "params/DerivO3CPU.hh"
+
template <class MemDepPred, class Impl>
MemDepUnit<MemDepPred, Impl>::MemDepUnit()
: loadBarrier(false), loadBarrierSN(0), storeBarrier(false),
@@ -41,8 +43,9 @@ MemDepUnit<MemDepPred, Impl>::MemDepUnit()
}
template <class MemDepPred, class Impl>
-MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params)
- : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false),
+MemDepUnit<MemDepPred, Impl>::MemDepUnit(DerivO3CPUParams *params)
+ : _name(params->name + ".memdepunit"),
+ depPred(params->SSITSize, params->LFSTSize), loadBarrier(false),
loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL)
{
DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n");
@@ -74,18 +77,12 @@ MemDepUnit<MemDepPred, Impl>::~MemDepUnit()
}
template <class MemDepPred, class Impl>
-std::string
-MemDepUnit<MemDepPred, Impl>::name() const
-{
- return "memdepunit";
-}
-
-template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid)
+MemDepUnit<MemDepPred, Impl>::init(DerivO3CPUParams *params, int tid)
{
DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid);
+ _name = csprintf("%s.memDep%d", params->name, tid);
id = tid;
depPred.init(params->SSITSize, params->LFSTSize);
@@ -96,19 +93,19 @@ void
MemDepUnit<MemDepPred, Impl>::regStats()
{
insertedLoads
- .name(name() + ".memDep.insertedLoads")
+ .name(name() + ".insertedLoads")
.desc("Number of loads inserted to the mem dependence unit.");
insertedStores
- .name(name() + ".memDep.insertedStores")
+ .name(name() + ".insertedStores")
.desc("Number of stores inserted to the mem dependence unit.");
conflictingLoads
- .name(name() + ".memDep.conflictingLoads")
+ .name(name() + ".conflictingLoads")
.desc("Number of conflicting loads.");
conflictingStores
- .name(name() + ".memDep.conflictingStores")
+ .name(name() + ".conflictingStores")
.desc("Number of conflicting stores.");
}
diff --git a/src/cpu/o3/mips/cpu.cc b/src/cpu/o3/mips/cpu.cc
deleted file mode 100755
index 420f460b2..000000000
--- a/src/cpu/o3/mips/cpu.cc
+++ /dev/null
@@ -1,39 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#include "cpu/o3/mips/impl.hh"
-#include "cpu/o3/mips/cpu_impl.hh"
-#include "cpu/o3/mips/dyn_inst.hh"
-
-// Force instantiation of MipsO3CPU for all the implemntations that are
-// needed. Consider merging this and mips_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (mips_impl.cc?).
-template class MipsO3CPU<MipsSimpleImpl>;
diff --git a/src/cpu/o3/mips/cpu.hh b/src/cpu/o3/mips/cpu.hh
deleted file mode 100755
index 3724ced46..000000000
--- a/src/cpu/o3/mips/cpu.hh
+++ /dev/null
@@ -1,130 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_CPU_HH__
-#define __CPU_O3_MIPS_CPU_HH__
-
-#include "arch/mips/regfile.hh"
-#include "arch/mips/syscallreturn.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-#include "sim/faults.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * MipsO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class MipsO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an MipsO3CPU with the given parameters. */
- MipsO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid);
-
- /** Sets a misc. register, including any side effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg,
- const TheISA::MiscReg &val, unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_MIPS_CPU_HH__
diff --git a/src/cpu/o3/mips/cpu_builder.cc b/src/cpu/o3/mips/cpu_builder.cc
deleted file mode 100644
index 4690b9804..000000000
--- a/src/cpu/o3/mips/cpu_builder.cc
+++ /dev/null
@@ -1,182 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#include <string>
-
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/impl.hh"
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public MipsO3CPU<MipsSimpleImpl>
-{
- public:
- DerivO3CPU(MipsSimpleParams *p)
- : MipsO3CPU<MipsSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-
- MipsSimpleParams *params = new MipsSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->workload = workload;
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- 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;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/mips/cpu_impl.hh b/src/cpu/o3/mips/cpu_impl.hh
deleted file mode 100644
index 09d73b4a2..000000000
--- a/src/cpu/o3/mips/cpu_impl.hh
+++ /dev/null
@@ -1,217 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/mips/faults.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/mips/thread_context.hh"
-#include "cpu/o3/comm.hh"
-#include "cpu/o3/thread_state.hh"
-
-template <class Impl>
-MipsO3CPU<Impl>::MipsO3CPU(Params *params)
- : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating MipsO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread 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;
- }
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- MipsTC<Impl> *mips_tc =
- new MipsTC<Impl>;
-
- tc = mips_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<MipsTC<Impl> >(
- mips_tc, this->checker);
- }
-#endif
-
- mips_tc->cpu = this;
- mips_tc->thread = this->thread[i];
-
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-MipsO3CPU<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();
-}
-
-
-template <class Impl>
-MiscReg
-MipsO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-MiscReg
-MipsO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val,
- unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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(callnum);
-
- // Decrease funcExeInst by one as the normal commit will handle
- // incrementing it.
- --(this->thread[tid]->funcExeInst);
-
- DPRINTF(O3CPU, "[tid:%i] Register 2 is %i ", tid, this->readIntReg(2));
-}
-
-template <class Impl>
-TheISA::IntReg
-MipsO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- return this->readArchIntReg(MipsISA::ArgumentReg[i], tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- this->setArchIntReg(MipsISA::ArgumentReg[i], val, tid);
-}
-
-template <class Impl>
-void
-MipsO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/mips/dyn_inst.cc b/src/cpu/o3/mips/dyn_inst.cc
deleted file mode 100755
index 216aa7d2c..000000000
--- a/src/cpu/o3/mips/dyn_inst.cc
+++ /dev/null
@@ -1,37 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#include "cpu/o3/mips/dyn_inst_impl.hh"
-#include "cpu/o3/mips/impl.hh"
-
-// Force instantiation of MipsDynInst for all the implementations that
-// are needed.
-template class MipsDynInst<MipsSimpleImpl>;
diff --git a/src/cpu/o3/mips/dyn_inst.hh b/src/cpu/o3/mips/dyn_inst.hh
deleted file mode 100755
index b1a29ccf9..000000000
--- a/src/cpu/o3/mips/dyn_inst.hh
+++ /dev/null
@@ -1,281 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_DYN_INST_HH__
-#define __CPU_O3_MIPS_DYN_INST_HH__
-
-#include "arch/isa_traits.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/mips/cpu.hh"
-#include "cpu/o3/mips/impl.hh"
-
-class Packet;
-
-/**
- * Mostly implementation & ISA specific MipsDynInst. 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 MipsDynInst serves as the primary interface to the CPU
- * for instructions that are executing.
- */
-template <class Impl>
-class MipsDynInst : public BaseDynInst<Impl>
-{
- public:
- /** Typedef for the CPU. */
- typedef typename Impl::O3CPU O3CPU;
-
- /** Logical register index type. */
- typedef TheISA::RegIndex RegIndex;
- /** Integer register index type. */
- typedef TheISA::IntReg IntReg;
- typedef TheISA::FloatReg FloatReg;
- typedef TheISA::FloatRegBits FloatRegBits;
- /** 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. */
- MipsDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- MipsDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a static inst pointer. */
- MipsDynInst(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(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- /** TODO: Use thread number from argument if given, will probably not work for MIPS MT as is */
- MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid = 0)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- MiscReg readMiscReg(int misc_reg, unsigned tid = 0)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const MiscReg &val, unsigned tid = 0)
- {
- this->instResult.integer = val;
- this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const MiscReg &val, unsigned tid = 0)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
-
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-
- 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 readIntRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readIntReg(this->_srcRegIdx[idx]);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx,
- int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val,
- int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscRegNoEffect(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si, int idx, const MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscRegOperand(const StaticInst *si, int idx,
- const MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
- uint64_t readRegOtherThread(int misc_reg)
- {
- panic("MIPS MT not defined for O3 CPU.\n");
- return 0;
- }
-
- void setRegOtherThread(int misc_reg, const TheISA::MiscReg &val)
- {
- panic("MIPS MT not defined for O3 CPU.\n");
- }
-
- 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_MIPS_DYN_INST_HH__
-
diff --git a/src/cpu/o3/mips/dyn_inst_impl.hh b/src/cpu/o3/mips/dyn_inst_impl.hh
deleted file mode 100755
index 7e8697b32..000000000
--- a/src/cpu/o3/mips/dyn_inst_impl.hh
+++ /dev/null
@@ -1,130 +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.
- *
- * Authors: Kevin Lim
- */
-
-#include "cpu/o3/mips/dyn_inst.hh"
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-MipsDynInst<Impl>::MipsDynInst(StaticInstPtr &_staticInst)
- : BaseDynInst<Impl>(_staticInst)
-{
- initVars();
-}
-
-template <class Impl>
-void
-MipsDynInst<Impl>::initVars()
-{
- // Make sure to have the renamed register entries set to the same
- // as the normal register entries. It will allow the IQ to work
- // without any modifications.
- for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
- this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
- }
-
- for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
- this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
- this->_readySrcRegIdx[i] = 0;
- }
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::execute()
-{
- // @todo: Pretty convoluted way to avoid squashing from happening
- // when using the TC during an instruction's execution
- // (specifically for instructions that have side-effects that use
- // the TC). Fix this.
- bool in_syscall = this->thread->inSyscall;
- this->thread->inSyscall = true;
-
- this->fault = this->staticInst->execute(this, this->traceData);
-
- this->thread->inSyscall = in_syscall;
-
- return this->fault;
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::initiateAcc()
-{
- // @todo: Pretty convoluted way to avoid squashing from happening
- // when using the TC during an instruction's execution
- // (specifically for instructions that have side-effects that use
- // the TC). Fix this.
- bool in_syscall = this->thread->inSyscall;
- this->thread->inSyscall = true;
-
- this->fault = this->staticInst->initiateAcc(this, this->traceData);
-
- this->thread->inSyscall = in_syscall;
-
- return this->fault;
-}
-
-template <class Impl>
-Fault
-MipsDynInst<Impl>::completeAcc(PacketPtr pkt)
-{
- this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
-
- return this->fault;
-}
-
-template <class Impl>
-void
-MipsDynInst<Impl>::syscall(int64_t callnum)
-{
- this->cpu->syscall(callnum, this->threadNumber);
-}
-
diff --git a/src/cpu/o3/mips/impl.hh b/src/cpu/o3/mips/impl.hh
deleted file mode 100644
index ac7181a19..000000000
--- a/src/cpu/o3/mips/impl.hh
+++ /dev/null
@@ -1,93 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_IMPL_HH__
-#define __CPU_O3_MIPS_IMPL_HH__
-
-#include "arch/mips/isa_traits.hh"
-
-#include "cpu/o3/mips/params.hh"
-#include "cpu/o3/cpu_policy.hh"
-
-
-// Forward declarations.
-template <class Impl>
-class MipsDynInst;
-
-template <class Impl>
-class MipsO3CPU;
-
-/** Implementation specific struct that defines several key types to the
- * CPU, the stages within the CPU, the time buffers, and the DynInst.
- * The struct defines the ISA, the CPU policy, the specific DynInst, the
- * specific O3CPU, and all of the structs from the time buffers to do
- * communication.
- * This is one of the key things that must be defined for each hardware
- * specific CPU implementation.
- */
-struct MipsSimpleImpl
-{
- /** The type of MachInst. */
- typedef TheISA::MachInst MachInst;
-
- /** The CPU policy to be used, which defines all of the CPU stages. */
- typedef SimpleCPUPolicy<MipsSimpleImpl> CPUPol;
-
- /** The DynInst type to be used. */
- typedef MipsDynInst<MipsSimpleImpl> DynInst;
-
- /** The refcounted DynInst pointer to be used. In most cases this is
- * what should be used, and not DynInst *.
- */
- typedef RefCountingPtr<DynInst> DynInstPtr;
-
- /** The O3CPU type to be used. */
- typedef MipsO3CPU<MipsSimpleImpl> O3CPU;
-
- /** Same typedef, but for CPUType. BaseDynInst may not always use
- * an O3 CPU, so it's clearer to call it CPUType instead in that
- * case.
- */
- typedef O3CPU CPUType;
-
- /** The Params to be passed to each stage. */
- typedef MipsSimpleParams Params;
-
- enum {
- MaxWidth = 8,
- MaxThreads = 4
- };
-};
-
-/** The O3Impl to be used. */
-typedef MipsSimpleImpl O3CPUImpl;
-
-#endif // __CPU_O3_MIPS_IMPL_HH__
diff --git a/src/cpu/o3/mips/params.hh b/src/cpu/o3/mips/params.hh
deleted file mode 100644
index 2688d3fb3..000000000
--- a/src/cpu/o3/mips/params.hh
+++ /dev/null
@@ -1,64 +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.
- *
- * Authors: Kevin Lim
- * Korey Sewell
- */
-
-#ifndef __CPU_O3_MIPS_PARAMS_HH__
-#define __CPU_O3_MIPS_PARAMS_HH__
-
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
-
-//Forward declarations
-namespace MipsISA
-{
- class MipsDTB;
- class MipsITB;
-}
-class MemObject;
-class Process;
-class System;
-
-/**
- * This file defines the parameters that will be used for the MipsO3CPU.
- * This must be defined externally so that the Impl can have a params class
- * defined that it can pass to all of the individual stages.
- */
-
-class MipsSimpleParams : public O3Params
-{
- public:
- MipsSimpleParams() {}
-
- //Full System Paramater Objects place here
- MipsISA::ITB *itb;
- MipsISA::DTB *dtb;
-};
-
-#endif // __CPU_O3_MIPS_PARAMS_HH__
diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh
index 97846ed16..f0621c5b5 100644
--- a/src/cpu/o3/ras.hh
+++ b/src/cpu/o3/ras.hh
@@ -71,6 +71,9 @@ class ReturnAddrStack
*/
void restore(unsigned top_entry_idx, const Addr &restored_target);
+ bool empty() { return usedEntries == 0; }
+
+ bool full() { return usedEntries == numEntries; }
private:
/** Increments the top of stack index. */
inline void incrTos()
diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh
index 75d3fa6eb..53ac2d683 100644
--- a/src/cpu/o3/regfile.hh
+++ b/src/cpu/o3/regfile.hh
@@ -33,6 +33,7 @@
#define __CPU_O3_REGFILE_HH__
#include "arch/isa_traits.hh"
+#include "arch/regfile.hh"
#include "arch/types.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
@@ -264,7 +265,7 @@ class PhysRegFile
#if FULL_SYSTEM
private:
- int intrflag; // interrupt flag
+ int intrflag; // interrupt flag
#endif
private:
diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh
index b2faffe43..0fdf28b19 100644
--- a/src/cpu/o3/rename.hh
+++ b/src/cpu/o3/rename.hh
@@ -36,6 +36,8 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
+class DerivO3CPUParams;
+
/**
* DefaultRename handles both single threaded and SMT rename. Its
* width is specified by the parameters; each cycle it tries to rename
@@ -56,7 +58,6 @@ class DefaultRename
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::O3CPU O3CPU;
- typedef typename Impl::Params Params;
// Typedefs from the CPUPol
typedef typename CPUPol::DecodeStruct DecodeStruct;
@@ -107,7 +108,7 @@ class DefaultRename
public:
/** DefaultRename constructor. */
- DefaultRename(O3CPU *_cpu, Params *params);
+ DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params);
/** Returns the name of rename. */
std::string name() const;
@@ -440,44 +441,44 @@ class DefaultRename
inline void incrFullStat(const FullSource &source);
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> renameSquashCycles;
+ Stats::Scalar renameSquashCycles;
/** Stat for total number of cycles spent idle. */
- Stats::Scalar<> renameIdleCycles;
+ Stats::Scalar renameIdleCycles;
/** Stat for total number of cycles spent blocking. */
- Stats::Scalar<> renameBlockCycles;
+ Stats::Scalar renameBlockCycles;
/** Stat for total number of cycles spent stalling for a serializing inst. */
- Stats::Scalar<> renameSerializeStallCycles;
+ Stats::Scalar renameSerializeStallCycles;
/** Stat for total number of cycles spent running normally. */
- Stats::Scalar<> renameRunCycles;
+ Stats::Scalar renameRunCycles;
/** Stat for total number of cycles spent unblocking. */
- Stats::Scalar<> renameUnblockCycles;
+ Stats::Scalar renameUnblockCycles;
/** Stat for total number of renamed instructions. */
- Stats::Scalar<> renameRenamedInsts;
+ Stats::Scalar renameRenamedInsts;
/** Stat for total number of squashed instructions that rename discards. */
- Stats::Scalar<> renameSquashedInsts;
+ Stats::Scalar renameSquashedInsts;
/** Stat for total number of times that the ROB starts a stall in rename. */
- Stats::Scalar<> renameROBFullEvents;
+ Stats::Scalar renameROBFullEvents;
/** Stat for total number of times that the IQ starts a stall in rename. */
- Stats::Scalar<> renameIQFullEvents;
+ Stats::Scalar renameIQFullEvents;
/** Stat for total number of times that the LSQ starts a stall in rename. */
- Stats::Scalar<> renameLSQFullEvents;
+ Stats::Scalar renameLSQFullEvents;
/** Stat for total number of times that rename runs out of free registers
* to use to rename. */
- Stats::Scalar<> renameFullRegistersEvents;
+ Stats::Scalar renameFullRegistersEvents;
/** Stat for total number of renamed destination registers. */
- Stats::Scalar<> renameRenamedOperands;
+ Stats::Scalar renameRenamedOperands;
/** Stat for total number of source register rename lookups. */
- Stats::Scalar<> renameRenameLookups;
+ Stats::Scalar renameRenameLookups;
/** Stat for total number of committed renaming mappings. */
- Stats::Scalar<> renameCommittedMaps;
+ Stats::Scalar renameCommittedMaps;
/** Stat for total number of mappings that were undone due to a squash. */
- Stats::Scalar<> renameUndoneMaps;
+ Stats::Scalar renameUndoneMaps;
/** Number of serialize instructions handled. */
- Stats::Scalar<> renamedSerializing;
+ Stats::Scalar renamedSerializing;
/** Number of instructions marked as temporarily serializing. */
- Stats::Scalar<> renamedTempSerializing;
+ Stats::Scalar renamedTempSerializing;
/** Number of instructions inserted into skid buffers. */
- Stats::Scalar<> renameSkidInsts;
+ Stats::Scalar renameSkidInsts;
};
#endif // __CPU_O3_RENAME_HH__
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh
index 49c885753..81647b133 100644
--- a/src/cpu/o3/rename_impl.hh
+++ b/src/cpu/o3/rename_impl.hh
@@ -35,9 +35,10 @@
#include "arch/regfile.hh"
#include "config/full_system.hh"
#include "cpu/o3/rename.hh"
+#include "params/DerivO3CPU.hh"
template <class Impl>
-DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params)
+DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
iewToRenameDelay(params->iewToRenameDelay),
decodeToRenameDelay(params->decodeToRenameDelay),
@@ -46,7 +47,7 @@ DefaultRename<Impl>::DefaultRename(O3CPU *_cpu, Params *params)
commitWidth(params->commitWidth),
resumeSerialize(false),
resumeUnblocking(false),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
maxPhysicalRegs(params->numPhysIntRegs + params->numPhysFloatRegs)
{
_status = Inactive;
diff --git a/src/cpu/o3/sparc/cpu.hh b/src/cpu/o3/sparc/cpu.hh
deleted file mode 100644
index 3fd193e0f..000000000
--- a/src/cpu/o3/sparc/cpu.hh
+++ /dev/null
@@ -1,148 +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.
- *
- * Authors: Kevin Lim
- */
-
-#ifndef __CPU_O3_SPARC_CPU_HH__
-#define __CPU_O3_SPARC_CPU_HH__
-
-#include "arch/sparc/regfile.hh"
-#include "arch/sparc/types.hh"
-#include "cpu/thread_context.hh"
-#include "cpu/o3/cpu.hh"
-#include "sim/byteswap.hh"
-
-class EndQuiesceEvent;
-namespace Kernel {
- class Statistics;
-};
-
-class TranslatingPort;
-
-/**
- * SparcO3CPU class. Derives from the FullO3CPU class, and
- * implements all ISA and implementation specific functions of the
- * CPU. This is the CPU class that is used for the SimObjects, and is
- * what is given to the DynInsts. Most of its state exists in the
- * FullO3CPU; the state is has is mainly for ISA specific
- * functionality.
- */
-template <class Impl>
-class SparcO3CPU : public FullO3CPU<Impl>
-{
- public:
- typedef O3ThreadState<Impl> ImplState;
- typedef O3ThreadState<Impl> Thread;
- typedef typename Impl::Params Params;
-
- /** Constructs an AlphaO3CPU with the given parameters. */
- SparcO3CPU(Params *params);
-
- /** Registers statistics. */
- void regStats();
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg, unsigned tid);
-
- /** Reads a misc. register, including any side effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg, unsigned tid);
-
- /** Sets a miscellaneous register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val, unsigned tid);
-
- /** Sets a misc. register, including any side effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const TheISA::MiscReg &val,
- unsigned tid);
-
- /** Initiates a squash of all in-flight instructions for a given
- * thread. The source of the squash is an external update of
- * state through the TC.
- */
- void squashFromTC(unsigned tid);
-
-#if FULL_SYSTEM
- /** Posts an interrupt. */
- void post_interrupt(int int_num, int index);
- /** HW return from error interrupt. */
- Fault hwrei(unsigned tid);
-
- bool simPalCheck(int palFunc, unsigned tid);
-
- /** Returns the Fault for any valid interrupt. */
- Fault getInterrupts();
-
- /** Processes any an interrupt fault. */
- void processInterrupts(Fault interrupt);
-
- /** Halts the CPU. */
- void halt() { panic("Halt not implemented!\n"); }
-#endif
-
- /** Traps to handle given fault. */
- void trap(Fault fault, unsigned tid);
-
-#if !FULL_SYSTEM
- /** Executes a syscall.
- * @todo: Determine if this needs to be virtual.
- */
- void syscall(int64_t callnum, int tid);
- /** Gets a syscall argument. */
- TheISA::IntReg getSyscallArg(int i, int tid);
-
- /** Used to shift args for indirect syscall. */
- void setSyscallArg(int i, TheISA::IntReg val, int tid);
-
- /** Sets the return value of a syscall. */
- void setSyscallReturn(SyscallReturn return_value, int tid);
-#endif
-
- /** CPU read function, forwards read to LSQ. */
- template <class T>
- Fault read(RequestPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- /** CPU write function, forwards write to LSQ. */
- template <class T>
- Fault write(RequestPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
- Addr lockAddr;
-
- /** Temporary fix for the lock flag, works in the UP case. */
- bool lockFlag;
-};
-
-#endif // __CPU_O3_SPARC_CPU_HH__
diff --git a/src/cpu/o3/sparc/cpu_builder.cc b/src/cpu/o3/sparc/cpu_builder.cc
deleted file mode 100644
index b08845b4e..000000000
--- a/src/cpu/o3/sparc/cpu_builder.cc
+++ /dev/null
@@ -1,200 +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.
- *
- * Authors: Gabe Black
- */
-
-#include <string>
-
-#include "config/full_system.hh"
-#include "config/use_checker.hh"
-#include "cpu/base.hh"
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/impl.hh"
-#include "cpu/o3/sparc/params.hh"
-#include "cpu/o3/fu_pool.hh"
-#include "params/DerivO3CPU.hh"
-
-class DerivO3CPU : public SparcO3CPU<SparcSimpleImpl>
-{
- public:
- DerivO3CPU(SparcSimpleParams *p)
- : SparcO3CPU<SparcSimpleImpl>(p)
- { }
-};
-
-DerivO3CPU *
-DerivO3CPUParams::create()
-{
- DerivO3CPU *cpu;
-
-#if FULL_SYSTEM
- // Full-system only supports a single thread for the moment.
- int actual_num_threads = 1;
-#else
- // In non-full-system mode, we infer the number of threads from
- // the workload if it's not explicitly specified.
- int actual_num_threads =
- (numThreads >= workload.size()) ? numThreads : workload.size();
-
- if (workload.size() == 0) {
- fatal("Must specify at least one workload!");
- }
-#endif
-
- SparcSimpleParams *params = new SparcSimpleParams;
-
- params->clock = clock;
- params->phase = phase;
-
- params->tracer = tracer;
-
- params->name = name;
- params->numberOfThreads = actual_num_threads;
- params->cpu_id = cpu_id;
- params->activity = activity;
-
- params->itb = itb;
- params->dtb = dtb;
-
- params->system = system;
-#if FULL_SYSTEM
- params->profile = profile;
-
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
- params->workload = workload;
-#endif // FULL_SYSTEM
-
-#if USE_CHECKER
- params->checker = checker;
-#endif
-
- 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->progress_interval = progress_interval;
-
- //
- // Caches
- //
- params->cachePorts = cachePorts;
-
- params->decodeToFetchDelay = decodeToFetchDelay;
- params->renameToFetchDelay = renameToFetchDelay;
- params->iewToFetchDelay = iewToFetchDelay;
- params->commitToFetchDelay = commitToFetchDelay;
- params->fetchWidth = fetchWidth;
-
- params->renameToDecodeDelay = renameToDecodeDelay;
- params->iewToDecodeDelay = iewToDecodeDelay;
- params->commitToDecodeDelay = commitToDecodeDelay;
- params->fetchToDecodeDelay = fetchToDecodeDelay;
- params->decodeWidth = decodeWidth;
-
- params->iewToRenameDelay = iewToRenameDelay;
- params->commitToRenameDelay = commitToRenameDelay;
- params->decodeToRenameDelay = decodeToRenameDelay;
- params->renameWidth = renameWidth;
-
- params->commitToIEWDelay = commitToIEWDelay;
- params->renameToIEWDelay = renameToIEWDelay;
- params->issueToExecuteDelay = issueToExecuteDelay;
- params->dispatchWidth = dispatchWidth;
- params->issueWidth = issueWidth;
- params->wbWidth = wbWidth;
- params->wbDepth = wbDepth;
- params->fuPool = fuPool;
-
- params->iewToCommitDelay = iewToCommitDelay;
- params->renameToROBDelay = renameToROBDelay;
- params->commitWidth = commitWidth;
- params->squashWidth = squashWidth;
- params->trapLatency = trapLatency;
-
- params->backComSize = backComSize;
- params->forwardComSize = forwardComSize;
-
- params->predType = predType;
- params->localPredictorSize = localPredictorSize;
- params->localCtrBits = localCtrBits;
- params->localHistoryTableSize = localHistoryTableSize;
- params->localHistoryBits = localHistoryBits;
- params->globalPredictorSize = globalPredictorSize;
- params->globalCtrBits = globalCtrBits;
- params->globalHistoryBits = globalHistoryBits;
- params->choicePredictorSize = choicePredictorSize;
- params->choiceCtrBits = choiceCtrBits;
-
- params->BTBEntries = BTBEntries;
- params->BTBTagSize = BTBTagSize;
-
- params->RASSize = RASSize;
-
- params->LQEntries = LQEntries;
- params->SQEntries = SQEntries;
-
- params->SSITSize = SSITSize;
- params->LFSTSize = LFSTSize;
-
- params->numPhysIntRegs = numPhysIntRegs;
- params->numPhysFloatRegs = numPhysFloatRegs;
- params->numIQEntries = numIQEntries;
- params->numROBEntries = numROBEntries;
-
- params->smtNumFetchingThreads = smtNumFetchingThreads;
-
- // Default smtFetchPolicy to "RoundRobin", if necessary.
- std::string round_robin_policy = "RoundRobin";
- std::string single_thread = "SingleThread";
-
- if (actual_num_threads > 1 && single_thread.compare(smtFetchPolicy) == 0)
- params->smtFetchPolicy = round_robin_policy;
- else
- params->smtFetchPolicy = smtFetchPolicy;
-
- params->smtIQPolicy = smtIQPolicy;
- params->smtLSQPolicy = smtLSQPolicy;
- params->smtLSQThreshold = smtLSQThreshold;
- params->smtROBPolicy = smtROBPolicy;
- params->smtROBThreshold = smtROBThreshold;
- params->smtCommitPolicy = smtCommitPolicy;
-
- params->instShiftAmt = 2;
-
- params->deferRegistration = defer_registration;
-
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
-
- cpu = new DerivO3CPU(params);
-
- return cpu;
-}
diff --git a/src/cpu/o3/sparc/cpu_impl.hh b/src/cpu/o3/sparc/cpu_impl.hh
deleted file mode 100644
index 068057fc0..000000000
--- a/src/cpu/o3/sparc/cpu_impl.hh
+++ /dev/null
@@ -1,298 +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.
- *
- * Authors: Gabe Black
- */
-
-#include "config/use_checker.hh"
-
-#include "arch/sparc/faults.hh"
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/miscregfile.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "cpu/checker/thread_context.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/params.hh"
-#include "cpu/o3/sparc/thread_context.hh"
-#include "cpu/o3/comm.hh"
-#include "cpu/o3/thread_state.hh"
-
-#if FULL_SYSTEM
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/kernel_stats.hh"
-#include "cpu/quiesce_event.hh"
-#include "sim/sim_exit.hh"
-#include "sim/system.hh"
-#endif
-
-template <class Impl>
-SparcO3CPU<Impl>::SparcO3CPU(Params *params) : FullO3CPU<Impl>(this, params)
-{
- DPRINTF(O3CPU, "Creating SparcO3CPU object.\n");
-
- // Setup any thread state.
- this->thread.resize(this->numThreads);
-
- for (int i = 0; i < this->numThreads; ++i) {
-#if FULL_SYSTEM
- // SMT is not supported in FS mode yet.
- assert(this->numThreads == 1);
- this->thread[i] = new Thread(this, 0);
- this->thread[i]->setStatus(ThreadContext::Suspended);
-#else
- if (i < params->workload.size()) {
- DPRINTF(O3CPU, "Workload[%i] process is %#x",
- i, this->thread[i]);
- this->thread[i] = new Thread(this, i, params->workload[i], i);
-
- this->thread[i]->setStatus(ThreadContext::Suspended);
-
- //usedTids[i] = true;
- //threadMap[i] = i;
- } else {
- //Allocate Empty thread 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
-
- ThreadContext *tc;
-
- // Setup the TC that will serve as the interface to the threads/CPU.
- SparcTC<Impl> *sparc_tc = new SparcTC<Impl>;
-
- tc = sparc_tc;
-
- // If we're using a checker, then the TC should be the
- // CheckerThreadContext.
-#if USE_CHECKER
- if (params->checker) {
- tc = new CheckerThreadContext<SparcTC<Impl> >(
- sparc_tc, this->checker);
- }
-#endif
-
- sparc_tc->cpu = this;
- sparc_tc->thread = this->thread[i];
-
-#if FULL_SYSTEM
- // Setup quiesce event.
- this->thread[i]->quiesceEvent = new EndQuiesceEvent(tc);
-#endif
- // Give the thread the TC.
- this->thread[i]->tc = tc;
- this->thread[i]->setCpuId(params->cpu_id);
-
- // Add the TC to the CPU's list of TC's.
- this->threadContexts.push_back(tc);
- }
-
- for (int i=0; i < this->numThreads; i++) {
- this->thread[i]->setFuncExeInst(0);
- }
-
- lockAddr = 0;
- lockFlag = false;
-}
-
-template <class Impl>
-void
-SparcO3CPU<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();
-}
-
-
-template <class Impl>
-TheISA::MiscReg
-SparcO3CPU<Impl>::readMiscRegNoEffect(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscRegNoEffect(misc_reg, tid);
-}
-
-template <class Impl>
-TheISA::MiscReg
-SparcO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
-{
- return this->regFile.readMiscReg(misc_reg, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setMiscRegNoEffect(int misc_reg,
- const SparcISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscRegNoEffect(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setMiscReg(int misc_reg,
- const SparcISA::MiscReg &val, unsigned tid)
-{
- this->regFile.setMiscReg(misc_reg, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::squashFromTC(unsigned tid)
-{
- this->thread[tid]->inSyscall = true;
- this->commit.generateTCEvent(tid);
-}
-
-#if FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::post_interrupt(int int_num, int index)
-{
- BaseCPU::post_interrupt(int_num, index);
-
- if (this->thread[0]->status() == ThreadContext::Suspended) {
- DPRINTF(IPI,"Suspended Processor awoke\n");
- this->threadContexts[0]->activate();
- }
-}
-
-template <class Impl>
-Fault
-SparcO3CPU<Impl>::hwrei(unsigned tid)
-{
- panic("This doesn't make sense for SPARC\n");
- return NoFault;
-}
-
-template <class Impl>
-bool
-SparcO3CPU<Impl>::simPalCheck(int palFunc, unsigned tid)
-{
- panic("This doesn't make sense for SPARC\n");
- return true;
-}
-
-template <class Impl>
-Fault
-SparcO3CPU<Impl>::getInterrupts()
-{
- // Check if there are any outstanding interrupts
- return this->interrupts.getInterrupt(this->threadContexts[0]);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::processInterrupts(Fault interrupt)
-{
- // 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.
-
- assert(interrupt != NoFault);
- this->interrupts.updateIntrInfo(this->threadContexts[0]);
-
- DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
- this->trap(interrupt, 0);
-}
-
-#endif // FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::trap(Fault fault, unsigned tid)
-{
- // Pass the thread's TC into the invoke method.
- fault->invoke(this->threadContexts[tid]);
-}
-
-#if !FULL_SYSTEM
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::syscall(int64_t callnum, int tid)
-{
- DPRINTF(O3CPU, "[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(callnum);
-
- // Decrease funcExeInst by one as the normal commit will handle
- // incrementing it.
- --(this->thread[tid]->funcExeInst);
-}
-
-template <class Impl>
-TheISA::IntReg
-SparcO3CPU<Impl>::getSyscallArg(int i, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
- SparcISA::ArgumentReg[i]);
- TheISA::IntReg val = this->readArchIntReg(idx, tid);
- if (bits(this->readMiscRegNoEffect(SparcISA::MISCREG_PSTATE, tid), 3, 3))
- val = bits(val, 31, 0);
- return val;
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setSyscallArg(int i, TheISA::IntReg val, int tid)
-{
- assert(i < TheISA::NumArgumentRegs);
- TheISA::IntReg idx = TheISA::flattenIntIndex(this->tcBase(tid),
- SparcISA::ArgumentReg[i]);
- this->setArchIntReg(idx, val, tid);
-}
-
-template <class Impl>
-void
-SparcO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
-{
- TheISA::setSyscallReturn(return_value, this->tcBase(tid));
-}
-#endif
diff --git a/src/cpu/o3/sparc/dyn_inst.hh b/src/cpu/o3/sparc/dyn_inst.hh
deleted file mode 100644
index a7ab6cd79..000000000
--- a/src/cpu/o3/sparc/dyn_inst.hh
+++ /dev/null
@@ -1,265 +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.
- *
- * Authors: Gabe Black
- */
-
-#ifndef __CPU_O3_SPARC_DYN_INST_HH__
-#define __CPU_O3_SPARC_DYN_INST_HH__
-
-#include "arch/sparc/isa_traits.hh"
-#include "arch/sparc/types.hh"
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/inst_seq.hh"
-#include "cpu/o3/sparc/cpu.hh"
-#include "cpu/o3/sparc/impl.hh"
-
-class Packet;
-
-/**
- * Mostly implementation & ISA specific SparcDynInst. 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 SparcDynInst serves as the primary interface to the CPU
- * for instructions that are executing.
- */
-template <class Impl>
-class SparcDynInst : public BaseDynInst<Impl>
-{
- public:
- /** Typedef for the CPU. */
- typedef typename Impl::O3CPU O3CPU;
-
- public:
- /** BaseDynInst constructor given a binary instruction. */
- SparcDynInst(StaticInstPtr staticInst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a binary instruction. */
- SparcDynInst(TheISA::ExtMachInst inst, Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu);
-
- /** BaseDynInst constructor given a static inst pointer. */
- SparcDynInst(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(PacketPtr pkt);
-
- private:
- /** Initializes variables. */
- void initVars();
-
- public:
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegNoEffect(int misc_reg)
- {
- return this->cpu->readMiscRegNoEffect(misc_reg, this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscReg(int misc_reg)
- {
- return this->cpu->readMiscReg(misc_reg, this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegNoEffect(int misc_reg, const TheISA::MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(misc_reg, val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscReg(int misc_reg, const TheISA::MiscReg &val)
- {
- return this->cpu->setMiscReg(misc_reg, val,
- this->threadNumber);
- }
-
- /** Reads a miscellaneous register. */
- TheISA::MiscReg readMiscRegOperandNoEffect(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscRegNoEffect(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Reads a misc. register, including any side-effects the read
- * might have as defined by the architecture.
- */
- TheISA::MiscReg readMiscRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readMiscReg(
- si->srcRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- this->threadNumber);
- }
-
- /** Sets a misc. register. */
- void setMiscRegOperandNoEffect(const StaticInst * si,
- int idx, const TheISA::MiscReg &val)
- {
- this->instResult.integer = val;
- return this->cpu->setMiscRegNoEffect(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
- /** Sets a misc. register, including any side-effects the write
- * might have as defined by the architecture.
- */
- void setMiscRegOperand(
- const StaticInst *si, int idx, const TheISA::MiscReg &val)
- {
- return this->cpu->setMiscReg(
- si->destRegIdx(idx) - TheISA::Ctrl_Base_DepTag,
- val, this->threadNumber);
- }
-
-#if FULL_SYSTEM
- /** Calls hardware return from error interrupt. */
- Fault hwrei();
- /** Traps to handle specified fault. */
- void trap(Fault fault);
- bool simPalCheck(int palFunc);
-#else
- /** Calls a syscall. */
- void syscall(int64_t callnum);
-#endif
-
- 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 readIntRegOperand(const StaticInst *si, int idx)
- {
- uint64_t val = this->cpu->readIntReg(this->_srcRegIdx[idx]);
- DPRINTF(Sparc, "Reading int reg %d (%d, %d) as %x\n", (int)this->_flatSrcRegIdx[idx], (int)this->_srcRegIdx[idx], idx, val);
- return val;
- }
-
- TheISA::FloatReg readFloatRegOperand(const StaticInst *si,
- int idx, int width)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx], width);
- }
-
- TheISA::FloatReg readFloatRegOperand(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatReg(this->_srcRegIdx[idx]);
- }
-
- TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si,
- int idx, int width)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx], width);
- }
-
- TheISA::FloatRegBits readFloatRegOperandBits(const StaticInst *si, int idx)
- {
- return this->cpu->readFloatRegBits(this->_srcRegIdx[idx]);
- }
-
- /** @todo: Make results into arrays so they can handle multiple dest
- * registers.
- */
- void setIntRegOperand(const StaticInst *si, int idx, uint64_t val)
- {
- DPRINTF(Sparc, "Setting int reg %d (%d, %d) to %x\n", (int)this->_flatDestRegIdx[idx], (int)this->_destRegIdx[idx], idx, val);
- this->cpu->setIntReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setIntRegOperand(si, idx, val);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx,
- TheISA::FloatReg val, int width)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val, width);
- }
-
- void setFloatRegOperand(const StaticInst *si, int idx, TheISA::FloatReg val)
- {
- this->cpu->setFloatReg(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperand(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si, int idx,
- TheISA::FloatRegBits val, int width)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val, width);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- void setFloatRegOperandBits(const StaticInst *si,
- int idx, TheISA::FloatRegBits val)
- {
- this->cpu->setFloatRegBits(this->_destRegIdx[idx], val);
- BaseDynInst<Impl>::setFloatRegOperandBits(si, idx, val);
- }
-
- 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_SPARC_DYN_INST_HH__
-
diff --git a/src/cpu/o3/sparc/dyn_inst_impl.hh b/src/cpu/o3/sparc/dyn_inst_impl.hh
deleted file mode 100644
index 6bfe97717..000000000
--- a/src/cpu/o3/sparc/dyn_inst_impl.hh
+++ /dev/null
@@ -1,154 +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.
- *
- * Authors: Gabe Black
- */
-
-#include "cpu/o3/sparc/dyn_inst.hh"
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(StaticInstPtr staticInst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(staticInst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(TheISA::ExtMachInst inst,
- Addr PC, Addr NPC, Addr microPC,
- Addr Pred_PC, Addr Pred_NPC, Addr Pred_MicroPC,
- InstSeqNum seq_num, O3CPU *cpu)
- : BaseDynInst<Impl>(inst, PC, NPC, microPC,
- Pred_PC, Pred_NPC, Pred_MicroPC, seq_num, cpu)
-{
- initVars();
-}
-
-template <class Impl>
-SparcDynInst<Impl>::SparcDynInst(StaticInstPtr &_staticInst)
- : BaseDynInst<Impl>(_staticInst)
-{
- initVars();
-}
-
-template <class Impl>
-void
-SparcDynInst<Impl>::initVars()
-{
- // Make sure to have the renamed register entries set to the same
- // as the normal register entries. It will allow the IQ to work
- // without any modifications.
- for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
- this->_destRegIdx[i] = this->staticInst->destRegIdx(i);
- }
-
- for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
- this->_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
- this->_readySrcRegIdx[i] = 0;
- }
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::execute()
-{
- // @todo: Pretty convoluted way to avoid squashing from happening
- // when using the TC during an instruction's execution
- // (specifically for instructions that have side-effects that use
- // the TC). Fix this.
- bool in_syscall = this->thread->inSyscall;
- this->thread->inSyscall = true;
-
- this->fault = this->staticInst->execute(this, this->traceData);
-
- this->thread->inSyscall = in_syscall;
-
- return this->fault;
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::initiateAcc()
-{
- // @todo: Pretty convoluted way to avoid squashing from happening
- // when using the TC during an instruction's execution
- // (specifically for instructions that have side-effects that use
- // the TC). Fix this.
- bool in_syscall = this->thread->inSyscall;
- this->thread->inSyscall = true;
-
- this->fault = this->staticInst->initiateAcc(this, this->traceData);
-
- this->thread->inSyscall = in_syscall;
-
- return this->fault;
-}
-
-template <class Impl>
-Fault
-SparcDynInst<Impl>::completeAcc(PacketPtr pkt)
-{
- this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
-
- return this->fault;
-}
-
-#if FULL_SYSTEM
-template <class Impl>
-Fault
-SparcDynInst<Impl>::hwrei()
-{
- return NoFault;
-}
-
-template <class Impl>
-void
-SparcDynInst<Impl>::trap(Fault fault)
-{
- this->cpu->trap(fault, this->threadNumber);
-}
-
-template <class Impl>
-bool
-SparcDynInst<Impl>::simPalCheck(int palFunc)
-{
- panic("simPalCheck called, but there's no PAL in SPARC!\n");
- return false;
-}
-#else
-template <class Impl>
-void
-SparcDynInst<Impl>::syscall(int64_t callnum)
-{
- this->cpu->syscall(callnum, this->threadNumber);
-}
-#endif
-
diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/thread_context.cc
index 4a02715bc..0d8c67643 100755
--- a/src/cpu/o3/alpha/thread_context.cc
+++ b/src/cpu/o3/thread_context.cc
@@ -26,11 +26,11 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
- * Korey Sewell
*/
#include "cpu/o3/thread_context.hh"
#include "cpu/o3/thread_context_impl.hh"
+#include "cpu/o3/impl.hh"
-template class O3ThreadContext<AlphaSimpleImpl>;
+template class O3ThreadContext<O3CPUImpl>;
diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh
index e7bdc6de5..f3058925d 100755
--- a/src/cpu/o3/thread_context.hh
+++ b/src/cpu/o3/thread_context.hh
@@ -75,16 +75,21 @@ class O3ThreadContext : public ThreadContext
/** Returns a pointer to this CPU. */
virtual BaseCPU *getCpuPtr() { return cpu; }
- /** Sets this CPU's ID. */
- virtual void setCpuId(int id) { cpu->setCpuId(id); }
-
/** Reads this CPU's ID. */
- virtual int readCpuId() { return cpu->readCpuId(); }
+ virtual int cpuId() { return cpu->cpuId(); }
+
+ virtual int contextId() { return thread->contextId(); }
+
+ virtual void setContextId(int id) { thread->setContextId(id); }
+
+ /** Returns this thread's ID number. */
+ virtual int threadId() { return thread->threadId(); }
+ virtual void setThreadId(int id) { return thread->setThreadId(id); }
-#if FULL_SYSTEM
/** Returns a pointer to the system. */
virtual System *getSystemPtr() { return cpu->system; }
+#if FULL_SYSTEM
/** Returns a pointer to physical memory. */
virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; }
@@ -94,11 +99,9 @@ class O3ThreadContext : public ThreadContext
virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
- virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL);
-
- void delVirtPort(VirtualPort *vp);
+ virtual VirtualPort *getVirtPort();
- virtual void connectMemPorts() { thread->connectMemPorts(); }
+ virtual void connectMemPorts(ThreadContext *tc) { thread->connectMemPorts(tc); }
#else
virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
@@ -153,9 +156,6 @@ class O3ThreadContext : public ThreadContext
/** Samples the function profiling information. */
virtual void profileSample();
#endif
- /** Returns this thread's ID number. */
- virtual int getThreadNum() { return thread->readTid(); }
-
/** Returns the instruction this thread is currently committing.
* Only used when an instruction faults.
*/
@@ -191,36 +191,36 @@ class O3ThreadContext : public ThreadContext
/** Reads this thread's PC. */
virtual uint64_t readPC()
- { return cpu->readPC(thread->readTid()); }
+ { return cpu->readPC(thread->threadId()); }
/** Sets this thread's PC. */
virtual void setPC(uint64_t val);
/** Reads this thread's next PC. */
virtual uint64_t readNextPC()
- { return cpu->readNextPC(thread->readTid()); }
+ { return cpu->readNextPC(thread->threadId()); }
/** Sets this thread's next PC. */
virtual void setNextPC(uint64_t val);
virtual uint64_t readMicroPC()
- { return cpu->readMicroPC(thread->readTid()); }
+ { return cpu->readMicroPC(thread->threadId()); }
virtual void setMicroPC(uint64_t val);
virtual uint64_t readNextMicroPC()
- { return cpu->readNextMicroPC(thread->readTid()); }
+ { return cpu->readNextMicroPC(thread->threadId()); }
virtual void setNextMicroPC(uint64_t val);
/** Reads a miscellaneous register. */
virtual MiscReg readMiscRegNoEffect(int misc_reg)
- { return cpu->readMiscRegNoEffect(misc_reg, thread->readTid()); }
+ { return cpu->readMiscRegNoEffect(misc_reg, thread->threadId()); }
/** Reads a misc. register, including any side-effects the
* read might have as defined by the architecture. */
virtual MiscReg readMiscReg(int misc_reg)
- { return cpu->readMiscReg(misc_reg, thread->readTid()); }
+ { return cpu->readMiscReg(misc_reg, thread->threadId()); }
/** Sets a misc. register. */
virtual void setMiscRegNoEffect(int misc_reg, const MiscReg &val);
@@ -247,22 +247,48 @@ class O3ThreadContext : public ThreadContext
virtual bool misspeculating() { return false; }
#if !FULL_SYSTEM
- /** Gets a syscall argument by index. */
- virtual IntReg getSyscallArg(int i);
-
- /** Sets a syscall argument. */
- virtual void setSyscallArg(int i, IntReg val);
-
- /** Sets the syscall return value. */
- virtual void setSyscallReturn(SyscallReturn return_value);
-
/** Executes a syscall in SE mode. */
virtual void syscall(int64_t callnum)
- { return cpu->syscall(callnum, thread->readTid()); }
+ { return cpu->syscall(callnum, thread->threadId()); }
/** Reads the funcExeInst counter. */
virtual Counter readFuncExeInst() { return thread->funcExeInst; }
+#else
+ /** Returns pointer to the quiesce event. */
+ virtual EndQuiesceEvent *getQuiesceEvent()
+ {
+ return this->thread->quiesceEvent;
+ }
#endif
+
+ virtual uint64_t readNextNPC()
+ {
+ return this->cpu->readNextNPC(this->thread->threadId());
+ }
+
+ virtual void setNextNPC(uint64_t val)
+ {
+#if THE_ISA == ALPHA_ISA
+ panic("Not supported on Alpha!");
+#endif
+ this->cpu->setNextNPC(val, this->thread->threadId());
+ }
+
+ /** This function exits the thread context in the CPU and returns
+ * 1 if the CPU has no more active threads (meaning it's OK to exit);
+ * Used in syscall-emulation mode when a thread executes the 'exit'
+ * syscall.
+ */
+ virtual int exit()
+ {
+ this->deallocate();
+
+ // If there are still threads executing in the system
+ if (this->cpu->numActiveThreads())
+ return 0; // don't exit simulation
+ else
+ return 1; // exit simulation
+ }
};
#endif
diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh
index 865d58635..fc8b66b83 100755
--- a/src/cpu/o3/thread_context_impl.hh
+++ b/src/cpu/o3/thread_context_impl.hh
@@ -36,16 +36,9 @@
#if FULL_SYSTEM
template <class Impl>
VirtualPort *
-O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc)
+O3ThreadContext<Impl>::getVirtPort()
{
- if (!src_tc)
- return thread->getVirtPort();
-
- VirtualPort *vp;
-
- vp = new VirtualPort("tc-vport", src_tc);
- thread->connectToMemFunc(vp);
- return vp;
+ return thread->getVirtPort();
}
template <class Impl>
@@ -61,16 +54,16 @@ void
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
{
// some things should already be set up
-#if FULL_SYSTEM
assert(getSystemPtr() == old_context->getSystemPtr());
-#else
+#if !FULL_SYSTEM
assert(getProcessPtr() == old_context->getProcessPtr());
#endif
// copy over functional state
setStatus(old_context->status());
copyArchRegs(old_context);
- setCpuId(old_context->readCpuId());
+ setContextId(old_context->contextId());
+ setThreadId(old_context->threadId());
#if !FULL_SYSTEM
thread->funcExeInst = old_context->readFuncExeInst();
@@ -97,24 +90,12 @@ O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
thread->trapPending = false;
}
-#if FULL_SYSTEM
-template <class Impl>
-void
-O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
-{
- if (vp != thread->getVirtPort()) {
- vp->removeConn();
- delete vp;
- }
-}
-#endif
-
template <class Impl>
void
O3ThreadContext<Impl>::activate(int delay)
{
DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Active)
return;
@@ -124,14 +105,14 @@ O3ThreadContext<Impl>::activate(int delay)
#endif
if (thread->status() == ThreadContext::Unallocated) {
- cpu->activateWhenReady(thread->readTid());
+ cpu->activateWhenReady(thread->threadId());
return;
}
thread->setStatus(ThreadContext::Active);
// status() == Suspended
- cpu->activateContext(thread->readTid(), delay);
+ cpu->activateContext(thread->threadId(), delay);
}
template <class Impl>
@@ -139,7 +120,7 @@ void
O3ThreadContext<Impl>::suspend(int delay)
{
DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Suspended)
return;
@@ -151,14 +132,14 @@ O3ThreadContext<Impl>::suspend(int delay)
/*
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
- if (cpu->check_interrupts()) {
+ if (cpu->checkInterrupts()) {
assert(status() == ThreadContext::Active);
return;
}
#endif
*/
thread->setStatus(ThreadContext::Suspended);
- cpu->suspendContext(thread->readTid());
+ cpu->suspendContext(thread->threadId());
}
template <class Impl>
@@ -166,13 +147,13 @@ void
O3ThreadContext<Impl>::deallocate(int delay)
{
DPRINTF(O3CPU, "Calling deallocate on Thread Context %d delay %d\n",
- getThreadNum(), delay);
+ threadId(), delay);
if (thread->status() == ThreadContext::Unallocated)
return;
thread->setStatus(ThreadContext::Unallocated);
- cpu->deallocateContext(thread->readTid(), true, delay);
+ cpu->deallocateContext(thread->threadId(), true, delay);
}
template <class Impl>
@@ -180,13 +161,13 @@ void
O3ThreadContext<Impl>::halt(int delay)
{
DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
- getThreadNum());
+ threadId());
if (thread->status() == ThreadContext::Halted)
return;
thread->setStatus(ThreadContext::Halted);
- cpu->haltContext(thread->readTid());
+ cpu->haltContext(thread->threadId());
}
template <class Impl>
@@ -264,7 +245,7 @@ O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
{
// This function will mess things up unless the ROB is empty and
// there are no instructions in the pipeline.
- unsigned tid = thread->readTid();
+ unsigned tid = thread->threadId();
PhysRegIndex renamed_reg;
// First loop through the integer registers.
@@ -311,7 +292,7 @@ uint64_t
O3ThreadContext<Impl>::readIntReg(int reg_idx)
{
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
- return cpu->readArchIntReg(reg_idx, thread->readTid());
+ return cpu->readArchIntReg(reg_idx, thread->threadId());
}
template <class Impl>
@@ -321,9 +302,9 @@ O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width)
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
switch(width) {
case 32:
- return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegSingle(reg_idx, thread->threadId());
case 64:
- return cpu->readArchFloatRegDouble(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegDouble(reg_idx, thread->threadId());
default:
panic("Unsupported width!");
return 0;
@@ -335,7 +316,7 @@ TheISA::FloatReg
O3ThreadContext<Impl>::readFloatReg(int reg_idx)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegSingle(reg_idx, thread->threadId());
}
template <class Impl>
@@ -344,7 +325,7 @@ O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width)
{
DPRINTF(Fault, "Reading floatint register through the TC!\n");
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}
template <class Impl>
@@ -352,7 +333,7 @@ TheISA::FloatRegBits
O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+ return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}
template <class Impl>
@@ -360,11 +341,11 @@ void
O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
{
reg_idx = TheISA::flattenIntIndex(this, reg_idx);
- cpu->setArchIntReg(reg_idx, val, thread->readTid());
+ cpu->setArchIntReg(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -375,16 +356,16 @@ O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
switch(width) {
case 32:
- cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId());
break;
case 64:
- cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegDouble(reg_idx, val, thread->threadId());
break;
}
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -393,10 +374,10 @@ void
O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->threadId());
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -407,11 +388,11 @@ O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val,
{
DPRINTF(Fault, "Setting floatint register through the TC!\n");
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -420,11 +401,11 @@ void
O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
{
reg_idx = TheISA::flattenFloatIndex(this, reg_idx);
- cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+ cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -432,11 +413,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setPC(uint64_t val)
{
- cpu->setPC(val, thread->readTid());
+ cpu->setPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -444,11 +425,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setNextPC(uint64_t val)
{
- cpu->setNextPC(val, thread->readTid());
+ cpu->setNextPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -456,11 +437,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setMicroPC(uint64_t val)
{
- cpu->setMicroPC(val, thread->readTid());
+ cpu->setMicroPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -468,11 +449,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
{
- cpu->setNextMicroPC(val, thread->readTid());
+ cpu->setNextMicroPC(val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -480,11 +461,11 @@ template <class Impl>
void
O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
- cpu->setMiscRegNoEffect(misc_reg, val, thread->readTid());
+ cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
@@ -493,36 +474,11 @@ void
O3ThreadContext<Impl>::setMiscReg(int misc_reg,
const MiscReg &val)
{
- cpu->setMiscReg(misc_reg, val, thread->readTid());
+ cpu->setMiscReg(misc_reg, val, thread->threadId());
// Squash if we're not already in a state update mode.
if (!thread->trapPending && !thread->inSyscall) {
- cpu->squashFromTC(thread->readTid());
+ cpu->squashFromTC(thread->threadId());
}
}
-#if !FULL_SYSTEM
-
-template <class Impl>
-TheISA::IntReg
-O3ThreadContext<Impl>::getSyscallArg(int i)
-{
- return cpu->getSyscallArg(i, thread->readTid());
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setSyscallArg(int i, IntReg val)
-{
- cpu->setSyscallArg(i, val, thread->readTid());
-}
-
-template <class Impl>
-void
-O3ThreadContext<Impl>::setSyscallReturn(SyscallReturn return_value)
-{
- cpu->setSyscallReturn(return_value, thread->readTid());
-}
-
-#endif // FULL_SYSTEM
-
diff --git a/src/cpu/o3/thread_state.hh b/src/cpu/o3/thread_state.hh
index d8720b3ab..1f0e7a3bb 100644
--- a/src/cpu/o3/thread_state.hh
+++ b/src/cpu/o3/thread_state.hh
@@ -77,11 +77,11 @@ struct O3ThreadState : public ThreadState {
#if FULL_SYSTEM
O3ThreadState(O3CPU *_cpu, int _thread_num)
- : ThreadState(_cpu, -1, _thread_num),
+ : ThreadState(_cpu, _thread_num),
cpu(_cpu), inSyscall(0), trapPending(0)
{
- if (cpu->params->profile) {
- profile = new FunctionProfile(cpu->params->system->kernelSymtab);
+ if (cpu->params()->profile) {
+ profile = new FunctionProfile(cpu->params()->system->kernelSymtab);
Callback *cb =
new MakeCallback<O3ThreadState,
&O3ThreadState::dumpFuncProfile>(this);
@@ -96,7 +96,7 @@ struct O3ThreadState : public ThreadState {
}
#else
O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid)
- : ThreadState(_cpu, -1, _thread_num, _process, _asid),
+ : ThreadState(_cpu, _thread_num, _process, _asid),
cpu(_cpu), inSyscall(0), trapPending(0)
{ }
#endif
diff --git a/src/cpu/ozone/OzoneCPU.py b/src/cpu/ozone/OzoneCPU.py
index b9cfb448f..37386898d 100644
--- a/src/cpu/ozone/OzoneCPU.py
+++ b/src/cpu/ozone/OzoneCPU.py
@@ -40,8 +40,6 @@ class DerivOzoneCPU(BaseCPU):
if build_env['USE_CHECKER']:
checker = Param.BaseCPU("Checker CPU")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
diff --git a/src/cpu/ozone/OzoneChecker.py b/src/cpu/ozone/OzoneChecker.py
index f20b8770e..bfa39ead9 100644
--- a/src/cpu/ozone/OzoneChecker.py
+++ b/src/cpu/ozone/OzoneChecker.py
@@ -39,5 +39,3 @@ class OzoneChecker(BaseCPU):
"If a load result is incorrect, only print a warning and do not exit")
function_trace = Param.Bool(False, "Enable function trace")
function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh
index 4cdc86c3c..ca858ce2e 100644
--- a/src/cpu/ozone/back_end.hh
+++ b/src/cpu/ozone/back_end.hh
@@ -157,13 +157,13 @@ class BackEnd
int numInsts;
int width;
- Stats::VectorDistribution<> occ_dist;
+ Stats::VectorDistribution occ_dist;
- Stats::Vector<> inst_count;
- Stats::Vector<> peak_inst_count;
- Stats::Scalar<> empty_count;
- Stats::Scalar<> current_count;
- Stats::Scalar<> fullCount;
+ Stats::Vector inst_count;
+ Stats::Vector peak_inst_count;
+ Stats::Scalar empty_count;
+ Stats::Scalar current_count;
+ Stats::Scalar fullCount;
Stats::Formula occ_rate;
Stats::Formula avg_residency;
@@ -371,45 +371,45 @@ class BackEnd
bool fetchRedirect[Impl::MaxThreads];
// number of cycles stalled for D-cache misses
-/* Stats::Scalar<> dcacheStallCycles;
+/* Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
*/
- Stats::Vector<> rob_cap_events;
- Stats::Vector<> rob_cap_inst_count;
- Stats::Vector<> iq_cap_events;
- Stats::Vector<> iq_cap_inst_count;
+ Stats::Vector rob_cap_events;
+ Stats::Vector rob_cap_inst_count;
+ Stats::Vector iq_cap_events;
+ Stats::Vector iq_cap_inst_count;
// total number of instructions executed
- Stats::Vector<> exe_inst;
- Stats::Vector<> exe_swp;
- Stats::Vector<> exe_nop;
- Stats::Vector<> exe_refs;
- Stats::Vector<> exe_loads;
- Stats::Vector<> exe_branches;
+ Stats::Vector exe_inst;
+ Stats::Vector exe_swp;
+ Stats::Vector exe_nop;
+ Stats::Vector exe_refs;
+ Stats::Vector exe_loads;
+ Stats::Vector exe_branches;
- Stats::Vector<> issued_ops;
+ Stats::Vector issued_ops;
// total number of loads forwaded from LSQ stores
- Stats::Vector<> lsq_forw_loads;
+ Stats::Vector lsq_forw_loads;
// total number of loads ignored due to invalid addresses
- Stats::Vector<> inv_addr_loads;
+ Stats::Vector inv_addr_loads;
// total number of software prefetches ignored due to invalid addresses
- Stats::Vector<> inv_addr_swpfs;
+ Stats::Vector inv_addr_swpfs;
// ready loads blocked due to memory disambiguation
- Stats::Vector<> lsq_blocked_loads;
+ Stats::Vector lsq_blocked_loads;
- Stats::Scalar<> lsqInversion;
+ Stats::Scalar lsqInversion;
- Stats::Vector<> n_issued_dist;
- Stats::VectorDistribution<> issue_delay_dist;
+ Stats::Vector n_issued_dist;
+ Stats::VectorDistribution issue_delay_dist;
- Stats::VectorDistribution<> queue_res_dist;
+ Stats::VectorDistribution queue_res_dist;
/*
- Stats::Vector<> stat_fu_busy;
- Stats::Vector2d<> stat_fuBusy;
- Stats::Vector<> dist_unissued;
- Stats::Vector2d<> stat_issued_inst_type;
+ Stats::Vector stat_fu_busy;
+ Stats::Vector2d stat_fuBusy;
+ Stats::Vector dist_unissued;
+ Stats::Vector2d stat_issued_inst_type;
Stats::Formula misspec_cnt;
Stats::Formula misspec_ipc;
@@ -422,34 +422,34 @@ class BackEnd
Stats::Formula commit_ipb;
Stats::Formula lsq_inv_rate;
*/
- Stats::Vector<> writeback_count;
- Stats::Vector<> producer_inst;
- Stats::Vector<> consumer_inst;
- Stats::Vector<> wb_penalized;
+ Stats::Vector writeback_count;
+ Stats::Vector producer_inst;
+ Stats::Vector consumer_inst;
+ Stats::Vector wb_penalized;
Stats::Formula wb_rate;
Stats::Formula wb_fanout;
Stats::Formula wb_penalized_rate;
// total number of instructions committed
- Stats::Vector<> stat_com_inst;
- Stats::Vector<> stat_com_swp;
- Stats::Vector<> stat_com_refs;
- Stats::Vector<> stat_com_loads;
- Stats::Vector<> stat_com_membars;
- Stats::Vector<> stat_com_branches;
+ Stats::Vector stat_com_inst;
+ Stats::Vector stat_com_swp;
+ Stats::Vector stat_com_refs;
+ Stats::Vector stat_com_loads;
+ Stats::Vector stat_com_membars;
+ Stats::Vector stat_com_branches;
- Stats::Distribution<> n_committed_dist;
+ Stats::Distribution n_committed_dist;
- Stats::Scalar<> commit_eligible_samples;
- Stats::Vector<> commit_eligible;
+ Stats::Scalar commit_eligible_samples;
+ Stats::Vector commit_eligible;
- Stats::Scalar<> ROB_fcount;
+ Stats::Scalar ROB_fcount;
Stats::Formula ROB_full_rate;
- Stats::Vector<> ROB_count; // cumulative ROB occupancy
+ Stats::Vector ROB_count; // cumulative ROB occupancy
Stats::Formula ROB_occ_rate;
- Stats::VectorDistribution<> ROB_occ_dist;
+ Stats::VectorDistribution ROB_occ_dist;
public:
void dumpInsts();
};
@@ -482,8 +482,8 @@ BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx)
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
-// status = DcacheMissStall;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
} else {
// do functional access
@@ -524,8 +524,8 @@ BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx)
if (result != MA_HIT && dcacheInterface->doEvents()) {
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
-// status = DcacheMissStall;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
DPRINTF(OzoneCPU, "Dcache miss stall!\n");
}
}
diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc
index 5a3a69dff..e0570fd16 100644
--- a/src/cpu/ozone/base_dyn_inst.cc
+++ b/src/cpu/ozone/base_dyn_inst.cc
@@ -33,7 +33,3 @@
// Explicit instantiation
template class BaseDynInst<OzoneImpl>;
-
-template <>
-int
-BaseDynInst<OzoneImpl>::instcount = 0;
diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh
index b0ea2cba9..0bfb4bfa9 100644
--- a/src/cpu/ozone/cpu.hh
+++ b/src/cpu/ozone/cpu.hh
@@ -116,10 +116,6 @@ class OzoneCPU : public BaseCPU
BaseCPU *getCpuPtr();
- void setCpuId(int id);
-
- int readCpuId() { return thread->readCpuId(); }
-
TheISA::ITB *getITBPtr() { return cpu->itb; }
TheISA::DTB * getDTBPtr() { return cpu->dtb; }
@@ -134,10 +130,8 @@ class OzoneCPU : public BaseCPU
FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL)
- { return thread->getVirtPort(tc); }
-
- void delVirtPort(VirtualPort *vp);
+ VirtualPort *getVirtPort()
+ { return thread->getVirtPort(); }
#else
TranslatingPort *getMemPort() { return thread->getMemPort(); }
@@ -182,7 +176,7 @@ class OzoneCPU : public BaseCPU
void profileSample();
#endif
- int getThreadNum();
+ int threadId();
// Also somewhat obnoxious. Really only used for the TLB fault.
TheISA::MachInst getInst();
@@ -252,30 +246,11 @@ class OzoneCPU : public BaseCPU
bool misspeculating() { return false; }
#if !FULL_SYSTEM
- TheISA::IntReg getSyscallArg(int i)
- {
- assert(i < TheISA::NumArgumentRegs);
- return thread->renameTable[TheISA::ArgumentReg[i]]->readIntResult();
- }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, TheISA::IntReg val)
- {
- assert(i < TheISA::NumArgumentRegs);
- thread->renameTable[TheISA::ArgumentReg[i]]->setIntResult(i);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- { cpu->setSyscallReturn(return_value, thread->readTid()); }
-
Counter readFuncExeInst() { return thread->funcExeInst; }
void setFuncExeInst(Counter new_val)
{ thread->funcExeInst = new_val; }
#endif
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Alpha!"); }
};
// Ozone specific thread context
@@ -296,6 +271,11 @@ class OzoneCPU : public BaseCPU
// main simulation loop (one cycle)
void tick();
+#ifndef NDEBUG
+ /** Count of total number of dynamic instructions in flight. */
+ int instcount;
+#endif
+
std::set<InstSeqNum> snList;
std::set<Addr> lockAddrList;
private:
@@ -337,7 +317,7 @@ class OzoneCPU : public BaseCPU
Status _status;
public:
- void post_interrupt(int int_num, int index);
+ void wakeup();
void zero_fill_64(Addr addr) {
static int warned = 0;
@@ -358,12 +338,6 @@ class OzoneCPU : public BaseCPU
public:
BaseCPU *getCpuPtr() { return this; }
- void setCpuId(int id) { cpuId = id; }
-
- int readCpuId() { return cpuId; }
-
- int cpuId;
-
void switchOut();
void signalSwitched();
void takeOverFrom(BaseCPU *oldCPU);
@@ -416,7 +390,7 @@ class OzoneCPU : public BaseCPU
Counter startNumLoad;
// number of idle cycles
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
public:
@@ -425,59 +399,20 @@ class OzoneCPU : public BaseCPU
void demapPage(Addr vaddr, uint64_t asn)
{
- itb->demap(vaddr, asn);
- dtb->demap(vaddr, asn);
+ cpu->itb->demap(vaddr, asn);
+ cpu->dtb->demap(vaddr, asn);
}
void demapInstPage(Addr vaddr, uint64_t asn)
{
- itb->demap(vaddr, asn);
+ cpu->itb->demap(vaddr, asn);
}
void demapDataPage(Addr vaddr, uint64_t asn)
{
- dtb->demap(vaddr, asn);
- }
-
-#if FULL_SYSTEM
- /** Translates instruction requestion. */
- Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return itb->translate(req, thread->getTC());
- }
-
- /** Translates data read request. */
- Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return dtb->translate(req, thread->getTC(), false);
- }
-
- /** Translates data write request. */
- Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return dtb->translate(req, thread->getTC(), true);
- }
-
-#else
- /** Translates instruction requestion in syscall emulation mode. */
- Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
- }
-
- /** Translates data read request in syscall emulation mode. */
- Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
+ cpu->dtb->demap(vaddr, asn);
}
- /** Translates data write request in syscall emulation mode. */
- Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
- {
- return thread->getProcessPtr()->pTable->translate(req);
- }
-#endif
-
/** CPU read function, forwards read to LSQ. */
template <class T>
Fault read(Request *req, T &data, int load_idx)
@@ -517,7 +452,6 @@ class OzoneCPU : public BaseCPU
void processInterrupts();
#else
void syscall(uint64_t &callnum);
- void setSyscallReturn(SyscallReturn return_value, int tid);
#endif
ThreadContext *tcBase() { return tc; }
@@ -539,7 +473,7 @@ class OzoneCPU : public BaseCPU
bool lockFlag;
- Stats::Scalar<> quiesceCycles;
+ Stats::Scalar quiesceCycles;
Checker<DynInstPtr> *checker;
};
diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh
index 0c7105382..aa76c8aa6 100644
--- a/src/cpu/ozone/cpu_impl.hh
+++ b/src/cpu/ozone/cpu_impl.hh
@@ -95,6 +95,9 @@ OzoneCPU<Impl>::OzoneCPU(Params *p)
: BaseCPU(p), thread(this, 0, p->workload[0], 0),
tickEvent(this, p->width),
#endif
+#ifndef NDEBUG
+ instcount(0),
+#endif
comm(5, 5)
{
frontEnd = new FrontEnd(p);
@@ -417,7 +420,7 @@ OzoneCPU<Impl>::init()
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, tc->readCpuId());
+ TheISA::initCPU(tc, tc->contextId());
}
#endif
frontEnd->renameTable.copyFrom(thread.renameTable);
@@ -579,16 +582,14 @@ OzoneCPU<Impl>::dbg_vtophys(Addr addr)
#if FULL_SYSTEM
template <class Impl>
void
-OzoneCPU<Impl>::post_interrupt(int int_num, int index)
+OzoneCPU<Impl>::wakeup()
{
- BaseCPU::post_interrupt(int_num, index);
-
if (_status == Idle) {
DPRINTF(IPI,"Suspended Processor awoke\n");
-// thread.activate();
+// thread.activate();
// Hack for now. Otherwise might have to go through the tc, or
// I need to figure out what's the right thing to call.
- activateContext(thread.readTid(), 1);
+ activateContext(thread.threadId(), 1);
}
}
#endif // FULL_SYSTEM
@@ -647,26 +648,6 @@ OzoneCPU<Impl>::syscall(uint64_t &callnum)
frontEnd->renameTable.copyFrom(thread.renameTable);
backEnd->renameTable.copyFrom(thread.renameTable);
}
-
-template <class Impl>
-void
-OzoneCPU<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
- thread.renameTable[SyscallSuccessReg]->setIntResult(0);
- thread.renameTable[ReturnValueReg]->setIntResult(
- return_value.value());
- } else {
- // got an error, return details
- thread.renameTable[SyscallSuccessReg]->setIntResult((IntReg) -1);
- thread.renameTable[ReturnValueReg]->setIntResult(
- -return_value.value());
- }
-}
#else
template <class Impl>
Fault
@@ -693,10 +674,10 @@ OzoneCPU<Impl>::processInterrupts()
// Check if there are any outstanding interrupts
//Handle the interrupts
- Fault interrupt = this->interrupts.getInterrupt(thread.getTC());
+ Fault interrupt = this->interrupts->getInterrupt(thread.getTC());
if (interrupt != NoFault) {
- this->interrupts.updateIntrInfo(thread.getTC());
+ this->interrupts->updateIntrInfo(thread.getTC());
interrupt->invoke(thread.getTC());
}
}
@@ -711,7 +692,7 @@ OzoneCPU<Impl>::simPalCheck(int palFunc)
switch (palFunc) {
case PAL::halt:
- haltContext(thread.readTid());
+ haltContext(thread.threadId());
if (--System::numSystemsRunning == 0)
exitSimLoop("all cpus halted");
break;
@@ -736,24 +717,6 @@ OzoneCPU<Impl>::OzoneTC::getCpuPtr()
template <class Impl>
void
-OzoneCPU<Impl>::OzoneTC::setCpuId(int id)
-{
- cpu->cpuId = id;
- thread->setCpuId(id);
-}
-
-#if FULL_SYSTEM
-template <class Impl>
-void
-OzoneCPU<Impl>::OzoneTC::delVirtPort(VirtualPort *vp)
-{
- vp->removeConn();
- delete vp;
-}
-#endif
-
-template <class Impl>
-void
OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
{
thread->setStatus(new_status);
@@ -763,7 +726,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::activate(int delay)
{
- cpu->activateContext(thread->readTid(), delay);
+ cpu->activateContext(thread->threadId(), delay);
}
/// Set the status to Suspended.
@@ -771,7 +734,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::suspend()
{
- cpu->suspendContext(thread->readTid());
+ cpu->suspendContext(thread->threadId());
}
/// Set the status to Unallocated.
@@ -779,7 +742,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::deallocate(int delay)
{
- cpu->deallocateContext(thread->readTid(), delay);
+ cpu->deallocateContext(thread->threadId(), delay);
}
/// Set the status to Halted.
@@ -787,7 +750,7 @@ template <class Impl>
void
OzoneCPU<Impl>::OzoneTC::halt()
{
- cpu->haltContext(thread->readTid());
+ cpu->haltContext(thread->threadId());
}
#if FULL_SYSTEM
@@ -813,7 +776,8 @@ OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
// copy over functional state
setStatus(old_context->status());
copyArchRegs(old_context);
- setCpuId(old_context->readCpuId());
+ setCpuId(old_context->cpuId());
+ setContextId(old_context->contextId());
thread->setInst(old_context->getInst());
#if !FULL_SYSTEM
@@ -901,9 +865,9 @@ OzoneCPU<Impl>::OzoneTC::profileSample()
template <class Impl>
int
-OzoneCPU<Impl>::OzoneTC::getThreadNum()
+OzoneCPU<Impl>::OzoneTC::threadId()
{
- return thread->readTid();
+ return thread->threadId();
}
template <class Impl>
diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh
index 667392c06..38fc89e3f 100644
--- a/src/cpu/ozone/front_end.hh
+++ b/src/cpu/ozone/front_end.hh
@@ -275,48 +275,48 @@ class FrontEnd
private:
// number of idle cycles
/*
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
*/
// @todo: Consider making these vectors and tracking on a per thread basis.
/** Stat for total number of cycles stalled due to an icache miss. */
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
/** Stat for total number of fetched instructions. */
- Stats::Scalar<> fetchedInsts;
- Stats::Scalar<> fetchedBranches;
+ Stats::Scalar fetchedInsts;
+ Stats::Scalar fetchedBranches;
/** Stat for total number of predicted branches. */
- Stats::Scalar<> predictedBranches;
+ Stats::Scalar predictedBranches;
/** Stat for total number of cycles spent fetching. */
- Stats::Scalar<> fetchCycles;
+ Stats::Scalar fetchCycles;
- Stats::Scalar<> fetchIdleCycles;
+ Stats::Scalar fetchIdleCycles;
/** Stat for total number of cycles spent squashing. */
- Stats::Scalar<> fetchSquashCycles;
+ Stats::Scalar fetchSquashCycles;
/** Stat for total number of cycles spent blocked due to other stages in
* the pipeline.
*/
- Stats::Scalar<> fetchBlockedCycles;
+ Stats::Scalar fetchBlockedCycles;
/** Stat for total number of fetched cache lines. */
- Stats::Scalar<> fetchedCacheLines;
+ Stats::Scalar fetchedCacheLines;
- Stats::Scalar<> fetchIcacheSquashes;
+ Stats::Scalar fetchIcacheSquashes;
/** Distribution of number of instructions fetched each cycle. */
- Stats::Distribution<> fetchNisnDist;
-// Stats::Vector<> qfull_iq_occupancy;
-// Stats::VectorDistribution<> qfull_iq_occ_dist_;
+ Stats::Distribution fetchNisnDist;
+// Stats::Vector qfull_iq_occupancy;
+// Stats::VectorDistribution qfull_iq_occ_dist_;
Stats::Formula idleRate;
Stats::Formula branchRate;
Stats::Formula fetchRate;
- Stats::Scalar<> IFQCount; // cumulative IFQ occupancy
+ Stats::Scalar IFQCount; // cumulative IFQ occupancy
Stats::Formula IFQOccupancy;
Stats::Formula IFQLatency;
- Stats::Scalar<> IFQFcount; // cumulative IFQ full count
+ Stats::Scalar IFQFcount; // cumulative IFQ full count
Stats::Formula IFQFullRate;
- Stats::Scalar<> dispatchCountStat;
- Stats::Scalar<> dispatchedSerializing;
- Stats::Scalar<> dispatchedTempSerializing;
- Stats::Scalar<> dispatchSerializeStallCycles;
+ Stats::Scalar dispatchCountStat;
+ Stats::Scalar dispatchedSerializing;
+ Stats::Scalar dispatchedTempSerializing;
+ Stats::Scalar dispatchSerializeStallCycles;
Stats::Formula dispatchRate;
Stats::Formula regIntFull;
Stats::Formula regFpFull;
diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh
index 198ce0308..6b47ef539 100644
--- a/src/cpu/ozone/front_end_impl.hh
+++ b/src/cpu/ozone/front_end_impl.hh
@@ -477,10 +477,10 @@ FrontEnd<Impl>::fetchCacheLine()
// Setup the memReq to do a read of the first isntruction's address.
// Set the appropriate read size and flags as well.
memReq = new Request(0, fetch_PC, cacheBlkSize, 0,
- PC, cpu->readCpuId(), 0);
+ PC, cpu->thread->contextId());
// Translate the instruction request.
- fault = cpu->translateInstReq(memReq, thread);
+ fault = cpu->itb->translateAtomic(memReq, thread);
// Now do the timing access to see whether or not the instruction
// exists within the cache.
diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh
index aef29b1e2..e930144be 100644
--- a/src/cpu/ozone/inorder_back_end.hh
+++ b/src/cpu/ozone/inorder_back_end.hh
@@ -192,7 +192,7 @@ class InorderBackEnd
TimeBuffer<CommStruct> *comm;
// number of cycles stalled for D-cache misses
- Stats::Scalar<> dcacheStallCycles;
+ Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
};
@@ -204,7 +204,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags)
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
- Fault fault = cpu->translateDataReadReq(memReq);
+ Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), false);
// if we have a cache, do cache access too
if (fault == NoFault && dcacheInterface) {
@@ -222,7 +222,7 @@ InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags)
// are executed twice.
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissLoadStall;
DPRINTF(IBE, "Dcache miss stall!\n");
} else {
@@ -245,11 +245,11 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
memReq->reset(addr, sizeof(T), flags);
// translate to physical address
- Fault fault = cpu->translateDataWriteReq(memReq);
+ Fault fault = cpu->dtb->translateAtomic(memReq, thread->getTC(), true);
if (fault == NoFault && dcacheInterface) {
memReq->cmd = Write;
-// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
+// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
memReq->completionEvent = NULL;
memReq->time = curTick;
memReq->flags &= ~INST_READ;
@@ -261,7 +261,7 @@ InorderBackEnd<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
if (result != MA_HIT) {
memReq->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissStoreStall;
DPRINTF(IBE, "Dcache miss stall!\n");
} else {
@@ -307,7 +307,7 @@ InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx)
if (result != MA_HIT) {
req->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissLoadStall;
DPRINTF(IBE, "Dcache miss load stall!\n");
} else {
@@ -372,7 +372,7 @@ InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx)
if (result != MA_HIT) {
req->completionEvent = &cacheCompletionEvent;
lastDcacheStall = curTick;
-// unscheduleTickEvent();
+// unscheduleTickEvent();
status = DcacheMissStoreStall;
DPRINTF(IBE, "Dcache miss store stall!\n");
} else {
diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh
index cf8634a42..798b628d6 100644
--- a/src/cpu/ozone/inorder_back_end_impl.hh
+++ b/src/cpu/ozone/inorder_back_end_impl.hh
@@ -149,8 +149,7 @@ InorderBackEnd<Impl>::tick()
// if (interrupt) then set thread PC, stall front end, record that
// I'm waiting for it to drain. (for now just squash)
#if FULL_SYSTEM
- if (interruptBlocked ||
- cpu->check_interrupts(tc)) {
+ if (interruptBlocked || cpu->checkInterrupts(tc)) {
if (!robEmpty()) {
interruptBlocked = true;
//AlphaDep
diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh
index a11d5204b..e840d5c21 100644
--- a/src/cpu/ozone/inst_queue.hh
+++ b/src/cpu/ozone/inst_queue.hh
@@ -473,35 +473,35 @@ class InstQueue
void dumpInsts();
/** Stat for number of instructions added. */
- Stats::Scalar<> iqInstsAdded;
+ Stats::Scalar iqInstsAdded;
/** Stat for number of non-speculative instructions added. */
- Stats::Scalar<> iqNonSpecInstsAdded;
-// Stats::Scalar<> iqIntInstsAdded;
+ Stats::Scalar iqNonSpecInstsAdded;
+// Stats::Scalar iqIntInstsAdded;
/** Stat for number of integer instructions issued. */
- Stats::Scalar<> iqIntInstsIssued;
-// Stats::Scalar<> iqFloatInstsAdded;
+ Stats::Scalar iqIntInstsIssued;
+// Stats::Scalar iqFloatInstsAdded;
/** Stat for number of floating point instructions issued. */
- Stats::Scalar<> iqFloatInstsIssued;
-// Stats::Scalar<> iqBranchInstsAdded;
+ Stats::Scalar iqFloatInstsIssued;
+// Stats::Scalar iqBranchInstsAdded;
/** Stat for number of branch instructions issued. */
- Stats::Scalar<> iqBranchInstsIssued;
-// Stats::Scalar<> iqMemInstsAdded;
+ Stats::Scalar iqBranchInstsIssued;
+// Stats::Scalar iqMemInstsAdded;
/** Stat for number of memory instructions issued. */
- Stats::Scalar<> iqMemInstsIssued;
-// Stats::Scalar<> iqMiscInstsAdded;
+ Stats::Scalar iqMemInstsIssued;
+// Stats::Scalar iqMiscInstsAdded;
/** Stat for number of miscellaneous instructions issued. */
- Stats::Scalar<> iqMiscInstsIssued;
+ Stats::Scalar iqMiscInstsIssued;
/** Stat for number of squashed instructions that were ready to issue. */
- Stats::Scalar<> iqSquashedInstsIssued;
+ Stats::Scalar iqSquashedInstsIssued;
/** Stat for number of squashed instructions examined when squashing. */
- Stats::Scalar<> iqSquashedInstsExamined;
+ Stats::Scalar iqSquashedInstsExamined;
/** Stat for number of squashed instruction operands examined when
* squashing.
*/
- Stats::Scalar<> iqSquashedOperandsExamined;
+ Stats::Scalar iqSquashedOperandsExamined;
/** Stat for number of non-speculative instructions removed due to a squash.
*/
- Stats::Scalar<> iqSquashedNonSpecRemoved;
+ Stats::Scalar iqSquashedNonSpecRemoved;
};
diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh
index 981682c26..47be245e5 100644
--- a/src/cpu/ozone/lsq_unit.hh
+++ b/src/cpu/ozone/lsq_unit.hh
@@ -331,7 +331,7 @@ class OzoneLSQ {
//list<InstSeqNum> mshrSeqNums;
- //Stats::Scalar<> dcacheStallCycles;
+ //Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
/** Wire to read information from the issue stage time queue. */
diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh
index 84a90eede..c24410520 100644
--- a/src/cpu/ozone/lsq_unit_impl.hh
+++ b/src/cpu/ozone/lsq_unit_impl.hh
@@ -553,7 +553,7 @@ OzoneLSQ<Impl>::writebackStores()
MemReqPtr req = storeQueue[storeWBIdx].req;
storeQueue[storeWBIdx].committed = true;
-// Fault fault = cpu->translateDataReadReq(req);
+// Fault fault = cpu->translateDataReadReq(req);
req->cmd = Write;
req->completionEvent = NULL;
req->time = curTick;
diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh
index a335ab7dc..4a1657c9b 100644
--- a/src/cpu/ozone/lw_back_end.hh
+++ b/src/cpu/ozone/lw_back_end.hh
@@ -326,47 +326,47 @@ class LWBackEnd
bool exactFullStall;
// number of cycles stalled for D-cache misses
-/* Stats::Scalar<> dcacheStallCycles;
+/* Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
*/
- Stats::Vector<> robCapEvents;
- Stats::Vector<> robCapInstCount;
- Stats::Vector<> iqCapEvents;
- Stats::Vector<> iqCapInstCount;
+ Stats::Vector robCapEvents;
+ Stats::Vector robCapInstCount;
+ Stats::Vector iqCapEvents;
+ Stats::Vector iqCapInstCount;
// total number of instructions executed
- Stats::Vector<> exeInst;
- Stats::Vector<> exeSwp;
- Stats::Vector<> exeNop;
- Stats::Vector<> exeRefs;
- Stats::Vector<> exeLoads;
- Stats::Vector<> exeBranches;
+ Stats::Vector exeInst;
+ Stats::Vector exeSwp;
+ Stats::Vector exeNop;
+ Stats::Vector exeRefs;
+ Stats::Vector exeLoads;
+ Stats::Vector exeBranches;
- Stats::Vector<> issuedOps;
+ Stats::Vector issuedOps;
// total number of loads forwaded from LSQ stores
- Stats::Vector<> lsqForwLoads;
+ Stats::Vector lsqForwLoads;
// total number of loads ignored due to invalid addresses
- Stats::Vector<> invAddrLoads;
+ Stats::Vector invAddrLoads;
// total number of software prefetches ignored due to invalid addresses
- Stats::Vector<> invAddrSwpfs;
+ Stats::Vector invAddrSwpfs;
// ready loads blocked due to memory disambiguation
- Stats::Vector<> lsqBlockedLoads;
+ Stats::Vector lsqBlockedLoads;
- Stats::Scalar<> lsqInversion;
+ Stats::Scalar lsqInversion;
- Stats::Vector<> nIssuedDist;
+ Stats::Vector nIssuedDist;
/*
- Stats::VectorDistribution<> issueDelayDist;
+ Stats::VectorDistribution issueDelayDist;
- Stats::VectorDistribution<> queueResDist;
+ Stats::VectorDistribution queueResDist;
*/
/*
- Stats::Vector<> stat_fu_busy;
- Stats::Vector2d<> stat_fuBusy;
- Stats::Vector<> dist_unissued;
- Stats::Vector2d<> stat_issued_inst_type;
+ Stats::Vector stat_fu_busy;
+ Stats::Vector2d stat_fuBusy;
+ Stats::Vector dist_unissued;
+ Stats::Vector2d stat_issued_inst_type;
Stats::Formula misspec_cnt;
Stats::Formula misspec_ipc;
@@ -379,37 +379,37 @@ class LWBackEnd
Stats::Formula commit_ipb;
Stats::Formula lsq_inv_rate;
*/
- Stats::Vector<> writebackCount;
- Stats::Vector<> producerInst;
- Stats::Vector<> consumerInst;
- Stats::Vector<> wbPenalized;
+ Stats::Vector writebackCount;
+ Stats::Vector producerInst;
+ Stats::Vector consumerInst;
+ Stats::Vector wbPenalized;
Stats::Formula wbRate;
Stats::Formula wbFanout;
Stats::Formula wbPenalizedRate;
// total number of instructions committed
- Stats::Vector<> statComInst;
- Stats::Vector<> statComSwp;
- Stats::Vector<> statComRefs;
- Stats::Vector<> statComLoads;
- Stats::Vector<> statComMembars;
- Stats::Vector<> statComBranches;
+ Stats::Vector statComInst;
+ Stats::Vector statComSwp;
+ Stats::Vector statComRefs;
+ Stats::Vector statComLoads;
+ Stats::Vector statComMembars;
+ Stats::Vector statComBranches;
- Stats::Distribution<> nCommittedDist;
+ Stats::Distribution nCommittedDist;
- Stats::Scalar<> commitEligibleSamples;
- Stats::Vector<> commitEligible;
+ Stats::Scalar commitEligibleSamples;
+ Stats::Vector commitEligible;
- Stats::Vector<> squashedInsts;
- Stats::Vector<> ROBSquashedInsts;
+ Stats::Vector squashedInsts;
+ Stats::Vector ROBSquashedInsts;
- Stats::Scalar<> ROBFcount;
+ Stats::Scalar ROBFcount;
Stats::Formula ROBFullRate;
- Stats::Vector<> ROBCount; // cumulative ROB occupancy
+ Stats::Vector ROBCount; // cumulative ROB occupancy
Stats::Formula ROBOccRate;
-// Stats::VectorDistribution<> ROBOccDist;
+// Stats::VectorDistribution ROBOccDist;
public:
void dumpInsts();
diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh
index a5d79a789..60c42edd3 100644
--- a/src/cpu/ozone/lw_back_end_impl.hh
+++ b/src/cpu/ozone/lw_back_end_impl.hh
@@ -525,10 +525,7 @@ template <class Impl>
void
LWBackEnd<Impl>::checkInterrupts()
{
- if (cpu->checkInterrupts &&
- cpu->check_interrupts(tc) &&
- !trapSquash &&
- !tcSquash) {
+ if (cpu->checkInterrupts(tc) && !trapSquash && !tcSquash) {
frontEnd->interruptPending = true;
if (robEmpty() && !LSQ.hasStoresToWB()) {
// Will need to squash all instructions currently in flight and have
diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh
index 7fc8b6307..4f8101bc0 100644
--- a/src/cpu/ozone/lw_lsq.hh
+++ b/src/cpu/ozone/lw_lsq.hh
@@ -39,6 +39,7 @@
#include "arch/faults.hh"
#include "arch/types.hh"
#include "config/full_system.hh"
+#include "base/fast_alloc.hh"
#include "base/hashmap.hh"
#include "cpu/inst_seq.hh"
#include "mem/packet.hh"
@@ -301,7 +302,7 @@ class OzoneLWLSQ {
};
/** Derived class to hold any sender state the LSQ needs. */
- class LSQSenderState : public Packet::SenderState
+ class LSQSenderState : public Packet::SenderState, public FastAlloc
{
public:
/** Default constructor. */
@@ -410,9 +411,9 @@ class OzoneLWLSQ {
//list<InstSeqNum> mshrSeqNums;
/** Tota number of memory ordering violations. */
- Stats::Scalar<> lsqMemOrderViolation;
+ Stats::Scalar lsqMemOrderViolation;
- //Stats::Scalar<> dcacheStallCycles;
+ //Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
// Make these per thread?
diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc
index 438218df2..79f5277d5 100644
--- a/src/cpu/pc_event.cc
+++ b/src/cpu/pc_event.cc
@@ -34,12 +34,12 @@
#include <string>
#include <utility>
+#include "base/debug.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "cpu/pc_event.hh"
-#include "sim/debug.hh"
#include "sim/core.hh"
#include "sim/system.hh"
diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc
index 81384d529..38ffb74e4 100644
--- a/src/cpu/quiesce_event.cc
+++ b/src/cpu/quiesce_event.cc
@@ -33,7 +33,7 @@
#include "cpu/quiesce_event.hh"
EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc)
- : Event(&mainEventQueue), tc(_tc)
+ : tc(_tc)
{
}
diff --git a/src/cpu/simple/AtomicSimpleCPU.py b/src/cpu/simple/AtomicSimpleCPU.py
index 28c2aa9c9..b7174bb43 100644
--- a/src/cpu/simple/AtomicSimpleCPU.py
+++ b/src/cpu/simple/AtomicSimpleCPU.py
@@ -28,18 +28,15 @@
from m5.params import *
from m5 import build_env
-from BaseCPU import BaseCPU
+from BaseSimpleCPU import BaseSimpleCPU
-class AtomicSimpleCPU(BaseCPU):
+class AtomicSimpleCPU(BaseSimpleCPU):
type = 'AtomicSimpleCPU'
width = Param.Int(1, "CPU width")
- simulate_stalls = Param.Bool(False, "Simulate cache stall cycles")
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
+ simulate_data_stalls = Param.Bool(False, "Simulate dcache stall cycles")
+ simulate_inst_stalls = Param.Bool(False, "Simulate icache stall cycles")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
physmem_port = Port("Physical Memory Port")
- _mem_ports = BaseCPU._mem_ports + \
+ _mem_ports = BaseSimpleCPU._mem_ports + \
['icache_port', 'dcache_port', 'physmem_port']
diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py
new file mode 100644
index 000000000..9f528bc20
--- /dev/null
+++ b/src/cpu/simple/BaseSimpleCPU.py
@@ -0,0 +1,34 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from BaseCPU import BaseCPU
+
+class BaseSimpleCPU(BaseCPU):
+ type = 'BaseSimpleCPU'
+ abstract = True
diff --git a/src/cpu/simple/SConscript b/src/cpu/simple/SConscript
index c090a938c..76598666f 100644
--- a/src/cpu/simple/SConscript
+++ b/src/cpu/simple/SConscript
@@ -47,3 +47,4 @@ if 'AtomicSimpleCPU' in env['CPU_MODELS'] or \
if need_simple_base:
Source('base.cc')
+ SimObject('BaseSimpleCPU.py')
diff --git a/src/cpu/simple/TimingSimpleCPU.py b/src/cpu/simple/TimingSimpleCPU.py
index 7e777e813..ce6839241 100644
--- a/src/cpu/simple/TimingSimpleCPU.py
+++ b/src/cpu/simple/TimingSimpleCPU.py
@@ -28,14 +28,10 @@
from m5.params import *
from m5 import build_env
-from BaseCPU import BaseCPU
+from BaseSimpleCPU import BaseSimpleCPU
-class TimingSimpleCPU(BaseCPU):
+class TimingSimpleCPU(BaseSimpleCPU):
type = 'TimingSimpleCPU'
- function_trace = Param.Bool(False, "Enable function trace")
- function_trace_start = Param.Tick(0, "Cycle to start function trace")
- if build_env['FULL_SYSTEM']:
- profile = Param.Latency('0ns', "trace the kernel stack")
icache_port = Port("Instruction Port")
dcache_port = Port("Data Port")
- _mem_ports = BaseCPU._mem_ports + ['icache_port', 'dcache_port']
+ _mem_ports = BaseSimpleCPU._mem_ports + ['icache_port', 'dcache_port']
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index 23bd40b9b..17f93c882 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -43,7 +43,7 @@ using namespace std;
using namespace TheISA;
AtomicSimpleCPU::TickEvent::TickEvent(AtomicSimpleCPU *c)
- : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
+ : Event(CPU_Tick_Pri), cpu(c)
{
}
@@ -79,13 +79,12 @@ void
AtomicSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, tc->contextId());
}
#endif
if (hasPhysMemPort) {
@@ -94,9 +93,10 @@ AtomicSimpleCPU::init()
physmemPort.getPeerAddressRanges(pmAddrList, snoop);
physMemAddr = *pmAddrList.begin();
}
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ // Atomic doesn't do MT right now, so contextId == threadId
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
bool
@@ -148,13 +148,14 @@ AtomicSimpleCPU::DcachePort::setPeer(Port *port)
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
- cpu->tcBase()->connectMemPorts();
+ cpu->tcBase()->connectMemPorts(cpu->tcBase());
#endif
}
-AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
- : BaseSimpleCPU(p), tickEvent(this),
- width(p->width), simulate_stalls(p->simulate_stalls),
+AtomicSimpleCPU::AtomicSimpleCPU(AtomicSimpleCPUParams *p)
+ : BaseSimpleCPU(p), tickEvent(this), width(p->width),
+ simulate_data_stalls(p->simulate_data_stalls),
+ simulate_inst_stalls(p->simulate_inst_stalls),
icachePort(name() + "-iport", this), dcachePort(name() + "-iport", this),
physmemPort(name() + "-iport", this), hasPhysMemPort(false)
{
@@ -175,8 +176,6 @@ AtomicSimpleCPU::serialize(ostream &os)
{
SimObject::State so_state = SimObject::getState();
SERIALIZE_ENUM(so_state);
- Status _status = status();
- SERIALIZE_ENUM(_status);
BaseSimpleCPU::serialize(os);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
@@ -187,7 +186,6 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
SimObject::State so_state;
UNSERIALIZE_ENUM(so_state);
- UNSERIALIZE_ENUM(_status);
BaseSimpleCPU::unserialize(cp, section);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
}
@@ -203,16 +201,15 @@ AtomicSimpleCPU::resume()
changeState(SimObject::Running);
if (thread->status() == ThreadContext::Active) {
- if (!tickEvent.scheduled()) {
- tickEvent.schedule(nextCycle());
- }
+ if (!tickEvent.scheduled())
+ schedule(tickEvent, nextCycle());
}
}
void
AtomicSimpleCPU::switchOut()
{
- assert(status() == Running || status() == Idle);
+ assert(_status == Running || _status == Idle);
_status = SwitchedOut;
tickEvent.squash();
@@ -232,7 +229,7 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
ThreadContext *tc = threadContexts[i];
if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
- tickEvent.schedule(nextCycle());
+ schedule(tickEvent, nextCycle());
break;
}
}
@@ -240,10 +237,9 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
- ifetch_req.setThreadContext(cpuId, 0); // Add thread ID if we add MT
- data_read_req.setThreadContext(cpuId, 0); // Add thread ID here too
- data_write_req.setThreadContext(cpuId, 0); // Add thread ID here too
+ ifetch_req.setThreadContext(_cpuId, 0); // Add thread ID if we add MT
+ data_read_req.setThreadContext(_cpuId, 0); // Add thread ID here too
+ data_write_req.setThreadContext(_cpuId, 0); // Add thread ID here too
}
@@ -262,7 +258,7 @@ AtomicSimpleCPU::activateContext(int thread_num, int delay)
numCycles += tickToCycles(thread->lastActivate - thread->lastSuspend);
//Make sure ticks are still on multiples of cycles
- tickEvent.schedule(nextCycle(curTick + ticks(delay)));
+ schedule(tickEvent, nextCycle(curTick + ticks(delay)));
_status = Running;
}
@@ -280,7 +276,7 @@ AtomicSimpleCPU::suspendContext(int thread_num)
// tick event may not be scheduled if this gets called from inside
// an instruction's execution, e.g. "quiesce"
if (tickEvent.scheduled())
- tickEvent.deschedule();
+ deschedule(tickEvent);
notIdleFraction--;
_status = Idle;
@@ -318,7 +314,7 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, false);
// Now do the access.
if (fault == NoFault) {
@@ -355,6 +351,9 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
if (secondAddr <= addr)
{
data = gtoh(data);
+ if (traceData) {
+ traceData->setData(data);
+ }
return fault;
}
@@ -371,61 +370,6 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
}
}
-Fault
-AtomicSimpleCPU::translateDataReadAddr(Addr vaddr, Addr & paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated read request and packet objects
- Request *req = &data_read_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + dataSize - 1, blockSize);
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
-
- //If there's a fault, return it
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- //If we don't need to access a second cache line, stop now.
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
template
@@ -508,7 +452,7 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
req->setVirt(0, addr, dataSize, flags, thread->readPC());
// translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
+ Fault fault = thread->dtb->translateAtomic(req, tc, true);
// Now do the access.
if (fault == NoFault) {
@@ -568,6 +512,9 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
// If the write needs to have a fault on the access, consider
// calling changeStatus() and changing it to "bad addr write"
// or something.
+ if (traceData) {
+ traceData->setData(gtoh(data));
+ }
return fault;
}
@@ -584,64 +531,6 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
}
}
-Fault
-AtomicSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- // use the CPU's statically allocated write request and packet objects
- Request *req = &data_write_req;
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- //The block size of our peer.
- int blockSize = dcachePort.peerBlockSize();
-
- //The address of the second part of this access if it needs to be split
- //across a cache line boundary.
- Addr secondAddr = roundDown(vaddr + size - 1, blockSize);
-
- //The size of the data we're trying to read.
- int dataSize = size;
-
- bool firstTimeThrough = true;
-
- if(secondAddr > vaddr)
- dataSize = secondAddr - vaddr;
-
- dcache_latency = 0;
-
- while(1) {
- req->setVirt(0, vaddr, dataSize, flags, thread->readPC());
-
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- //If there's a fault or we don't need to access a second cache line,
- //stop now.
- if (fault != NoFault)
- return fault;
-
- if (firstTimeThrough) {
- paddr = req->getPaddr();
- firstTimeThrough = false;
- }
-
- if (secondAddr <= vaddr)
- return fault;
-
- /*
- * Set up for accessing the second cache line.
- */
-
- //Adjust the size to get the remaining bytes.
- dataSize = vaddr + size - secondAddr;
- //And access the right address.
- vaddr = secondAddr;
- }
-}
-
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -705,7 +594,7 @@ AtomicSimpleCPU::tick()
{
DPRINTF(SimpleCPU, "Tick\n");
- Tick latency = ticks(1); // instruction takes one cycle by default
+ Tick latency = 0;
for (int i = 0; i < width; ++i) {
numCycles++;
@@ -715,31 +604,43 @@ AtomicSimpleCPU::tick()
checkPcEventQueue();
- Fault fault = setupFetchRequest(&ifetch_req);
+ Fault fault = NoFault;
+
+ bool fromRom = isRomMicroPC(thread->readMicroPC());
+ if (!fromRom && !curMacroStaticInst) {
+ setupFetchRequest(&ifetch_req);
+ fault = thread->itb->translateAtomic(&ifetch_req, tc);
+ }
if (fault == NoFault) {
Tick icache_latency = 0;
bool icache_access = false;
dcache_access = false; // assume no dcache access
- //Fetch more instruction memory if necessary
- //if(predecoder.needMoreBytes())
- //{
- icache_access = true;
- Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
- Packet::Broadcast);
- ifetch_pkt.dataStatic(&inst);
-
- if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
- icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
- else
- icache_latency = icachePort.sendAtomic(&ifetch_pkt);
+ if (!fromRom && !curMacroStaticInst) {
+ // This is commented out because the predecoder would act like
+ // a tiny cache otherwise. It wouldn't be flushed when needed
+ // like the I cache. It should be flushed, and when that works
+ // this code should be uncommented.
+ //Fetch more instruction memory if necessary
+ //if(predecoder.needMoreBytes())
+ //{
+ icache_access = true;
+ Packet ifetch_pkt = Packet(&ifetch_req, MemCmd::ReadReq,
+ Packet::Broadcast);
+ ifetch_pkt.dataStatic(&inst);
+
+ if (hasPhysMemPort && ifetch_pkt.getAddr() == physMemAddr)
+ icache_latency = physmemPort.sendAtomic(&ifetch_pkt);
+ else
+ icache_latency = icachePort.sendAtomic(&ifetch_pkt);
- assert(!ifetch_pkt.isError());
+ assert(!ifetch_pkt.isError());
- // ifetch_req is initialized to read the instruction directly
- // into the CPU object's inst field.
- //}
+ // ifetch_req is initialized to read the instruction directly
+ // into the CPU object's inst field.
+ //}
+ }
preExecute();
@@ -763,16 +664,21 @@ AtomicSimpleCPU::tick()
curStaticInst->isFirstMicroop()))
instCnt++;
- if (simulate_stalls) {
- Tick icache_stall =
- icache_access ? icache_latency - ticks(1) : 0;
- Tick dcache_stall =
- dcache_access ? dcache_latency - ticks(1) : 0;
- Tick stall_cycles = (icache_stall + dcache_stall) / ticks(1);
- if (ticks(stall_cycles) < (icache_stall + dcache_stall))
- latency += ticks(stall_cycles+1);
- else
- latency += ticks(stall_cycles);
+ Tick stall_ticks = 0;
+ if (simulate_inst_stalls && icache_access)
+ stall_ticks += icache_latency;
+
+ if (simulate_data_stalls && dcache_access)
+ stall_ticks += dcache_latency;
+
+ if (stall_ticks) {
+ Tick stall_cycles = stall_ticks / ticks(1);
+ Tick aligned_stall_ticks = ticks(stall_cycles);
+
+ if (aligned_stall_ticks < stall_ticks)
+ aligned_stall_ticks += 1;
+
+ latency += aligned_stall_ticks;
}
}
@@ -780,8 +686,12 @@ AtomicSimpleCPU::tick()
advancePC(fault);
}
+ // instruction takes at least one cycle
+ if (latency < ticks(1))
+ latency = ticks(1);
+
if (_status != Idle)
- tickEvent.schedule(curTick + latency);
+ schedule(tickEvent, curTick + latency);
}
@@ -799,38 +709,10 @@ AtomicSimpleCPU::printAddr(Addr a)
AtomicSimpleCPU *
AtomicSimpleCPUParams::create()
{
- AtomicSimpleCPU::Params *params = new AtomicSimpleCPU::Params();
- params->name = name;
- 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->progress_interval = progress_interval;
- params->deferRegistration = defer_registration;
- params->phase = phase;
- params->clock = clock;
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
- params->width = width;
- params->simulate_stalls = simulate_stalls;
- params->system = system;
- params->cpu_id = cpu_id;
- params->tracer = tracer;
-
- params->itb = itb;
- params->dtb = dtb;
-#if FULL_SYSTEM
- params->profile = profile;
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
+ numThreads = 1;
+#if !FULL_SYSTEM
if (workload.size() != 1)
panic("only one workload allowed");
- params->process = workload[0];
#endif
-
- AtomicSimpleCPU *cpu = new AtomicSimpleCPU(params);
- return cpu;
+ return new AtomicSimpleCPU(this);
}
diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh
index 19bc0e13b..190097637 100644
--- a/src/cpu/simple/atomic.hh
+++ b/src/cpu/simple/atomic.hh
@@ -32,34 +32,17 @@
#define __CPU_SIMPLE_ATOMIC_HH__
#include "cpu/simple/base.hh"
+#include "params/AtomicSimpleCPU.hh"
class AtomicSimpleCPU : public BaseSimpleCPU
{
public:
- struct Params : public BaseSimpleCPU::Params {
- int width;
- bool simulate_stalls;
- };
-
- AtomicSimpleCPU(Params *params);
+ AtomicSimpleCPU(AtomicSimpleCPUParams *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
@@ -74,7 +57,8 @@ class AtomicSimpleCPU : public BaseSimpleCPU
TickEvent tickEvent;
const int width;
- const bool simulate_stalls;
+ const bool simulate_data_stalls;
+ const bool simulate_inst_stalls;
// main simulation loop (one cycle)
void tick();
@@ -152,11 +136,6 @@ class AtomicSimpleCPU : public BaseSimpleCPU
template <class T>
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
/**
* Print state of address in memory system via PrintReq (for
* debugging).
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 4a91a9e12..348d2392f 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -31,6 +31,7 @@
#include "arch/utility.hh"
#include "arch/faults.hh"
#include "base/cprintf.hh"
+#include "base/cp_annotate.hh"
#include "base/inifile.hh"
#include "base/loader/symtab.hh"
#include "base/misc.hh"
@@ -65,16 +66,18 @@
#include "mem/mem_object.hh"
#endif // FULL_SYSTEM
+#include "params/BaseSimpleCPU.hh"
+
using namespace std;
using namespace TheISA;
-BaseSimpleCPU::BaseSimpleCPU(Params *p)
+BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
: BaseCPU(p), traceData(NULL), thread(NULL), predecoder(NULL)
{
#if FULL_SYSTEM
thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
#else
- thread = new SimpleThread(this, /* thread_num */ 0, p->process,
+ thread = new SimpleThread(this, /* thread_num */ 0, p->workload[0],
p->itb, p->dtb, /* asid */ 0);
#endif // !FULL_SYSTEM
@@ -174,12 +177,13 @@ void
BaseSimpleCPU::resetStats()
{
// startNumInst = numInst;
- // notIdleFraction = (_status != Idle);
+ notIdleFraction = (_status != Idle);
}
void
BaseSimpleCPU::serialize(ostream &os)
{
+ SERIALIZE_ENUM(_status);
BaseCPU::serialize(os);
// SERIALIZE_SCALAR(inst);
nameOut(os, csprintf("%s.xc.0", name()));
@@ -189,6 +193,7 @@ BaseSimpleCPU::serialize(ostream &os)
void
BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
+ UNSERIALIZE_ENUM(_status);
BaseCPU::unserialize(cp, section);
// UNSERIALIZE_SCALAR(inst);
thread->unserialize(cp, csprintf("%s.xc.0", section));
@@ -299,14 +304,13 @@ BaseSimpleCPU::dbg_vtophys(Addr addr)
#if FULL_SYSTEM
void
-BaseSimpleCPU::post_interrupt(int int_num, int index)
+BaseSimpleCPU::wakeup()
{
- BaseCPU::post_interrupt(int_num, index);
+ if (thread->status() != ThreadContext::Suspended)
+ return;
- if (thread->status() == ThreadContext::Suspended) {
- DPRINTF(Quiesce,"Suspended Processor awoke\n");
- thread->activate();
- }
+ DPRINTF(Quiesce,"Suspended Processor awoke\n");
+ thread->activate();
}
#endif // FULL_SYSTEM
@@ -314,11 +318,12 @@ void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
- if (check_interrupts(tc)) {
- Fault interrupt = interrupts.getInterrupt(tc);
+ if (checkInterrupts(tc)) {
+ Fault interrupt = interrupts->getInterrupt(tc);
if (interrupt != NoFault) {
- interrupts.updateIntrInfo(tc);
+ predecoder.reset();
+ interrupts->updateIntrInfo(tc);
interrupt->invoke(tc);
}
}
@@ -326,7 +331,7 @@ BaseSimpleCPU::checkForInterrupts()
}
-Fault
+void
BaseSimpleCPU::setupFetchRequest(Request *req)
{
Addr threadPC = thread->readPC();
@@ -342,10 +347,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req)
Addr fetchPC = (threadPC & PCMask) + fetchOffset;
req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC);
-
- Fault fault = thread->translateInstReq(req);
-
- return fault;
}
@@ -364,9 +365,13 @@ BaseSimpleCPU::preExecute()
// decode the instruction
inst = gtoh(inst);
- //If we're not in the middle of a macro instruction
- if (!curMacroStaticInst) {
+ MicroPC upc = thread->readMicroPC();
+ if (isRomMicroPC(upc)) {
+ stayAtPC = false;
+ curStaticInst = microcodeRom.fetchMicroop(upc, curMacroStaticInst);
+ } else if (!curMacroStaticInst) {
+ //We're not in the middle of a macro instruction
StaticInstPtr instPtr = NULL;
//Predecode, ie bundle up an ExtMachInst
@@ -397,23 +402,22 @@ BaseSimpleCPU::preExecute()
//out micro ops
if (instPtr && instPtr->isMacroop()) {
curMacroStaticInst = instPtr;
- curStaticInst = curMacroStaticInst->
- fetchMicroop(thread->readMicroPC());
+ curStaticInst = curMacroStaticInst->fetchMicroop(upc);
} else {
curStaticInst = instPtr;
}
} else {
//Read the next micro op from the macro op
- curStaticInst = curMacroStaticInst->
- fetchMicroop(thread->readMicroPC());
+ curStaticInst = curMacroStaticInst->fetchMicroop(upc);
}
//If we decoded an instruction this "tick", record information about it.
if(curStaticInst)
{
#if TRACING_ON
- traceData = tracer->getInstRecord(curTick, tc, curStaticInst,
- thread->readPC());
+ traceData = tracer->getInstRecord(curTick, tc,
+ curStaticInst, thread->readPC(),
+ curMacroStaticInst, thread->readMicroPC());
DPRINTF(Decode,"Decode: Decoded %s instruction: 0x%x\n",
curStaticInst->getName(), curStaticInst->machInst);
@@ -447,6 +451,10 @@ BaseSimpleCPU::postExecute()
comLoadEventQueue[0]->serviceEvents(numLoad);
}
+ if (CPA::available()) {
+ CPA::cpa()->swAutoBegin(tc, thread->readNextPC());
+ }
+
traceFunctions(thread->readPC());
if (traceData) {
@@ -465,22 +473,21 @@ BaseSimpleCPU::advancePC(Fault fault)
if (fault != NoFault) {
curMacroStaticInst = StaticInst::nullStaticInstPtr;
predecoder.reset();
- thread->setMicroPC(0);
- thread->setNextMicroPC(1);
fault->invoke(tc);
} else {
//If we're at the last micro op for this instruction
if (curStaticInst && curStaticInst->isLastMicroop()) {
- //We should be working with a macro op
- assert(curMacroStaticInst);
+ //We should be working with a macro op or be in the ROM
+ assert(curMacroStaticInst ||
+ isRomMicroPC(thread->readMicroPC()));
//Close out this macro op, and clean up the
//microcode state
curMacroStaticInst = StaticInst::nullStaticInstPtr;
- thread->setMicroPC(0);
- thread->setNextMicroPC(1);
+ thread->setMicroPC(normalMicroPC(0));
+ thread->setNextMicroPC(normalMicroPC(1));
}
//If we're still in a macro op
- if (curMacroStaticInst) {
+ if (curMacroStaticInst || isRomMicroPC(thread->readMicroPC())) {
//Advance the micro pc
thread->setMicroPC(thread->readNextMicroPC());
//Advance the "next" micro pc. Note that there are no delay
diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh
index 918965fdb..e80606388 100644
--- a/src/cpu/simple/base.hh
+++ b/src/cpu/simple/base.hh
@@ -76,6 +76,8 @@ namespace Trace {
class InstRecord;
}
+class BaseSimpleCPUParams;
+
class BaseSimpleCPU : public BaseCPU
{
@@ -96,7 +98,7 @@ class BaseSimpleCPU : public BaseCPU
}
public:
- void post_interrupt(int int_num, int index);
+ void wakeup();
void zero_fill_64(Addr addr) {
static int warned = 0;
@@ -107,15 +109,7 @@ class BaseSimpleCPU : public BaseCPU
};
public:
- struct Params : public BaseCPU::Params
- {
- TheISA::ITB *itb;
- TheISA::DTB *dtb;
-#if !FULL_SYSTEM
- Process *process;
-#endif
- };
- BaseSimpleCPU(Params *params);
+ BaseSimpleCPU(BaseSimpleCPUParams *params);
virtual ~BaseSimpleCPU();
public:
@@ -127,7 +121,22 @@ class BaseSimpleCPU : public BaseCPU
*/
ThreadContext *tc;
protected:
- int cpuId;
+
+ enum Status {
+ Idle,
+ Running,
+ ITBWaitResponse,
+ IcacheRetry,
+ IcacheWaitResponse,
+ IcacheWaitSwitch,
+ DTBWaitResponse,
+ DcacheRetry,
+ DcacheWaitResponse,
+ DcacheWaitSwitch,
+ SwitchedOut
+ };
+
+ Status _status;
public:
@@ -153,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU
bool stayAtPC;
void checkForInterrupts();
- Fault setupFetchRequest(Request *req);
+ void setupFetchRequest(Request *req);
void preExecute();
void postExecute();
void advancePC(Fault fault);
@@ -168,7 +177,7 @@ class BaseSimpleCPU : public BaseCPU
// number of simulated instructions
Counter numInst;
Counter startNumInst;
- Stats::Scalar<> numInsts;
+ Stats::Scalar numInsts;
void countInst()
{
@@ -187,30 +196,30 @@ class BaseSimpleCPU : public BaseCPU
static const Addr PCMask = ~((Addr)sizeof(TheISA::MachInst) - 1);
// number of simulated memory references
- Stats::Scalar<> numMemRefs;
+ Stats::Scalar numMemRefs;
// number of simulated loads
Counter numLoad;
Counter startNumLoad;
// number of idle cycles
- Stats::Average<> notIdleFraction;
+ Stats::Average notIdleFraction;
Stats::Formula idleFraction;
// number of cycles stalled for I-cache responses
- Stats::Scalar<> icacheStallCycles;
+ Stats::Scalar icacheStallCycles;
Counter lastIcacheStall;
// number of cycles stalled for I-cache retries
- Stats::Scalar<> icacheRetryCycles;
+ Stats::Scalar icacheRetryCycles;
Counter lastIcacheRetry;
// number of cycles stalled for D-cache responses
- Stats::Scalar<> dcacheStallCycles;
+ Stats::Scalar dcacheStallCycles;
Counter lastDcacheStall;
// number of cycles stalled for D-cache retries
- Stats::Scalar<> dcacheRetryCycles;
+ Stats::Scalar dcacheRetryCycles;
Counter lastDcacheRetry;
virtual void serialize(std::ostream &os);
@@ -219,7 +228,7 @@ class BaseSimpleCPU : public BaseCPU
// 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");
+ Addr getEA() { panic("BaseSimpleCPU::getEA() not implemented\n");
M5_DUMMY_RETURN}
void prefetch(Addr addr, unsigned flags)
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index a76824ff3..a8f86f8d2 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -57,13 +57,12 @@ void
TimingSimpleCPU::init()
{
BaseCPU::init();
- cpuId = tc->readCpuId();
#if FULL_SYSTEM
for (int i = 0; i < threadContexts.size(); ++i) {
ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(tc, cpuId);
+ TheISA::initCPU(tc, _cpuId);
}
#endif
}
@@ -101,11 +100,12 @@ void
TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
{
pkt = _pkt;
- Event::schedule(t);
+ cpu->schedule(this, t);
}
-TimingSimpleCPU::TimingSimpleCPU(Params *p)
- : BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock)
+TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
+ : BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
+ dcachePort(this, p->clock), fetchEvent(this)
{
_status = Idle;
@@ -114,7 +114,6 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
ifetch_pkt = dcache_pkt = NULL;
drainEvent = NULL;
- fetchEvent = NULL;
previousTick = 0;
changeState(SimObject::Running);
}
@@ -145,7 +144,7 @@ TimingSimpleCPU::drain(Event *drain_event)
{
// TimingSimpleCPU is ready to drain if it's not waiting for
// an access to complete.
- if (status() == Idle || status() == Running || status() == SwitchedOut) {
+ if (_status == Idle || _status == Running || _status == SwitchedOut) {
changeState(SimObject::Drained);
return 0;
} else {
@@ -162,15 +161,10 @@ TimingSimpleCPU::resume()
if (_status != SwitchedOut && _status != Idle) {
assert(system->getMemoryMode() == Enums::timing);
- // Delete the old event if it existed.
- if (fetchEvent) {
- if (fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
- delete fetchEvent;
- }
-
- fetchEvent = new FetchEvent(this, nextCycle());
+ schedule(fetchEvent, nextCycle());
}
changeState(SimObject::Running);
@@ -179,14 +173,14 @@ TimingSimpleCPU::resume()
void
TimingSimpleCPU::switchOut()
{
- assert(status() == Running || status() == Idle);
+ assert(_status == Running || _status == Idle);
_status = SwitchedOut;
numCycles += tickToCycles(curTick - previousTick);
// If we've been scheduled to resume but are then told to switch out,
// we'll need to cancel it.
- if (fetchEvent && fetchEvent->scheduled())
- fetchEvent->deschedule();
+ if (fetchEvent.scheduled())
+ deschedule(fetchEvent);
}
@@ -209,7 +203,6 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
_status = Idle;
}
assert(threadContexts.size() == 1);
- cpuId = tc->readCpuId();
previousTick = curTick;
}
@@ -228,7 +221,7 @@ TimingSimpleCPU::activateContext(int thread_num, int delay)
_status = Running;
// kick things off by initiating the fetch of the next instruction
- fetchEvent = new FetchEvent(this, nextCycle(curTick + ticks(delay)));
+ schedule(fetchEvent, nextCycle(curTick + ticks(delay)));
}
@@ -249,74 +242,239 @@ TimingSimpleCPU::suspendContext(int thread_num)
_status = Idle;
}
+bool
+TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
+{
+ RequestPtr req = pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprRead(thread->getTC(), pkt);
+ new IprEvent(pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(pkt)) {
+ _status = DcacheRetry;
+ dcache_pkt = pkt;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
-template <class T>
-Fault
-TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
+void
+TimingSimpleCPU::sendData(Fault fault, RequestPtr req,
+ uint8_t *data, uint64_t *res, bool read)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ _status = Running;
+ if (fault != NoFault) {
+ delete data;
+ delete req;
- if (traceData) {
- traceData->setAddr(req->getVaddr());
+ translationFault(fault);
+ return;
}
+ PacketPtr pkt;
+ buildPacket(pkt, req, read);
+ pkt->dataDynamic<uint8_t>(data);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt->makeResponse();
+ completeDataAccess(pkt);
+ } else if (read) {
+ handleReadPacket(pkt);
+ } else {
+ bool do_access = true; // flag to suppress cache access
- // translate to physical address
- Fault fault = thread->translateDataReadReq(req);
+ if (req->isLocked()) {
+ do_access = TheISA::handleLockedWrite(thread, req);
+ } else if (req->isCondSwap()) {
+ assert(res);
+ req->setExtraData(*res);
+ }
- // Now do the access.
- if (fault == NoFault) {
- PacketPtr pkt =
- new Packet(req,
- (req->isLocked() ?
- MemCmd::LoadLockedReq : MemCmd::ReadReq),
- Packet::Broadcast);
- pkt->dataDynamic<T>(new T);
-
- if (req->isMmapedIpr()) {
- Tick delay;
- delay = TheISA::handleIprRead(thread->getTC(), pkt);
- new IprEvent(pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(pkt)) {
- _status = DcacheRetry;
+ if (do_access) {
dcache_pkt = pkt;
+ handleWritePacket();
} else {
_status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
+ completeDataAccess(pkt);
}
+ }
+}
- // This will need a new way to tell if it has a dcache attached.
- if (req->isUncacheable())
- recordEvent("Uncached Read");
+void
+TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ _status = Running;
+ if (fault1 != NoFault || fault2 != NoFault) {
+ delete data;
+ delete req1;
+ delete req2;
+ if (fault1 != NoFault)
+ translationFault(fault1);
+ else if (fault2 != NoFault)
+ translationFault(fault2);
+ return;
+ }
+ PacketPtr pkt1, pkt2;
+ buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ assert(!dcache_pkt);
+ pkt1->makeResponse();
+ completeDataAccess(pkt1);
+ } else if (read) {
+ if (handleReadPacket(pkt1)) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ if (handleReadPacket(pkt2)) {
+ send_state = dynamic_cast<SplitFragmentSenderState *>(
+ pkt1->senderState);
+ send_state->clearFromParent();
+ }
+ }
} else {
- delete req;
+ dcache_pkt = pkt1;
+ if (handleWritePacket()) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
+ send_state->clearFromParent();
+ dcache_pkt = pkt2;
+ if (handleWritePacket()) {
+ send_state = dynamic_cast<SplitFragmentSenderState *>(
+ pkt1->senderState);
+ send_state->clearFromParent();
+ }
+ }
+ }
+}
+
+void
+TimingSimpleCPU::translationFault(Fault fault)
+{
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+
+ if (traceData) {
+ // Since there was a fault, we shouldn't trace this instruction.
+ delete traceData;
+ traceData = NULL;
}
- return fault;
+ postExecute();
+
+ if (getState() == SimObject::Draining) {
+ advancePC(fault);
+ completeDrain();
+ } else {
+ advanceInst(fault);
+ }
}
+void
+TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
+{
+ MemCmd cmd;
+ if (read) {
+ cmd = MemCmd::ReadReq;
+ if (req->isLocked())
+ cmd = MemCmd::LoadLockedReq;
+ } else {
+ cmd = MemCmd::WriteReq;
+ if (req->isLocked()) {
+ cmd = MemCmd::StoreCondReq;
+ } else if (req->isSwap()) {
+ cmd = MemCmd::SwapReq;
+ }
+ }
+ pkt = new Packet(req, cmd, Packet::Broadcast);
+}
+
+void
+TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read)
+{
+ pkt1 = pkt2 = NULL;
+
+ assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
+
+ if (req->getFlags().isSet(Request::NO_ACCESS)) {
+ buildPacket(pkt1, req, read);
+ return;
+ }
+
+ buildPacket(pkt1, req1, read);
+ buildPacket(pkt2, req2, read);
+
+ req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
+ PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
+ Packet::Broadcast);
+
+ pkt->dataDynamic<uint8_t>(data);
+ pkt1->dataStatic<uint8_t>(data);
+ pkt2->dataStatic<uint8_t>(data + req1->getSize());
+
+ SplitMainSenderState * main_send_state = new SplitMainSenderState;
+ pkt->senderState = main_send_state;
+ main_send_state->fragments[0] = pkt1;
+ main_send_state->fragments[1] = pkt2;
+ main_send_state->outstanding = 2;
+ pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
+ pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
+}
+
+template <class T>
Fault
-TimingSimpleCPU::translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
+TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
+ Fault fault;
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ RequestPtr req = new Request(asid, addr, data_size,
+ flags, pc, _cpuId, thread_id);
+
+ Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ assert(split_addr <= addr || split_addr - addr < block_size);
+
+
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)(new T), true);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), false);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), false);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)(new T), NULL, true),
+ false);
+ }
if (traceData) {
- traceData->setAddr(vaddr);
+ traceData->setData(data);
+ traceData->setAddr(addr);
}
- Fault fault = thread->translateDataWriteReq(req);
+ // This will need a new way to tell if it has a dcache attached.
+ if (req->isUncacheable())
+ recordEvent("Uncached Read");
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
@@ -369,92 +527,75 @@ TimingSimpleCPU::read(Addr addr, int32_t &data, unsigned flags)
return read(addr, (uint32_t&)data, flags);
}
+bool
+TimingSimpleCPU::handleWritePacket()
+{
+ RequestPtr req = dcache_pkt->req;
+ if (req->isMmapedIpr()) {
+ Tick delay;
+ delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
+ new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
+ _status = DcacheWaitResponse;
+ dcache_pkt = NULL;
+ } else if (!dcachePort.sendTiming(dcache_pkt)) {
+ _status = DcacheRetry;
+ } else {
+ _status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ dcache_pkt = NULL;
+ }
+ return dcache_pkt == NULL;
+}
template <class T>
Fault
TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- Request *req =
- new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
- cpuId, /* thread ID */ 0);
+ const int asid = 0;
+ const int thread_id = 0;
+ const Addr pc = thread->readPC();
+ int block_size = dcachePort.peerBlockSize();
+ int data_size = sizeof(T);
+
+ RequestPtr req = new Request(asid, addr, data_size,
+ flags, pc, _cpuId, thread_id);
+
+ Addr split_addr = roundDown(addr + data_size - 1, block_size);
+ assert(split_addr <= addr || split_addr - addr < block_size);
+
+ T *dataP = new T;
+ *dataP = TheISA::htog(data);
+ _status = DTBWaitResponse;
+ if (split_addr > addr) {
+ RequestPtr req1, req2;
+ assert(!req->isLocked() && !req->isSwap());
+ req->splitOnVaddr(split_addr, req1, req2);
+
+ typedef SplitDataTranslation::WholeTranslationState WholeState;
+ WholeState *state = new WholeState(req1, req2, req,
+ (uint8_t *)dataP, false);
+ thread->dtb->translateTiming(req1, tc,
+ new SplitDataTranslation(this, 0, state), true);
+ thread->dtb->translateTiming(req2, tc,
+ new SplitDataTranslation(this, 1, state), true);
+ } else {
+ thread->dtb->translateTiming(req, tc,
+ new DataTranslation(this, (uint8_t *)dataP, res, false),
+ true);
+ }
if (traceData) {
traceData->setAddr(req->getVaddr());
+ traceData->setData(data);
}
- // translate to physical address
- Fault fault = thread->translateDataWriteReq(req);
-
- // Now do the access.
- if (fault == NoFault) {
- MemCmd cmd = MemCmd::WriteReq; // default
- bool do_access = true; // flag to suppress cache access
-
- if (req->isLocked()) {
- cmd = MemCmd::StoreCondReq;
- do_access = TheISA::handleLockedWrite(thread, req);
- } else if (req->isSwap()) {
- cmd = MemCmd::SwapReq;
- if (req->isCondSwap()) {
- assert(res);
- req->setExtraData(*res);
- }
- }
-
- // Note: need to allocate dcache_pkt even if do_access is
- // false, as it's used unconditionally to call completeAcc().
- assert(dcache_pkt == NULL);
- dcache_pkt = new Packet(req, cmd, Packet::Broadcast);
- dcache_pkt->allocate();
- dcache_pkt->set(data);
-
- if (do_access) {
- if (req->isMmapedIpr()) {
- Tick delay;
- dcache_pkt->set(htog(data));
- delay = TheISA::handleIprWrite(thread->getTC(), dcache_pkt);
- new IprEvent(dcache_pkt, this, nextCycle(curTick + delay));
- _status = DcacheWaitResponse;
- dcache_pkt = NULL;
- } else if (!dcachePort.sendTiming(dcache_pkt)) {
- _status = DcacheRetry;
- } else {
- _status = DcacheWaitResponse;
- // memory system takes ownership of packet
- dcache_pkt = NULL;
- }
- }
- // This will need a new way to tell if it's hooked up to a cache or not.
- if (req->isUncacheable())
- recordEvent("Uncached Write");
- } else {
- delete req;
- }
-
+ // This will need a new way to tell if it's hooked up to a cache or not.
+ if (req->isUncacheable())
+ 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;
-}
-
-Fault
-TimingSimpleCPU::translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags)
-{
- Request *req =
- new Request(0, vaddr, size, flags, thread->readPC(), cpuId, 0);
-
- if (traceData) {
- traceData->setAddr(vaddr);
- }
-
- Fault fault = thread->translateDataWriteReq(req);
-
- if (fault == NoFault)
- paddr = req->getPaddr();
-
- delete req;
- return fault;
+ return NoFault;
}
@@ -524,14 +665,31 @@ TimingSimpleCPU::fetch()
checkPcEventQueue();
- Request *ifetch_req = new Request();
- ifetch_req->setThreadContext(cpuId, /* thread ID */ 0);
- Fault fault = setupFetchRequest(ifetch_req);
+ bool fromRom = isRomMicroPC(thread->readMicroPC());
- ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
- ifetch_pkt->dataStatic(&inst);
+ if (!fromRom && !curMacroStaticInst) {
+ Request *ifetch_req = new Request();
+ ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
+ setupFetchRequest(ifetch_req);
+ thread->itb->translateTiming(ifetch_req, tc,
+ &fetchTranslation);
+ } else {
+ _status = IcacheWaitResponse;
+ completeIfetch(NULL);
+ numCycles += tickToCycles(curTick - previousTick);
+ previousTick = curTick;
+ }
+}
+
+
+void
+TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
+{
if (fault == NoFault) {
+ ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
+ ifetch_pkt->dataStatic(&inst);
+
if (!icachePort.sendTiming(ifetch_pkt)) {
// Need to wait for retry
_status = IcacheRetry;
@@ -542,8 +700,7 @@ TimingSimpleCPU::fetch()
ifetch_pkt = NULL;
}
} else {
- delete ifetch_req;
- delete ifetch_pkt;
+ delete req;
// fetch fault: advance directly to next instruction (fault handler)
advanceInst(fault);
}
@@ -556,7 +713,8 @@ TimingSimpleCPU::fetch()
void
TimingSimpleCPU::advanceInst(Fault fault)
{
- advancePC(fault);
+ if (fault != NoFault || !stayAtPC)
+ advancePC(fault);
if (_status == Running) {
// kick off fetch of next instruction... callback from icache
@@ -574,7 +732,8 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
// received a response from the icache: execute the received
// instruction
- assert(!pkt->isError());
+
+ assert(!pkt || !pkt->isError());
assert(_status == IcacheWaitResponse);
_status = Running;
@@ -583,41 +742,27 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
previousTick = curTick;
if (getState() == SimObject::Draining) {
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
completeDrain();
return;
}
preExecute();
- if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
+ if (curStaticInst &&
+ curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
// load or store: just send to dcache
Fault fault = curStaticInst->initiateAcc(this, traceData);
if (_status != Running) {
// instruction will complete in dcache response callback
- assert(_status == DcacheWaitResponse || _status == DcacheRetry);
+ assert(_status == DcacheWaitResponse ||
+ _status == DcacheRetry || DTBWaitResponse);
assert(fault == NoFault);
} else {
- if (fault == NoFault) {
- // Note that ARM can have NULL packets if the instruction gets
- // squashed due to predication
- // early fail on store conditional: complete now
- assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
-
- fault = curStaticInst->completeAcc(dcache_pkt, this,
- traceData);
- if (dcache_pkt != NULL)
- {
- delete dcache_pkt->req;
- delete dcache_pkt;
- dcache_pkt = NULL;
- }
-
- // keep an instruction count
- if (fault == NoFault)
- countInst();
- } else if (traceData) {
+ if (fault != NoFault && traceData) {
// If there was a fault, we shouldn't trace this instruction.
delete traceData;
traceData = NULL;
@@ -630,7 +775,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
instCnt++;
advanceInst(fault);
}
- } else {
+ } else if (curStaticInst) {
// non-memory instruction: execute completely now
Fault fault = curStaticInst->execute(this, traceData);
@@ -649,10 +794,14 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
curStaticInst->isFirstMicroop()))
instCnt++;
advanceInst(fault);
+ } else {
+ advanceInst(NoFault);
}
- delete pkt->req;
- delete pkt;
+ if (pkt) {
+ delete pkt->req;
+ delete pkt;
+ }
}
void
@@ -707,12 +856,38 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
// received a response from the dcache: complete the load or store
// instruction
assert(!pkt->isError());
- assert(_status == DcacheWaitResponse);
- _status = Running;
numCycles += tickToCycles(curTick - previousTick);
previousTick = curTick;
+ if (pkt->senderState) {
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(pkt->senderState);
+ assert(send_state);
+ delete pkt->req;
+ delete pkt;
+ PacketPtr big_pkt = send_state->bigPkt;
+ delete send_state;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+ // Record the fact that this packet is no longer outstanding.
+ assert(main_send_state->outstanding != 0);
+ main_send_state->outstanding--;
+
+ if (main_send_state->outstanding) {
+ return;
+ } else {
+ delete main_send_state;
+ big_pkt->senderState = NULL;
+ pkt = big_pkt;
+ }
+ }
+
+ assert(_status == DcacheWaitResponse || _status == DTBWaitResponse);
+ _status = Running;
+
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
// keep an instruction count
@@ -724,7 +899,9 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
traceData = NULL;
}
- if (pkt->isRead() && pkt->isLocked()) {
+ // the locked flag may be cleared on the response packet, so check
+ // pkt->req and not pkt to see if it was a load-locked
+ if (pkt->isRead() && pkt->req->isLocked()) {
TheISA::handleLockedRead(thread, pkt->req);
}
@@ -760,7 +937,7 @@ TimingSimpleCPU::DcachePort::setPeer(Port *port)
#if FULL_SYSTEM
// Update the ThreadContext's memory ports (Functional/Virtual
// Ports)
- cpu->tcBase()->connectMemPorts();
+ cpu->tcBase()->connectMemPorts(cpu->tcBase());
#endif
}
@@ -771,10 +948,11 @@ TimingSimpleCPU::DcachePort::recvTiming(PacketPtr pkt)
// delay processing of returned data until next CPU clock edge
Tick next_tick = cpu->nextCycle(curTick);
- if (next_tick == curTick)
+ if (next_tick == curTick) {
cpu->completeDataAccess(pkt);
- else
+ } else {
tickEvent.schedule(pkt, next_tick);
+ }
return true;
}
@@ -804,17 +982,47 @@ TimingSimpleCPU::DcachePort::recvRetry()
assert(cpu->dcache_pkt != NULL);
assert(cpu->_status == DcacheRetry);
PacketPtr tmp = cpu->dcache_pkt;
- if (sendTiming(tmp)) {
+ if (tmp->senderState) {
+ // This is a packet from a split access.
+ SplitFragmentSenderState * send_state =
+ dynamic_cast<SplitFragmentSenderState *>(tmp->senderState);
+ assert(send_state);
+ PacketPtr big_pkt = send_state->bigPkt;
+
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(big_pkt->senderState);
+ assert(main_send_state);
+
+ if (sendTiming(tmp)) {
+ // If we were able to send without retrying, record that fact
+ // and try sending the other fragment.
+ send_state->clearFromParent();
+ int other_index = main_send_state->getPendingFragment();
+ if (other_index > 0) {
+ tmp = main_send_state->fragments[other_index];
+ cpu->dcache_pkt = tmp;
+ if ((big_pkt->isRead() && cpu->handleReadPacket(tmp)) ||
+ (big_pkt->isWrite() && cpu->handleWritePacket())) {
+ main_send_state->fragments[other_index] = NULL;
+ }
+ } else {
+ cpu->_status = DcacheWaitResponse;
+ // memory system takes ownership of packet
+ cpu->dcache_pkt = NULL;
+ }
+ }
+ } else if (sendTiming(tmp)) {
cpu->_status = DcacheWaitResponse;
// memory system takes ownership of packet
cpu->dcache_pkt = NULL;
}
}
-TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu, Tick t)
- : Event(&mainEventQueue), pkt(_pkt), cpu(_cpu)
+TimingSimpleCPU::IprEvent::IprEvent(Packet *_pkt, TimingSimpleCPU *_cpu,
+ Tick t)
+ : pkt(_pkt), cpu(_cpu)
{
- schedule(t);
+ cpu->schedule(this, t);
}
void
@@ -844,36 +1052,10 @@ TimingSimpleCPU::printAddr(Addr a)
TimingSimpleCPU *
TimingSimpleCPUParams::create()
{
- TimingSimpleCPU::Params *params = new TimingSimpleCPU::Params();
- params->name = name;
- 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->progress_interval = progress_interval;
- params->deferRegistration = defer_registration;
- params->clock = clock;
- params->phase = phase;
- params->functionTrace = function_trace;
- params->functionTraceStart = function_trace_start;
- params->system = system;
- params->cpu_id = cpu_id;
- params->tracer = tracer;
-
- params->itb = itb;
- params->dtb = dtb;
-#if FULL_SYSTEM
- params->profile = profile;
- params->do_quiesce = do_quiesce;
- params->do_checkpoint_insts = do_checkpoint_insts;
- params->do_statistics_insts = do_statistics_insts;
-#else
+ numThreads = 1;
+#if !FULL_SYSTEM
if (workload.size() != 1)
panic("only one workload allowed");
- params->process = workload[0];
#endif
-
- TimingSimpleCPU *cpu = new TimingSimpleCPU(params);
- return cpu;
+ return new TimingSimpleCPU(this);
}
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
index f8b77604a..a02ec48c9 100644
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -33,40 +33,181 @@
#include "cpu/simple/base.hh"
+#include "params/TimingSimpleCPU.hh"
+
class TimingSimpleCPU : public BaseSimpleCPU
{
public:
- struct Params : public BaseSimpleCPU::Params {
- };
-
- TimingSimpleCPU(Params *params);
+ TimingSimpleCPU(TimingSimpleCPUParams * params);
virtual ~TimingSimpleCPU();
virtual void init();
public:
- //
- enum Status {
- Idle,
- Running,
- IcacheRetry,
- IcacheWaitResponse,
- IcacheWaitSwitch,
- DcacheRetry,
- DcacheWaitResponse,
- DcacheWaitSwitch,
- SwitchedOut
+ Event *drainEvent;
+
+ private:
+
+ /*
+ * If an access needs to be broken into fragments, currently at most two,
+ * the the following two classes are used as the sender state of the
+ * packets so the CPU can keep track of everything. In the main packet
+ * sender state, there's an array with a spot for each fragment. If a
+ * fragment has already been accepted by the CPU, aka isn't waiting for
+ * a retry, it's pointer is NULL. After each fragment has successfully
+ * been processed, the "outstanding" counter is decremented. Once the
+ * count is zero, the entire larger access is complete.
+ */
+ class SplitMainSenderState : public Packet::SenderState
+ {
+ public:
+ int outstanding;
+ PacketPtr fragments[2];
+
+ int
+ getPendingFragment()
+ {
+ if (fragments[0]) {
+ return 0;
+ } else if (fragments[1]) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
};
- protected:
- Status _status;
+ class SplitFragmentSenderState : public Packet::SenderState
+ {
+ public:
+ SplitFragmentSenderState(PacketPtr _bigPkt, int _index) :
+ bigPkt(_bigPkt), index(_index)
+ {}
+ PacketPtr bigPkt;
+ int index;
+
+ void
+ clearFromParent()
+ {
+ SplitMainSenderState * main_send_state =
+ dynamic_cast<SplitMainSenderState *>(bigPkt->senderState);
+ main_send_state->fragments[index] = NULL;
+ }
+ };
- Status status() const { return _status; }
+ class FetchTranslation : public BaseTLB::Translation
+ {
+ protected:
+ TimingSimpleCPU *cpu;
- Event *drainEvent;
+ public:
+ FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu)
+ {}
- private:
+ void finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ cpu->sendFetch(fault, req, tc);
+ }
+ };
+ FetchTranslation fetchTranslation;
+
+ class DataTranslation : public BaseTLB::Translation
+ {
+ protected:
+ TimingSimpleCPU *cpu;
+ uint8_t *data;
+ uint64_t *res;
+ bool read;
+
+ public:
+ DataTranslation(TimingSimpleCPU *_cpu,
+ uint8_t *_data, uint64_t *_res, bool _read) :
+ cpu(_cpu), data(_data), res(_res), read(_read)
+ {}
+
+ void
+ finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ cpu->sendData(fault, req, data, res, read);
+ delete this;
+ }
+ };
+
+ class SplitDataTranslation : public BaseTLB::Translation
+ {
+ public:
+ struct WholeTranslationState
+ {
+ public:
+ int outstanding;
+ RequestPtr requests[2];
+ RequestPtr mainReq;
+ Fault faults[2];
+ uint8_t *data;
+ bool read;
+
+ WholeTranslationState(RequestPtr req1, RequestPtr req2,
+ RequestPtr main, uint8_t *_data, bool _read)
+ {
+ outstanding = 2;
+ requests[0] = req1;
+ requests[1] = req2;
+ mainReq = main;
+ faults[0] = faults[1] = NoFault;
+ data = _data;
+ read = _read;
+ }
+ };
+
+ TimingSimpleCPU *cpu;
+ int index;
+ WholeTranslationState *state;
+
+ SplitDataTranslation(TimingSimpleCPU *_cpu, int _index,
+ WholeTranslationState *_state) :
+ cpu(_cpu), index(_index), state(_state)
+ {}
+
+ void
+ finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write)
+ {
+ assert(state);
+ assert(state->outstanding);
+ state->faults[index] = fault;
+ if (--state->outstanding == 0) {
+ cpu->sendSplitData(state->faults[0],
+ state->faults[1],
+ state->requests[0],
+ state->requests[1],
+ state->mainReq,
+ state->data,
+ state->read);
+ delete state;
+ }
+ delete this;
+ }
+ };
+
+ void sendData(Fault fault, RequestPtr req,
+ uint8_t *data, uint64_t *res, bool read);
+ void sendSplitData(Fault fault1, Fault fault2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read);
+
+ void translationFault(Fault fault);
+
+ void buildPacket(PacketPtr &pkt, RequestPtr req, bool read);
+ void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
+ RequestPtr req1, RequestPtr req2, RequestPtr req,
+ uint8_t *data, bool read);
+
+ bool handleReadPacket(PacketPtr pkt);
+ // This function always implicitly uses dcache_pkt.
+ bool handleWritePacket();
class CpuPort : public Port
{
@@ -99,8 +240,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
PacketPtr pkt;
TimingSimpleCPU *cpu;
- TickEvent(TimingSimpleCPU *_cpu)
- :Event(&mainEventQueue), cpu(_cpu) {}
+ TickEvent(TimingSimpleCPU *_cpu) : cpu(_cpu) {}
const char *description() const { return "Timing CPU tick"; }
void schedule(PacketPtr _pkt, Tick t);
};
@@ -189,18 +329,13 @@ class TimingSimpleCPU : public BaseSimpleCPU
template <class T>
Fault read(Addr addr, T &data, unsigned flags);
- Fault translateDataReadAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
template <class T>
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
- Fault translateDataWriteAddr(Addr vaddr, Addr &paddr,
- int size, unsigned flags);
-
void fetch();
+ void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc);
void completeIfetch(PacketPtr );
- void completeDataAccess(PacketPtr );
+ void completeDataAccess(PacketPtr pkt);
void advanceInst(Fault fault);
/**
@@ -212,7 +347,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
private:
typedef EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch> FetchEvent;
- FetchEvent *fetchEvent;
+ FetchEvent fetchEvent;
struct IprEvent : Event {
Packet *pkt;
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index 93772fbe1..af0bb4490 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -37,9 +37,11 @@
#include "cpu/base.hh"
#include "cpu/simple_thread.hh"
#include "cpu/thread_context.hh"
+#include "params/BaseCPU.hh"
#if FULL_SYSTEM
#include "arch/kernel_stats.hh"
+#include "arch/stacktrace.hh"
#include "base/callback.hh"
#include "base/cprintf.hh"
#include "base/output.hh"
@@ -48,11 +50,10 @@
#include "cpu/quiesce_event.hh"
#include "sim/serialize.hh"
#include "sim/sim_exit.hh"
-#include "arch/stacktrace.hh"
#else
+#include "mem/translating_port.hh"
#include "sim/process.hh"
#include "sim/system.hh"
-#include "mem/translating_port.hh"
#endif
using namespace std;
@@ -62,7 +63,7 @@ using namespace std;
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
TheISA::ITB *_itb, TheISA::DTB *_dtb,
bool use_kernel_stats)
- : ThreadState(_cpu, -1, _thread_num), cpu(_cpu), system(_sys), itb(_itb),
+ : ThreadState(_cpu, _thread_num), cpu(_cpu), system(_sys), itb(_itb),
dtb(_dtb)
{
@@ -72,7 +73,7 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
regs.clear();
- if (cpu->params->profile) {
+ if (cpu->params()->profile) {
profile = new FunctionProfile(system->kernelSymtab);
Callback *cb =
new MakeCallback<SimpleThread,
@@ -86,16 +87,13 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
profileNode = &dummyNode;
profilePC = 3;
- if (use_kernel_stats) {
+ if (use_kernel_stats)
kernelStats = new TheISA::Kernel::Statistics(system);
- } else {
- kernelStats = NULL;
- }
}
#else
SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
TheISA::ITB *_itb, TheISA::DTB *_dtb, int _asid)
- : ThreadState(_cpu, -1, _thread_num, _process, _asid),
+ : ThreadState(_cpu, _thread_num, _process, _asid),
cpu(_cpu), itb(_itb), dtb(_dtb)
{
regs.clear();
@@ -106,9 +104,9 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process,
SimpleThread::SimpleThread()
#if FULL_SYSTEM
- : ThreadState(NULL, -1, -1)
+ : ThreadState(NULL, -1)
#else
- : ThreadState(NULL, -1, -1, NULL, -1)
+ : ThreadState(NULL, -1, NULL, -1)
#endif
{
tc = new ProxyThreadContext<SimpleThread>(this);
@@ -180,18 +178,20 @@ SimpleThread::copyState(ThreadContext *oldContext)
// copy over functional state
_status = oldContext->status();
copyArchRegs(oldContext);
- cpuId = oldContext->readCpuId();
#if !FULL_SYSTEM
funcExeInst = oldContext->readFuncExeInst();
#endif
inst = oldContext->getInst();
+
+ _threadId = oldContext->threadId();
+ _contextId = oldContext->contextId();
}
void
SimpleThread::serialize(ostream &os)
{
ThreadState::serialize(os);
- regs.serialize(os);
+ regs.serialize(cpu, os);
// thread_num and cpu_id are deterministic from the config
}
@@ -200,7 +200,7 @@ void
SimpleThread::unserialize(Checkpoint *cp, const std::string &section)
{
ThreadState::unserialize(cp, section);
- regs.unserialize(cp, section);
+ regs.unserialize(cpu, cp, section);
// thread_num and cpu_id are deterministic from the config
}
@@ -222,14 +222,14 @@ SimpleThread::activate(int delay)
lastActivate = curTick;
// if (status() == ThreadContext::Unallocated) {
-// cpu->activateWhenReady(tid);
-// return;
+// cpu->activateWhenReady(_threadId);
+// return;
// }
_status = ThreadContext::Active;
// status() == Suspended
- cpu->activateContext(tid, delay);
+ cpu->activateContext(_threadId, delay);
}
void
@@ -243,14 +243,14 @@ SimpleThread::suspend()
/*
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
- if (cpu->check_interrupts()) {
+ if (cpu->checkInterrupts()) {
assert(status() == ThreadContext::Active);
return;
}
#endif
*/
_status = ThreadContext::Suspended;
- cpu->suspendContext(tid);
+ cpu->suspendContext(_threadId);
}
void
@@ -260,7 +260,7 @@ SimpleThread::deallocate()
return;
_status = ThreadContext::Unallocated;
- cpu->deallocateContext(tid);
+ cpu->deallocateContext(_threadId);
}
void
@@ -270,7 +270,7 @@ SimpleThread::halt()
return;
_status = ThreadContext::Halted;
- cpu->haltContext(tid);
+ cpu->haltContext(_threadId);
}
@@ -289,26 +289,3 @@ SimpleThread::copyArchRegs(ThreadContext *src_tc)
TheISA::copyRegs(src_tc, tc);
}
-#if FULL_SYSTEM
-VirtualPort*
-SimpleThread::getVirtPort(ThreadContext *src_tc)
-{
- if (!src_tc)
- return virtPort;
-
- VirtualPort *vp = new VirtualPort("tc-vport", src_tc);
- connectToMemFunc(vp);
- return vp;
-}
-
-void
-SimpleThread::delVirtPort(VirtualPort *vp)
-{
- if (vp != virtPort) {
- vp->removeConn();
- delete vp;
- }
-}
-
-#endif
-
diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh
index fa80a283a..73929d362 100644
--- a/src/cpu/simple_thread.hh
+++ b/src/cpu/simple_thread.hh
@@ -34,7 +34,6 @@
#include "arch/isa_traits.hh"
#include "arch/regfile.hh"
-#include "arch/syscallreturn.hh"
#include "arch/tlb.hh"
#include "config/full_system.hh"
#include "cpu/thread_context.hh"
@@ -99,7 +98,7 @@ class SimpleThread : public ThreadState
typedef ThreadContext::Status Status;
protected:
- RegFile regs; // correct-path register context
+ RegFile regs; // correct-path register context
public:
// pointer to CPU associated with this SimpleThread
@@ -139,7 +138,7 @@ class SimpleThread : public ThreadState
/***************************************************************
* SimpleThread functions to provide CPU with access to various
- * state, and to provide address translation methods.
+ * state.
**************************************************************/
/** Returns the pointer to this SimpleThread's ThreadContext. Used
@@ -148,21 +147,6 @@ class SimpleThread : public ThreadState
*/
ThreadContext *getTC() { return tc; }
- Fault translateInstReq(RequestPtr &req)
- {
- return itb->translate(req, tc);
- }
-
- Fault translateDataReadReq(RequestPtr &req)
- {
- return dtb->translate(req, tc, false);
- }
-
- Fault translateDataWriteReq(RequestPtr &req)
- {
- return dtb->translate(req, tc, true);
- }
-
void demapPage(Addr vaddr, uint64_t asn)
{
itb->demapPage(vaddr, asn);
@@ -197,23 +181,20 @@ class SimpleThread : public ThreadState
BaseCPU *getCpuPtr() { return cpu; }
- int getThreadNum() { return tid; }
-
TheISA::ITB *getITBPtr() { return itb; }
TheISA::DTB *getDTBPtr() { return dtb; }
-#if FULL_SYSTEM
System *getSystemPtr() { return system; }
+#if FULL_SYSTEM
FunctionalPort *getPhysPort() { return physPort; }
- /** Return a virtual port. If no thread context is specified then a static
- * port is returned. Otherwise a port is created and returned. It must be
- * deleted by deleteVirtPort(). */
- VirtualPort *getVirtPort(ThreadContext *tc);
-
- void delVirtPort(VirtualPort *vp);
+ /** Return a virtual port. This port cannot be cached locally in an object.
+ * After a CPU switch it may point to the wrong memory object which could
+ * mean stale data.
+ */
+ VirtualPort *getVirtPort() { return virtPort; }
#endif
Status status() const { return _status; }
@@ -385,37 +366,11 @@ class SimpleThread : public ThreadState
{ storeCondFailures = sc_failures; }
#if !FULL_SYSTEM
- TheISA::IntReg getSyscallArg(int i)
- {
- assert(i < TheISA::NumArgumentRegs);
- return regs.readIntReg(TheISA::flattenIntIndex(getTC(),
- TheISA::ArgumentReg[i]));
- }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, TheISA::IntReg val)
- {
- assert(i < TheISA::NumArgumentRegs);
- regs.setIntReg(TheISA::flattenIntIndex(getTC(),
- TheISA::ArgumentReg[i]), val);
- }
-
- void setSyscallReturn(SyscallReturn return_value)
- {
- TheISA::setSyscallReturn(return_value, getTC());
- }
-
void syscall(int64_t callnum)
{
process->syscall(callnum, tc);
}
#endif
-
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- regs.changeContext(param, val);
- }
};
diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc
index 52a7ede03..01136bda1 100644
--- a/src/cpu/static_inst.cc
+++ b/src/cpu/static_inst.cc
@@ -40,11 +40,17 @@ StaticInst::DecodeCache StaticInst::decodeCache;
StaticInst::AddrDecodeCache StaticInst::addrDecodeCache;
StaticInst::cacheElement StaticInst::recentDecodes[2];
+using namespace std;
+
+StaticInst::~StaticInst()
+{
+ if (cachedDisassembly)
+ delete cachedDisassembly;
+}
+
void
StaticInst::dumpDecodeCacheStats()
{
- using namespace std;
-
cerr << "Decode hash table stats @ " << curTick << ":" << endl;
cerr << "\tnum entries = " << decodeCache.size() << endl;
cerr << "\tnum buckets = " << decodeCache.bucket_count() << endl;
@@ -81,6 +87,37 @@ StaticInstPtr
StaticInst::fetchMicroop(MicroPC micropc)
{
panic("StaticInst::fetchMicroop() called on instruction "
- "that is not microcoded.");
+ "that is not microcoded.");
}
+Addr
+StaticInst::branchTarget(Addr branchPC) const
+{
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not a PC-relative branch.");
+ M5_DUMMY_RETURN;
+}
+
+Addr
+StaticInst::branchTarget(ThreadContext *tc) const
+{
+ panic("StaticInst::branchTarget() called on instruction "
+ "that is not an indirect branch.");
+ M5_DUMMY_RETURN;
+}
+
+Request::Flags
+StaticInst::memAccFlags()
+{
+ panic("StaticInst::memAccFlags called on non-memory instruction");
+ return 0;
+}
+
+const string &
+StaticInst::disassemble(Addr pc, const SymbolTable *symtab) const
+{
+ if (!cachedDisassembly)
+ cachedDisassembly = new string(generateDisassembly(pc, symtab));
+
+ return *cachedDisassembly;
+}
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
index ceda78d90..cb32f2333 100644
--- a/src/cpu/static_inst.hh
+++ b/src/cpu/static_inst.hh
@@ -42,7 +42,6 @@
#include "base/misc.hh"
#include "base/refcnt.hh"
#include "cpu/op_class.hh"
-#include "cpu/o3/dyn_inst.hh"
#include "sim/faults.hh"
#include "sim/host.hh"
@@ -54,8 +53,11 @@ class ThreadContext;
class DynInst;
class Packet;
-template <class Impl>
-class OzoneDynInst;
+class O3CPUImpl;
+template <class Impl> class BaseO3DynInst;
+typedef BaseO3DynInst<O3CPUImpl> O3DynInst;
+template <class Impl> class OzoneDynInst;
+class InOrderDynInst;
class CheckerCPU;
class FastCPU;
@@ -69,7 +71,27 @@ namespace Trace {
class InstRecord;
}
-typedef uint32_t MicroPC;
+typedef uint16_t MicroPC;
+
+static const MicroPC MicroPCRomBit = 1 << (sizeof(MicroPC) * 8 - 1);
+
+static inline MicroPC
+romMicroPC(MicroPC upc)
+{
+ return upc | MicroPCRomBit;
+}
+
+static inline MicroPC
+normalMicroPC(MicroPC upc)
+{
+ return upc & ~MicroPCRomBit;
+}
+
+static inline bool
+isRomMicroPC(MicroPC upc)
+{
+ return MicroPCRomBit & upc;
+}
/**
* Base, ISA-independent static instruction class.
@@ -105,38 +127,39 @@ class StaticInstBase : public RefCounted
/// implement this behavior via the execute() methods.
///
enum Flags {
- IsNop, ///< Is a no-op (no effect at all).
+ IsNop, ///< Is a no-op (no effect at all).
- IsInteger, ///< References integer regs.
- IsFloating, ///< References FP regs.
+ 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.
+ IsMemRef, ///< References memory (load, store, or prefetch).
+ IsLoad, ///< Reads from memory (load or prefetch).
+ IsStore, ///< Writes to memory.
IsStoreConditional, ///< Store conditional instruction.
IsIndexed, ///< Accesses memory with an indexed address computation
- IsInstPrefetch, ///< Instruction-cache prefetch.
- IsDataPrefetch, ///< Data-cache prefetch.
+ 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.
+ 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.
+ IsThreadSync, ///< Thread synchronization operation.
- IsSerializing, ///< Serializes pipeline: won't execute until all
+ IsSerializing, ///< Serializes pipeline: won't execute until all
/// older instructions have committed.
IsSerializeBefore,
IsSerializeAfter,
- IsMemBarrier, ///< Is a memory barrier
- IsWriteBarrier, ///< Is a write barrier
+ IsMemBarrier, ///< Is a memory barrier
+ IsWriteBarrier, ///< Is a write barrier
+ IsReadBarrier, ///< Is a read barrier
IsERET, /// <- Causes the IFU to stall (MIPS ISA)
IsNonSpeculative, ///< Should not be executed speculatively
@@ -150,12 +173,12 @@ class StaticInstBase : public RefCounted
//Flags for microcode
IsMacroop, ///< Is a macroop containing microops
- IsMicroop, ///< Is a microop
- IsDelayedCommit, ///< This microop doesn't commit right away
- IsLastMicroop, ///< This microop ends a microop sequence
- IsFirstMicroop, ///< This microop begins a microop sequence
+ IsMicroop, ///< Is a microop
+ IsDelayedCommit, ///< This microop doesn't commit right away
+ IsLastMicroop, ///< This microop ends a microop sequence
+ IsFirstMicroop, ///< This microop begins a microop sequence
//This flag doesn't do anything yet
- IsMicroBranch, ///< This microop branches within the microcode for a macroop
+ IsMicroBranch, ///< This microop branches within the microcode for a macroop
IsDspOp,
NumFlags
@@ -215,26 +238,26 @@ class StaticInstBase : public RefCounted
/// of the individual flags.
//@{
- bool isNop() const { return flags[IsNop]; }
+ 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 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 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 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 isCondCtrl() const { return flags[IsCondControl]; }
+ bool isUncondCtrl() const { return flags[IsUncondControl]; }
bool isCondDelaySlot() const { return flags[IsCondDelaySlot]; }
bool isThreadSync() const { return flags[IsThreadSync]; }
@@ -287,8 +310,8 @@ class StaticInst : public StaticInstBase
typedef TheISA::RegIndex RegIndex;
enum {
- MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
- MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs, //< Max source regs
+ MaxInstDestRegs = TheISA::MaxInstDestRegs, //< Max dest regs
};
@@ -360,12 +383,7 @@ class StaticInst : public StaticInstBase
{ }
public:
-
- virtual ~StaticInst()
- {
- if (cachedDisassembly)
- delete cachedDisassembly;
- }
+ virtual ~StaticInst();
/**
* The execute() signatures are auto-generated by scons based on the
@@ -384,12 +402,7 @@ class StaticInst : public StaticInstBase
* 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.");
- M5_DUMMY_RETURN
- }
+ virtual Addr branchTarget(Addr branchPC) const;
/**
* Return the target address for an indirect branch (jump). The
@@ -398,12 +411,7 @@ class StaticInst : public StaticInstBase
* execute the branch in question. Invalid if not an indirect
* branch (i.e. isIndirectCtrl() should be true).
*/
- virtual Addr branchTarget(ThreadContext *tc) const
- {
- panic("StaticInst::branchTarget() called on instruction "
- "that is not an indirect branch.");
- M5_DUMMY_RETURN
- }
+ virtual Addr branchTarget(ThreadContext *tc) const;
/**
* Return true if the instruction is a control transfer, and if so,
@@ -411,6 +419,8 @@ class StaticInst : public StaticInstBase
*/
bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const;
+ virtual Request::Flags memAccFlags();
+
/**
* Return string representation of disassembled instruction.
* The default version of this function will call the internal
@@ -419,14 +429,7 @@ class StaticInst : public StaticInstBase
* 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;
- }
+ const SymbolTable *symtab = 0) const;
/// Decoded instruction cache type.
/// For now we're using a generic hash_map; this seems to work
@@ -458,13 +461,13 @@ class StaticInst : public StaticInstBase
/// A cache of decoded instruction objects from addresses.
static AddrDecodeCache addrDecodeCache;
- struct cacheElement {
+ struct cacheElement
+ {
Addr page_addr;
AddrDecodePage *decodePage;
- cacheElement()
- :decodePage(NULL) { }
- } ;
+ cacheElement() : decodePage(NULL) { }
+ };
/// An array of recently decoded instructions.
// might not use an array if there is only two elements
@@ -493,7 +496,7 @@ class StaticInst : public StaticInstBase
/// @retval A pointer to the corresponding StaticInst object.
//This is defined as inlined below.
static StaticInstPtr searchCache(ExtMachInst mach_inst, Addr addr,
- AddrDecodePage * decodePage);
+ AddrDecodePage *decodePage);
};
typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr;
@@ -547,7 +550,8 @@ class AddrDecodePage
public:
/// Constructor
- AddrDecodePage() {
+ AddrDecodePage()
+ {
lowerMask = TheISA::PageBytes - 1;
memset(valid, 0, TheISA::PageBytes);
}
@@ -557,7 +561,8 @@ class AddrDecodePage
/// related to the address
/// @param mach_inst The binary instruction to check
/// @param addr The address containing the instruction
- inline bool decoded(ExtMachInst mach_inst, Addr addr)
+ bool
+ decoded(ExtMachInst mach_inst, Addr addr)
{
return (valid[addr & lowerMask] &&
(instructions[addr & lowerMask]->machInst == mach_inst));
@@ -567,19 +572,22 @@ class AddrDecodePage
/// to check if the instruction is valid.
/// @param addr The address of the instruction.
/// @retval A pointer to the corresponding StaticInst object.
- inline StaticInstPtr getInst(Addr addr)
- { return instructions[addr & lowerMask]; }
+ StaticInstPtr
+ getInst(Addr addr)
+ {
+ return instructions[addr & lowerMask];
+ }
/// Inserts a pointer to a StaticInst object into the list of decoded
/// instructions on the page.
/// @param addr The address of the instruction.
/// @param si A pointer to the corresponding StaticInst object.
- inline void insert(Addr addr, StaticInstPtr &si)
+ void
+ insert(Addr addr, StaticInstPtr &si)
{
instructions[addr & lowerMask] = si;
valid[addr & lowerMask] = true;
}
-
};
@@ -628,7 +636,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr)
}
// creates a new object for a page of decoded instructions
- AddrDecodePage * decodePage = new AddrDecodePage;
+ AddrDecodePage *decodePage = new AddrDecodePage;
addrDecodeCache[page_addr] = decodePage;
updateCache(page_addr, decodePage);
return searchCache(mach_inst, addr, decodePage);
@@ -636,7 +644,7 @@ StaticInst::decode(StaticInst::ExtMachInst mach_inst, Addr addr)
inline StaticInstPtr
StaticInst::searchCache(ExtMachInst mach_inst, Addr addr,
- AddrDecodePage * decodePage)
+ AddrDecodePage *decodePage)
{
DecodeCache::iterator iter = decodeCache.find(mach_inst);
if (iter != decodeCache.end()) {
diff --git a/src/cpu/thread_context.cc b/src/cpu/thread_context.cc
index 10c94027d..ab105a435 100644
--- a/src/cpu/thread_context.cc
+++ b/src/cpu/thread_context.cc
@@ -74,8 +74,15 @@ ThreadContext::compare(ThreadContext *one, ThreadContext *two)
if (npc1 != npc2)
panic("NPCs doesn't match, one: %#x, two: %#x", npc1, npc2);
- int id1 = one->readCpuId();
- int id2 = two->readCpuId();
+ int id1 = one->cpuId();
+ int id2 = two->cpuId();
if (id1 != id2)
panic("CPU ids don't match, one: %d, two: %d", id1, id2);
+
+ id1 = one->contextId();
+ id2 = two->contextId();
+ if (id1 != id2)
+ panic("Context ids don't match, one: %d, two: %d", id1, id2);
+
+
}
diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh
index cf51c1637..700f1571e 100644
--- a/src/cpu/thread_context.hh
+++ b/src/cpu/thread_context.hh
@@ -38,7 +38,6 @@
#include "sim/faults.hh"
#include "sim/host.hh"
#include "sim/serialize.hh"
-#include "sim/syscallreturn.hh"
#include "sim/byteswap.hh"
// @todo: Figure out a more architecture independent way to obtain the ITB and
@@ -115,26 +114,30 @@ class ThreadContext
virtual BaseCPU *getCpuPtr() = 0;
- virtual void setCpuId(int id) = 0;
+ virtual int cpuId() = 0;
- virtual int readCpuId() = 0;
+ virtual int threadId() = 0;
+
+ virtual void setThreadId(int id) = 0;
+
+ virtual int contextId() = 0;
+
+ virtual void setContextId(int id) = 0;
virtual TheISA::ITB *getITBPtr() = 0;
virtual TheISA::DTB *getDTBPtr() = 0;
-#if FULL_SYSTEM
virtual System *getSystemPtr() = 0;
+#if FULL_SYSTEM
virtual TheISA::Kernel::Statistics *getKernelStats() = 0;
virtual FunctionalPort *getPhysPort() = 0;
- virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0;
-
- virtual void delVirtPort(VirtualPort *vp) = 0;
+ virtual VirtualPort *getVirtPort() = 0;
- virtual void connectMemPorts() = 0;
+ virtual void connectMemPorts(ThreadContext *tc) = 0;
#else
virtual TranslatingPort *getMemPort() = 0;
@@ -181,8 +184,6 @@ class ThreadContext
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;
@@ -256,13 +257,6 @@ class ThreadContext
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;
@@ -274,9 +268,6 @@ class ThreadContext
virtual int exit() { return 1; };
#endif
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val) = 0;
-
/** function to compare two thread contexts (for debugging) */
static void compare(ThreadContext *one, ThreadContext *two);
};
@@ -305,27 +296,31 @@ class ProxyThreadContext : public ThreadContext
BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
- void setCpuId(int id) { actualTC->setCpuId(id); }
+ int cpuId() { return actualTC->cpuId(); }
+
+ int threadId() { return actualTC->threadId(); }
- int readCpuId() { return actualTC->readCpuId(); }
+ void setThreadId(int id) { return actualTC->setThreadId(id); }
+
+ int contextId() { return actualTC->contextId(); }
+
+ void setContextId(int id) { actualTC->setContextId(id); }
TheISA::ITB *getITBPtr() { return actualTC->getITBPtr(); }
TheISA::DTB *getDTBPtr() { return actualTC->getDTBPtr(); }
-#if FULL_SYSTEM
System *getSystemPtr() { return actualTC->getSystemPtr(); }
+#if FULL_SYSTEM
TheISA::Kernel::Statistics *getKernelStats()
{ return actualTC->getKernelStats(); }
FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return actualTC->getVirtPort(tc); }
-
- void delVirtPort(VirtualPort *vp) { return actualTC->delVirtPort(vp); }
+ VirtualPort *getVirtPort() { return actualTC->getVirtPort(); }
- void connectMemPorts() { actualTC->connectMemPorts(); }
+ void connectMemPorts(ThreadContext *tc) { actualTC->connectMemPorts(tc); }
#else
TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
@@ -371,9 +366,6 @@ class ProxyThreadContext : public ThreadContext
void profileClear() { return actualTC->profileClear(); }
void profileSample() { return actualTC->profileSample(); }
#endif
-
- int getThreadNum() { return actualTC->getThreadNum(); }
-
// @todo: Do I need this?
MachInst getInst() { return actualTC->getInst(); }
@@ -433,7 +425,7 @@ class ProxyThreadContext : public ThreadContext
uint64_t readNextMicroPC() { return actualTC->readMicroPC(); }
- void setNextMicroPC(uint64_t val) { actualTC->setMicroPC(val); }
+ void setNextMicroPC(uint64_t val) { actualTC->setNextMicroPC(val); }
MiscReg readMiscRegNoEffect(int misc_reg)
{ return actualTC->readMiscRegNoEffect(misc_reg); }
@@ -457,26 +449,11 @@ class ProxyThreadContext : public ThreadContext
bool misspeculating() { return actualTC->misspeculating(); }
#if !FULL_SYSTEM
- IntReg getSyscallArg(int i) { return actualTC->getSyscallArg(i); }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- { actualTC->setSyscallArg(i, val); }
-
- void setSyscallReturn(SyscallReturn return_value)
- { actualTC->setSyscallReturn(return_value); }
-
void syscall(int64_t callnum)
{ actualTC->syscall(callnum); }
Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
#endif
-
- void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- {
- actualTC->changeRegFileContext(param, val);
- }
};
#endif
diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc
index be8f822f2..b0e719ddf 100644
--- a/src/cpu/thread_state.cc
+++ b/src/cpu/thread_state.cc
@@ -43,15 +43,15 @@
#endif
#if FULL_SYSTEM
-ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid)
- : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ThreadState::ThreadState(BaseCPU *cpu, int _tid)
+ : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0),
profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL),
- physPort(NULL), virtPort(NULL),
+ kernelStats(NULL), physPort(NULL), virtPort(NULL),
microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0)
#else
-ThreadState::ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process,
+ThreadState::ThreadState(BaseCPU *cpu, int _tid, Process *_process,
short _asid)
- : baseCpu(cpu), cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ : baseCpu(cpu), _threadId(_tid), lastActivate(0), lastSuspend(0),
port(NULL), process(_process), asid(_asid),
microPC(0), nextMicroPC(1), funcExeInst(0), storeCondFailures(0)
#endif
@@ -105,7 +105,7 @@ ThreadState::unserialize(Checkpoint *cp, const std::string &section)
Tick quiesceEndTick;
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
- quiesceEvent->schedule(quiesceEndTick);
+ baseCpu->schedule(quiesceEvent, quiesceEndTick);
if (kernelStats)
kernelStats->unserialize(cp, section);
#endif
@@ -113,10 +113,10 @@ ThreadState::unserialize(Checkpoint *cp, const std::string &section)
#if FULL_SYSTEM
void
-ThreadState::connectMemPorts()
+ThreadState::connectMemPorts(ThreadContext *tc)
{
connectPhysPort();
- connectVirtPort();
+ connectVirtPort(tc);
}
void
@@ -129,12 +129,12 @@ ThreadState::connectPhysPort()
physPort->removeConn();
else
physPort = new FunctionalPort(csprintf("%s-%d-funcport",
- baseCpu->name(), tid));
+ baseCpu->name(), _threadId));
connectToMemFunc(physPort);
}
void
-ThreadState::connectVirtPort()
+ThreadState::connectVirtPort(ThreadContext *tc)
{
// @todo: For now this disregards any older port that may have
// already existed. Fix this memory leak once the bus port IDs
@@ -143,7 +143,7 @@ ThreadState::connectVirtPort()
virtPort->removeConn();
else
virtPort = new VirtualPort(csprintf("%s-%d-vport",
- baseCpu->name(), tid));
+ baseCpu->name(), _threadId), tc);
connectToMemFunc(virtPort);
}
@@ -169,7 +169,7 @@ ThreadState::getMemPort()
return port;
/* Use this port to for syscall emulation writes to memory. */
- port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), tid),
+ port = new TranslatingPort(csprintf("%s-%d-funcport", baseCpu->name(), _threadId),
process, TranslatingPort::NextPage);
connectToMemFunc(port);
diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh
index 4f878db1f..99f0c2a87 100644
--- a/src/cpu/thread_state.hh
+++ b/src/cpu/thread_state.hh
@@ -34,6 +34,7 @@
#include "arch/types.hh"
#include "cpu/profile.hh"
#include "cpu/thread_context.hh"
+#include "cpu/base.hh"
#if !FULL_SYSTEM
#include "mem/mem_object.hh"
@@ -51,7 +52,6 @@ namespace TheISA {
};
#endif
-class BaseCPU;
class Checkpoint;
class Port;
class TranslatingPort;
@@ -66,9 +66,9 @@ struct ThreadState {
typedef ThreadContext::Status Status;
#if FULL_SYSTEM
- ThreadState(BaseCPU *cpu, int _cpuId, int _tid);
+ ThreadState(BaseCPU *cpu, int _tid);
#else
- ThreadState(BaseCPU *cpu, int _cpuId, int _tid, Process *_process,
+ ThreadState(BaseCPU *cpu, int _tid, Process *_process,
short _asid);
#endif
@@ -78,24 +78,26 @@ struct ThreadState {
void unserialize(Checkpoint *cp, const std::string &section);
- void setCpuId(int id) { cpuId = id; }
+ int cpuId() { return baseCpu->cpuId(); }
- int readCpuId() { return cpuId; }
+ int contextId() { return _contextId; }
- void setTid(int id) { tid = id; }
+ void setContextId(int id) { _contextId = id; }
- int readTid() { return tid; }
+ void setThreadId(int id) { _threadId = id; }
+
+ int threadId() { return _threadId; }
Tick readLastActivate() { return lastActivate; }
Tick readLastSuspend() { return lastSuspend; }
#if FULL_SYSTEM
- void connectMemPorts();
+ void connectMemPorts(ThreadContext *tc);
void connectPhysPort();
- void connectVirtPort();
+ void connectVirtPort(ThreadContext *tc);
void dumpFuncProfile();
@@ -111,9 +113,7 @@ struct ThreadState {
void setPhysPort(FunctionalPort *port) { physPort = port; }
- VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; }
-
- void setVirtPort(VirtualPort *port) { virtPort = port; }
+ VirtualPort *getVirtPort() { return virtPort; }
#else
Process *getProcessPtr() { return process; }
@@ -155,9 +155,9 @@ struct ThreadState {
/** Number of instructions committed. */
Counter numInst;
/** Stat for number instructions committed. */
- Stats::Scalar<> numInsts;
+ Stats::Scalar numInsts;
/** Stat for number of memory references. */
- Stats::Scalar<> numMemRefs;
+ Stats::Scalar numMemRefs;
/** Number of simulated loads, used for tracking events based on
* the number of loads committed.
@@ -173,12 +173,11 @@ struct ThreadState {
// Pointer to the base CPU.
BaseCPU *baseCpu;
- // 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 cpuId;
+ // system wide HW context id
+ int _contextId;
// Index of hardware thread context on the CPU that this represents.
- int tid;
+ int _threadId;
public:
/** Last time activate was called on this thread. */
@@ -201,7 +200,7 @@ struct ThreadState {
FunctionalPort *physPort;
/** A functional port, outgoing only, for functional accesse to virtual
- * addresses. That doen't require execution context information */
+ * addresses. */
VirtualPort *virtPort;
#else
TranslatingPort *port;
diff --git a/src/dev/CopyEngine.py b/src/dev/CopyEngine.py
new file mode 100644
index 000000000..29d9a23dd
--- /dev/null
+++ b/src/dev/CopyEngine.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+from Pci import PciDevice
+
+class CopyEngine(PciDevice):
+ type = 'CopyEngine'
+ VendorID = 0x8086
+ DeviceID = 0x1a38
+ Revision = 0xA2 # CM2 stepping (newest listed)
+ SubsystemID = 0
+ SubsystemVendorID = 0
+ Status = 0x0000
+ SubClassCode = 0x08
+ ClassCode = 0x80
+ ProgIF = 0x00
+ MaximumLatency = 0x00
+ MinimumGrant = 0xff
+ InterruptLine = 0x20
+ InterruptPin = 0x01
+ BAR0Size = '1kB'
+
+ ChanCnt = Param.UInt8(4, "Number of DMA channels that exist on device")
+ XferCap = Param.MemorySize('4kB', "Number of bits of transfer size that are supported")
+
+
+ clock = Param.Clock('500MHz', "Clock speed of the device")
+ latBeforeBegin = Param.Latency('20ns', "Latency after a DMA command is seen before it's proccessed")
+ latAfterCompletion = Param.Latency('20ns', "Latency after a DMA command is complete before it's reported as such")
+
+
diff --git a/src/dev/DiskImage.py b/src/dev/DiskImage.py
index af2407458..92eb0553c 100644
--- a/src/dev/DiskImage.py
+++ b/src/dev/DiskImage.py
@@ -42,3 +42,4 @@ class CowDiskImage(DiskImage):
child = Param.DiskImage(RawDiskImage(read_only=True),
"child image")
table_size = Param.Int(65536, "initial table size")
+ image_file = ""
diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py
index 2beb0d537..d73d56d03 100644
--- a/src/dev/Ethernet.py
+++ b/src/dev/Ethernet.py
@@ -67,6 +67,7 @@ class EtherDevice(PciDevice):
interface = Port("Ethernet Interrface")
class IGbE(EtherDevice):
+ # Base class for two IGbE adapters listed above
type = 'IGbE'
hardware_address = Param.EthernetAddr(NextEthernetAddr,
"Ethernet Hardware Address")
@@ -80,7 +81,6 @@ class IGbE(EtherDevice):
"Number of enteries in the rx descriptor cache")
clock = Param.Clock('500MHz', "Clock speed of the device")
VendorID = 0x8086
- DeviceID = 0x1075
SubsystemID = 0x1008
SubsystemVendorID = 0x8086
Status = 0x0000
@@ -98,6 +98,28 @@ class IGbE(EtherDevice):
InterruptLine = 0x1e
InterruptPin = 0x01
BAR0Size = '128kB'
+ wb_delay = Param.Latency('10ns', "delay before desc writeback occurs")
+ fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs")
+ fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs")
+ wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs")
+ tx_read_delay = Param.Latency('0ns', "delay after tx dma read")
+ rx_write_delay = Param.Latency('0ns', "delay after rx dma read")
+ phy_pid = Param.UInt16("Phy PID that corresponds to device ID")
+ phy_epid = Param.UInt16("Phy EPID that corresponds to device ID")
+
+class IGbE_e1000(IGbE):
+ # Older Intel 8254x based gigabit ethernet adapter
+ # Uses Intel e1000 driver
+ DeviceID = 0x1075
+ phy_pid = 0x02A8
+ phy_epid = 0x0380
+
+class IGbE_igb(IGbE):
+ # Newer Intel 8257x based gigabit ethernet adapter
+ # Uses Intel igb driver and in theory supports packet splitting and LRO
+ DeviceID = 0x10C9
+ phy_pid = 0x0141
+ phy_epid = 0x0CC0
class EtherDevBase(EtherDevice):
type = 'EtherDevBase'
@@ -153,8 +175,7 @@ class NSGigE(EtherDevBase):
class Sinic(EtherDevBase):
type = 'Sinic'
- cxx_namespace = 'Sinic'
- cxx_class = 'Device'
+ cxx_class = 'Sinic::Device'
rx_max_copy = Param.MemorySize('1514B', "rx max copy")
tx_max_copy = Param.MemorySize('16kB', "tx max copy")
@@ -164,6 +185,9 @@ class Sinic(EtherDevBase):
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_size = Param.UInt32(64, "Bytes to copy if below threshold")
+ zero_copy_threshold = Param.UInt32(256,
+ "Only zero copy above this threshold")
zero_copy = Param.Bool(False, "Zero copy receive")
delay_copy = Param.Bool(False, "Delayed copy transmit")
virtual_addr = Param.Bool(False, "Virtual addressing")
diff --git a/src/dev/Pci.py b/src/dev/Pci.py
index b50e1b15c..bd67d82fb 100644
--- a/src/dev/Pci.py
+++ b/src/dev/Pci.py
@@ -73,6 +73,12 @@ class PciDevice(DmaDevice):
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")
+ BAR0LegacyIO = Param.Bool(False, "Whether BAR0 is hardwired legacy IO")
+ BAR1LegacyIO = Param.Bool(False, "Whether BAR1 is hardwired legacy IO")
+ BAR2LegacyIO = Param.Bool(False, "Whether BAR2 is hardwired legacy IO")
+ BAR3LegacyIO = Param.Bool(False, "Whether BAR3 is hardwired legacy IO")
+ BAR4LegacyIO = Param.Bool(False, "Whether BAR4 is hardwired legacy IO")
+ BAR5LegacyIO = Param.Bool(False, "Whether BAR5 is hardwired legacy IO")
CardbusCIS = Param.UInt32(0x00, "Cardbus Card Information Structure")
SubsystemID = Param.UInt16(0x00, "Subsystem ID")
diff --git a/src/dev/SConscript b/src/dev/SConscript
index 0aba8ac35..c09ec3dcd 100644
--- a/src/dev/SConscript
+++ b/src/dev/SConscript
@@ -33,19 +33,22 @@ Import('*')
if env['FULL_SYSTEM']:
SimObject('BadDevice.py')
+ SimObject('CopyEngine.py')
SimObject('Device.py')
SimObject('DiskImage.py')
SimObject('Ethernet.py')
SimObject('Ide.py')
SimObject('Pci.py')
SimObject('Platform.py')
- SimObject('SimConsole.py')
SimObject('SimpleDisk.py')
+ SimObject('Terminal.py')
SimObject('Uart.py')
Source('baddev.cc')
+ Source('copy_engine.cc')
Source('disk_image.cc')
Source('etherbus.cc')
+ Source('etherdevice.cc')
Source('etherdump.cc')
Source('etherint.cc')
Source('etherlink.cc')
@@ -54,24 +57,25 @@ if env['FULL_SYSTEM']:
Source('i8254xGBe.cc')
Source('ide_ctrl.cc')
Source('ide_disk.cc')
+ Source('intel_8254_timer.cc')
Source('io_device.cc')
Source('isa_fake.cc')
+ Source('mc146818.cc')
Source('ns_gige.cc')
Source('pciconfigall.cc')
Source('pcidev.cc')
Source('pktfifo.cc')
Source('platform.cc')
- Source('simconsole.cc')
Source('simple_disk.cc')
Source('sinic.cc')
+ Source('terminal.cc')
Source('uart.cc')
Source('uart8250.cc')
- TraceFlag('Console')
- TraceFlag('ConsoleVerbose')
TraceFlag('DiskImageRead')
TraceFlag('DiskImageWrite')
TraceFlag('DMA')
+ TraceFlag('DMACopyEngine')
TraceFlag('Ethernet')
TraceFlag('EthernetCksum')
TraceFlag('EthernetDMA')
@@ -83,17 +87,21 @@ if env['FULL_SYSTEM']:
TraceFlag('EthernetSM')
TraceFlag('IdeCtrl')
TraceFlag('IdeDisk')
+ TraceFlag('Intel8254Timer')
TraceFlag('IsaFake')
+ TraceFlag('MC146818')
TraceFlag('PCIDEV')
TraceFlag('PciConfigAll')
TraceFlag('SimpleDisk')
TraceFlag('SimpleDiskData')
+ TraceFlag('Terminal')
+ TraceFlag('TerminalVerbose')
TraceFlag('Uart')
CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
- 'EthernetCksum' ])
+ 'EthernetCksum', 'EthernetEEPROM' ])
CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])
diff --git a/src/dev/SimConsole.py b/src/dev/Terminal.py
index bb8420527..d67019198 100644
--- a/src/dev/SimConsole.py
+++ b/src/dev/Terminal.py
@@ -30,10 +30,9 @@ from m5.SimObject import SimObject
from m5.params import *
from m5.proxy import *
-class SimConsole(SimObject):
- type = 'SimConsole'
- append_name = Param.Bool(True, "append name() to filename")
+class Terminal(SimObject):
+ type = 'Terminal'
intr_control = Param.IntrControl(Parent.any, "interrupt controller")
port = Param.TcpPort(3456, "listen port")
- number = Param.Int(0, "console number")
- output = Param.String('console', "file to dump output to")
+ number = Param.Int(0, "terminal number")
+ output = Param.Bool(True, "Enable output dump to file")
diff --git a/src/dev/Uart.py b/src/dev/Uart.py
index e32517a4c..c5db3c42f 100644
--- a/src/dev/Uart.py
+++ b/src/dev/Uart.py
@@ -34,7 +34,7 @@ from Device import BasicPioDevice
class Uart(BasicPioDevice):
type = 'Uart'
abstract = True
- sim_console = Param.SimConsole(Parent.any, "The console")
+ terminal = Param.Terminal(Parent.any, "The terminal")
class Uart8250(Uart):
type = 'Uart8250'
diff --git a/src/dev/alpha/AlphaConsole.py b/src/dev/alpha/AlphaBackdoor.py
index 43c7ef954..fa9627164 100644
--- a/src/dev/alpha/AlphaConsole.py
+++ b/src/dev/alpha/AlphaBackdoor.py
@@ -30,9 +30,9 @@ from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
-class AlphaConsole(BasicPioDevice):
- type = 'AlphaConsole'
+class AlphaBackdoor(BasicPioDevice):
+ type = 'AlphaBackdoor'
cpu = Param.BaseCPU(Parent.cpu[0], "Processor")
disk = Param.SimpleDisk("Simple Disk")
- sim_console = Param.SimConsole(Parent.any, "The Simulator Console")
+ terminal = Param.Terminal(Parent.any, "The console terminal")
system = Param.AlphaSystem(Parent.any, "system object")
diff --git a/src/dev/alpha/SConscript b/src/dev/alpha/SConscript
index 2292c3c57..4dbb73903 100644
--- a/src/dev/alpha/SConscript
+++ b/src/dev/alpha/SConscript
@@ -32,15 +32,14 @@
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'alpha':
- SimObject('AlphaConsole.py')
+ SimObject('AlphaBackdoor.py')
SimObject('Tsunami.py')
- Source('console.cc')
+ Source('backdoor.cc')
Source('tsunami.cc')
Source('tsunami_cchip.cc')
Source('tsunami_io.cc')
Source('tsunami_pchip.cc')
- TraceFlag('AlphaConsole')
- TraceFlag('MC146818')
+ TraceFlag('AlphaBackdoor')
TraceFlag('Tsunami')
diff --git a/src/dev/alpha/Tsunami.py b/src/dev/alpha/Tsunami.py
index 484976c09..5440486b6 100644
--- a/src/dev/alpha/Tsunami.py
+++ b/src/dev/alpha/Tsunami.py
@@ -28,12 +28,12 @@
from m5.params import *
from m5.proxy import *
+from BadDevice import BadDevice
+from AlphaBackdoor import AlphaBackdoor
from Device import BasicPioDevice, IsaFake, BadAddr
+from Pci import PciConfigAll
from Platform import Platform
-from AlphaConsole import AlphaConsole
from Uart import Uart8250
-from Pci import PciConfigAll
-from BadDevice import BadDevice
class TsunamiCChip(BasicPioDevice):
type = 'TsunamiCChip'
@@ -87,7 +87,7 @@ class Tsunami(Platform):
fb = BadDevice(pio_addr=0x801fc0003d0, devicename='FrameBuffer')
io = TsunamiIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0x801fc0003f8)
- console = AlphaConsole(pio_addr=0x80200000000, disk=Parent.simple_disk)
+ backdoor = AlphaBackdoor(pio_addr=0x80200000000, disk=Parent.simple_disk)
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
@@ -120,4 +120,4 @@ class Tsunami(Platform):
self.fb.pio = bus.port
self.io.pio = bus.port
self.uart.pio = bus.port
- self.console.pio = bus.port
+ self.backdoor.pio = bus.port
diff --git a/src/dev/alpha/access.h b/src/dev/alpha/access.h
index 4adeaf84b..72eb4950a 100644
--- a/src/dev/alpha/access.h
+++ b/src/dev/alpha/access.h
@@ -45,31 +45,31 @@ typedef unsigned long uint64_t;
// This structure hacked up from simos
struct AlphaAccess
{
- uint32_t last_offset; // 00: must be first field
- uint32_t version; // 04:
- uint32_t numCPUs; // 08:
- uint32_t intrClockFrequency; // 0C: Hz
- uint64_t cpuClock; // 10: MHz
- uint64_t mem_size; // 18:
+ uint32_t last_offset; // 00: must be first field
+ uint32_t version; // 04:
+ uint32_t numCPUs; // 08:
+ uint32_t intrClockFrequency; // 0C: Hz
+ uint64_t cpuClock; // 10: MHz
+ uint64_t mem_size; // 18:
// Loaded kernel
- uint64_t kernStart; // 20:
- uint64_t kernEnd; // 28:
- uint64_t entryPoint; // 30:
+ uint64_t kernStart; // 20:
+ uint64_t kernEnd; // 28:
+ uint64_t entryPoint; // 30:
// console disk stuff
- uint64_t diskUnit; // 38:
- uint64_t diskCount; // 40:
- uint64_t diskPAddr; // 48:
- uint64_t diskBlock; // 50:
- uint64_t diskOperation; // 58:
+ uint64_t diskUnit; // 38:
+ uint64_t diskCount; // 40:
+ uint64_t diskPAddr; // 48:
+ uint64_t diskBlock; // 50:
+ uint64_t diskOperation; // 58:
// console simple output stuff
- uint64_t outputChar; // 60: Placeholder for output
- uint64_t inputChar; // 68: Placeholder for input
+ uint64_t outputChar; // 60: Placeholder for output
+ uint64_t inputChar; // 68: Placeholder for input
// MP boot
- uint64_t cpuStack[64]; // 70:
+ uint64_t cpuStack[64]; // 70:
};
#endif // __ALPHA_ACCESS_H__
diff --git a/src/dev/alpha/console.cc b/src/dev/alpha/backdoor.cc
index 493a21f99..66f682e66 100644
--- a/src/dev/alpha/console.cc
+++ b/src/dev/alpha/backdoor.cc
@@ -32,7 +32,7 @@
*/
/** @file
- * Alpha Console Definition
+ * Alpha Console Backdoor Definition
*/
#include <cstddef>
@@ -44,21 +44,21 @@
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "dev/alpha/console.hh"
+#include "dev/alpha/backdoor.hh"
#include "dev/platform.hh"
-#include "dev/simconsole.hh"
#include "dev/simple_disk.hh"
+#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
-#include "params/AlphaConsole.hh"
+#include "params/AlphaBackdoor.hh"
#include "sim/sim_object.hh"
using namespace std;
using namespace AlphaISA;
-AlphaConsole::AlphaConsole(const Params *p)
- : BasicPioDevice(p), disk(p->disk), console(p->sim_console),
+AlphaBackdoor::AlphaBackdoor(const Params *p)
+ : BasicPioDevice(p), disk(p->disk), terminal(p->terminal),
system(p->system), cpu(p->cpu)
{
@@ -81,10 +81,10 @@ AlphaConsole::AlphaConsole(const Params *p)
}
void
-AlphaConsole::startup()
+AlphaBackdoor::startup()
{
system->setAlphaAccess(pioAddr);
- alphaAccess->numCPUs = system->getNumCPUs();
+ alphaAccess->numCPUs = system->numContexts();
alphaAccess->kernStart = system->getKernelStart();
alphaAccess->kernEnd = system->getKernelEnd();
alphaAccess->entryPoint = system->getKernelEntry();
@@ -94,7 +94,7 @@ AlphaConsole::startup()
}
Tick
-AlphaConsole::read(PacketPtr pkt)
+AlphaBackdoor::read(PacketPtr pkt)
{
/** XXX Do we want to push the addr munging to a bus brige or something? So
@@ -132,14 +132,14 @@ AlphaConsole::read(PacketPtr pkt)
*/
pkt->setBadAddress();
}
- DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ DPRINTF(AlphaBackdoor, "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());
+ pkt->set(terminal->console_in());
break;
case offsetof(AlphaAccess, cpuClock):
pkt->set(alphaAccess->cpuClock);
@@ -183,7 +183,7 @@ AlphaConsole::read(PacketPtr pkt)
else
panic("Unknown 64bit access, %#x\n", daddr);
}
- DPRINTF(AlphaConsole, "read: offset=%#x val=%#x\n", daddr,
+ DPRINTF(AlphaBackdoor, "read: offset=%#x val=%#x\n", daddr,
pkt->get<uint64_t>());
break;
default:
@@ -193,7 +193,7 @@ AlphaConsole::read(PacketPtr pkt)
}
Tick
-AlphaConsole::write(PacketPtr pkt)
+AlphaBackdoor::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
@@ -228,7 +228,7 @@ AlphaConsole::write(PacketPtr pkt)
break;
case offsetof(AlphaAccess, outputChar):
- console->out((char)(val & 0xff));
+ terminal->out((char)(val & 0xff));
break;
default:
@@ -248,7 +248,7 @@ AlphaConsole::write(PacketPtr pkt)
}
void
-AlphaConsole::Access::serialize(ostream &os)
+AlphaBackdoor::Access::serialize(ostream &os)
{
SERIALIZE_SCALAR(last_offset);
SERIALIZE_SCALAR(version);
@@ -270,7 +270,7 @@ AlphaConsole::Access::serialize(ostream &os)
}
void
-AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
+AlphaBackdoor::Access::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(last_offset);
UNSERIALIZE_SCALAR(version);
@@ -292,19 +292,19 @@ AlphaConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
}
void
-AlphaConsole::serialize(ostream &os)
+AlphaBackdoor::serialize(ostream &os)
{
alphaAccess->serialize(os);
}
void
-AlphaConsole::unserialize(Checkpoint *cp, const std::string &section)
+AlphaBackdoor::unserialize(Checkpoint *cp, const std::string &section)
{
alphaAccess->unserialize(cp, section);
}
-AlphaConsole *
-AlphaConsoleParams::create()
+AlphaBackdoor *
+AlphaBackdoorParams::create()
{
- return new AlphaConsole(this);
+ return new AlphaBackdoor(this);
}
diff --git a/src/dev/alpha/console.hh b/src/dev/alpha/backdoor.hh
index e77a7fad6..ad3c79823 100644
--- a/src/dev/alpha/console.hh
+++ b/src/dev/alpha/backdoor.hh
@@ -29,28 +29,28 @@
*/
/** @file
- * System Console Interface
+ * System Console Backdoor Interface
*/
-#ifndef __ALPHA_CONSOLE_HH__
-#define __ALPHA_CONSOLE_HH__
+#ifndef __DEV_ALPHA_BACKDOOR_HH__
+#define __DEV_ALPHA_BACKDOOR_HH__
#include "base/range.hh"
#include "dev/alpha/access.h"
#include "dev/io_device.hh"
-#include "params/AlphaConsole.hh"
+#include "params/AlphaBackdoor.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
class BaseCPU;
-class SimConsole;
+class Terminal;
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.
+ * System Console Backdoor.
*
* The system console is a small standalone program that is initially
* run when the system boots. It contains the necessary code to
@@ -72,7 +72,7 @@ class SimpleDisk;
* primarily used doing boot before the kernel has loaded its device
* drivers.
*/
-class AlphaConsole : public BasicPioDevice
+class AlphaBackdoor : public BasicPioDevice
{
protected:
struct Access : public AlphaAccess
@@ -90,7 +90,7 @@ class AlphaConsole : public BasicPioDevice
SimpleDisk *disk;
/** the system console (the terminal) is accessable from the console */
- SimConsole *console;
+ Terminal *terminal;
/** a pointer to the system we are running in */
AlphaSystem *system;
@@ -99,8 +99,8 @@ class AlphaConsole : public BasicPioDevice
BaseCPU *cpu;
public:
- typedef AlphaConsoleParams Params;
- AlphaConsole(const Params *p);
+ typedef AlphaBackdoorParams Params;
+ AlphaBackdoor(const Params *p);
const Params *
params() const
@@ -123,4 +123,4 @@ class AlphaConsole : public BasicPioDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
-#endif // __ALPHA_CONSOLE_HH__
+#endif // __DEV_ALPHA_BACKDOOR_HH__
diff --git a/src/dev/alpha/tsunami.cc b/src/dev/alpha/tsunami.cc
index 5bc0de5da..b6478fe22 100644
--- a/src/dev/alpha/tsunami.cc
+++ b/src/dev/alpha/tsunami.cc
@@ -37,11 +37,11 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami_pchip.hh"
#include "dev/alpha/tsunami_io.hh"
#include "dev/alpha/tsunami.hh"
+#include "dev/terminal.hh"
#include "sim/system.hh"
using namespace std;
@@ -96,11 +96,23 @@ Tsunami::pciToDma(Addr pciAddr) const
Addr
-Tsunami::calcConfigAddr(int bus, int dev, int func)
+Tsunami::calcPciConfigAddr(int bus, int dev, int func)
{
return pchip->calcConfigAddr(bus, dev, func);
}
+Addr
+Tsunami::calcPciIOAddr(Addr addr)
+{
+ return pchip->calcIOAddr(addr);
+}
+
+Addr
+Tsunami::calcPciMemAddr(Addr addr)
+{
+ return pchip->calcMemAddr(addr);
+}
+
void
Tsunami::serialize(std::ostream &os)
{
diff --git a/src/dev/alpha/tsunami.hh b/src/dev/alpha/tsunami.hh
index 44c5d41a4..64aafe533 100644
--- a/src/dev/alpha/tsunami.hh
+++ b/src/dev/alpha/tsunami.hh
@@ -116,7 +116,17 @@ class Tsunami : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int func);
+ virtual Addr calcPciConfigAddr(int bus, int dev, int func);
+
+ /**
+ * Calculate the address for an IO location on the PCI bus.
+ */
+ virtual Addr calcPciIOAddr(Addr addr);
+
+ /**
+ * Calculate the address for a memory location on the PCI bus.
+ */
+ virtual Addr calcPciMemAddr(Addr addr);
/**
* Serialize this object to the given output stream.
diff --git a/src/dev/alpha/tsunami_cchip.cc b/src/dev/alpha/tsunami_cchip.cc
index 891fe17da..52a2aea14 100644
--- a/src/dev/alpha/tsunami_cchip.cc
+++ b/src/dev/alpha/tsunami_cchip.cc
@@ -109,8 +109,14 @@ TsunamiCChip::read(PacketPtr pkt)
panic("TSDEV_CC_MTR not implemeted\n");
break;
case TSDEV_CC_MISC:
- pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
- (pkt->req->getCpuNum() & 0x3));
+ pkt->set(((ipint << 8) & 0xF) | ((itint << 4) & 0xF) |
+ (pkt->req->contextId() & 0x3));
+ // currently, FS cannot handle MT so contextId and
+ // cpuId are effectively the same, don't know if it will
+ // matter if FS becomes MT enabled. I suspect no because
+ // we are currently able to boot up to 64 procs anyway
+ // which would render the CPUID of this register useless
+ // anyway
break;
case TSDEV_CC_AAR0:
case TSDEV_CC_AAR1:
diff --git a/src/dev/alpha/tsunami_io.cc b/src/dev/alpha/tsunami_io.cc
index 710aca48d..9c88904e3 100644
--- a/src/dev/alpha/tsunami_io.cc
+++ b/src/dev/alpha/tsunami_io.cc
@@ -42,7 +42,6 @@
#include "base/time.hh"
#include "base/trace.hh"
-#include "dev/pitreg.h"
#include "dev/rtcreg.h"
#include "dev/alpha/tsunami_cchip.hh"
#include "dev/alpha/tsunami.hh"
@@ -57,386 +56,15 @@ using namespace std;
//Should this be AlphaISA?
using namespace TheISA;
-TsunamiIO::RTC::RTC(const string &n, Tsunami* tsunami,
- const TsunamiIO::Params *p)
- : _name(n), event(tsunami, p->frequency), addr(0)
+TsunamiIO::RTC::RTC(const string &n, const TsunamiIOParams *p)
+ : MC146818(p->tsunami, n, p->time, p->year_is_bcd, p->frequency),
+ tsunami(p->tsunami)
{
- memset(clock_data, 0, sizeof(clock_data));
- stat_regA = RTCA_32768HZ | RTCA_1024HZ;
- stat_regB = RTCB_PRDC_IE |RTCB_BIN | RTCB_24HR;
-
- year = p->time.tm_year;
-
- if (p->year_is_bcd) {
- // The datasheet says that the year field can be either BCD or
- // years since 1900. Linux seems to be happy with years since
- // 1900.
- year = year % 100;
- int tens = year / 10;
- int ones = year % 10;
- year = (tens << 4) + ones;
- }
-
- // Unix is 0-11 for month, data seet says start at 1
- mon = p->time.tm_mon + 1;
- mday = p->time.tm_mday;
- hour = p->time.tm_hour;
- min = p->time.tm_min;
- sec = p->time.tm_sec;
-
- // Datasheet says 1 is sunday
- wday = p->time.tm_wday + 1;
-
- DPRINTFN("Real-time clock set to %s", asctime(&p->time));
-}
-
-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 &section)
-{
- 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() const
-{
- 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 &section)
-{
- // 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 &section)
-{
- 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() const
-{
- return "tsunami 8254 Interval timer";
}
TsunamiIO::TsunamiIO(const Params *p)
- : BasicPioDevice(p), tsunami(p->tsunami), pitimer(p->name + "pitimer"),
- rtc(p->name + ".rtc", p->tsunami, p)
+ : BasicPioDevice(p), tsunami(p->tsunami),
+ pitimer(this, p->name + "pitimer"), rtc(p->name + ".rtc", p)
{
pioSize = 0x100;
@@ -486,19 +114,19 @@ TsunamiIO::read(PacketPtr pkt)
pkt->set(0x00);
break;
case TSDEV_TMR0_DATA:
- pkt->set(pitimer.counter0.read());
+ pkt->set(pitimer.readCounter(0));
break;
case TSDEV_TMR1_DATA:
- pkt->set(pitimer.counter1.read());
+ pkt->set(pitimer.readCounter(1));
break;
case TSDEV_TMR2_DATA:
- pkt->set(pitimer.counter2.read());
+ pkt->set(pitimer.readCounter(2));
break;
case TSDEV_RTC_DATA:
- pkt->set(rtc.readData());
+ pkt->set(rtc.readData(rtcAddr));
break;
case TSDEV_CTRL_PORTB:
- if (pitimer.counter2.outputHigh())
+ if (pitimer.outputHigh(2))
pkt->set(PORTB_SPKR_HIGH);
else
pkt->set(0x00);
@@ -561,22 +189,22 @@ TsunamiIO::write(PacketPtr pkt)
mode2 = pkt->get<uint8_t>();
break;
case TSDEV_TMR0_DATA:
- pitimer.counter0.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(0, pkt->get<uint8_t>());
break;
case TSDEV_TMR1_DATA:
- pitimer.counter1.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(1, pkt->get<uint8_t>());
break;
case TSDEV_TMR2_DATA:
- pitimer.counter2.write(pkt->get<uint8_t>());
+ pitimer.writeCounter(2, 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>());
+ rtcAddr = pkt->get<uint8_t>();
break;
case TSDEV_RTC_DATA:
- rtc.writeData(pkt->get<uint8_t>());
+ rtc.writeData(rtcAddr, pkt->get<uint8_t>());
break;
case TSDEV_KBD:
case TSDEV_DMA1_CMND:
@@ -623,6 +251,7 @@ TsunamiIO::clearPIC(uint8_t bitvector)
void
TsunamiIO::serialize(ostream &os)
{
+ SERIALIZE_SCALAR(rtcAddr);
SERIALIZE_SCALAR(timerData);
SERIALIZE_SCALAR(mask1);
SERIALIZE_SCALAR(mask2);
@@ -639,6 +268,7 @@ TsunamiIO::serialize(ostream &os)
void
TsunamiIO::unserialize(Checkpoint *cp, const string &section)
{
+ UNSERIALIZE_SCALAR(rtcAddr);
UNSERIALIZE_SCALAR(timerData);
UNSERIALIZE_SCALAR(mask1);
UNSERIALIZE_SCALAR(mask2);
diff --git a/src/dev/alpha/tsunami_io.hh b/src/dev/alpha/tsunami_io.hh
index 05c4ee910..b6d63322b 100644
--- a/src/dev/alpha/tsunami_io.hh
+++ b/src/dev/alpha/tsunami_io.hh
@@ -39,6 +39,8 @@
#include "base/range.hh"
#include "dev/alpha/tsunami.hh"
+#include "dev/intel_8254_timer.hh"
+#include "dev/mc146818.hh"
#include "dev/io_device.hh"
#include "params/TsunamiIO.hh"
#include "sim/eventq.hh"
@@ -53,223 +55,19 @@ class TsunamiIO : public BasicPioDevice
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() const;
- };
-
- 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* tsunami,
- const TsunamiIOParams *params);
-
- /** 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 base The base name of the counter object.
- * @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 base The base name of the counter object.
- * @param cp The checkpoint use.
- * @param section The section name of this object
- */
- void unserialize(const std::string &base, Checkpoint *cp,
- const std::string &section);
- };
-
- /** Programmable Interval Timer (Intel 8254) */
- class PITimer
+ class RTC : public MC146818
{
- /** 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() const;
-
- 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 base The base name of the counter object.
- * @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 base The base name of the counter object.
- * @param cp The checkpoint use.
- * @param section The section name of this object
- */
- void unserialize(const std::string &base, Checkpoint *cp,
- const std::string &section);
- };
-
- 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);
+ Tsunami *tsunami;
+ RTC(const std::string &n, const TsunamiIOParams *p);
- /**
- * Serialize this object to the given output stream.
- * @param base The base name of the counter object.
- * @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 base The base name of the counter object.
- * @param cp The checkpoint use.
- * @param section The section name of this object
- */
- void unserialize(const std::string &base, Checkpoint *cp,
- const std::string &section);
+ protected:
+ void handleEvent()
+ {
+ //Actually interrupt the processor here
+ tsunami->cchip->postRTC();
+ }
};
/** Mask of the PIC1 */
@@ -294,10 +92,12 @@ class TsunamiIO : public BasicPioDevice
Tsunami *tsunami;
/** Intel 8253 Periodic Interval Timer */
- PITimer pitimer;
+ Intel8254Timer pitimer;
RTC rtc;
+ uint8_t rtcAddr;
+
/** 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.
diff --git a/src/dev/alpha/tsunami_pchip.cc b/src/dev/alpha/tsunami_pchip.cc
index 83bcf8e65..4df7d1150 100644
--- a/src/dev/alpha/tsunami_pchip.cc
+++ b/src/dev/alpha/tsunami_pchip.cc
@@ -300,6 +300,7 @@ TsunamiPChip::translatePciToDma(Addr busAddr)
// if no match was found, then return the original address
return busAddr;
}
+
Addr
TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
{
@@ -310,7 +311,17 @@ TsunamiPChip::calcConfigAddr(int bus, int dev, int func)
return TsunamiPciBus0Config | (func << 8) | (dev << 11);
}
+Addr
+TsunamiPChip::calcIOAddr(Addr addr)
+{
+ return TSUNAMI_PCI0_IO + addr;
+}
+Addr
+TsunamiPChip::calcMemAddr(Addr addr)
+{
+ return TSUNAMI_PCI0_MEMORY + addr;
+}
void
TsunamiPChip::serialize(std::ostream &os)
diff --git a/src/dev/alpha/tsunami_pchip.hh b/src/dev/alpha/tsunami_pchip.hh
index 53050565f..d31a28dbe 100644
--- a/src/dev/alpha/tsunami_pchip.hh
+++ b/src/dev/alpha/tsunami_pchip.hh
@@ -84,6 +84,8 @@ class TsunamiPChip : public BasicPioDevice
Addr translatePciToDma(Addr busAddr);
Addr calcConfigAddr(int bus, int dev, int func);
+ Addr calcIOAddr(Addr addr);
+ Addr calcMemAddr(Addr addr);
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
diff --git a/src/dev/copy_engine.cc b/src/dev/copy_engine.cc
new file mode 100644
index 000000000..3c759ac1d
--- /dev/null
+++ b/src/dev/copy_engine.cc
@@ -0,0 +1,764 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+/* @file
+ * Device model for Intel's I/O AT DMA copy engine.
+ */
+
+#include <algorithm>
+
+#include "base/cp_annotate.hh"
+#include "base/trace.hh"
+#include "dev/copy_engine.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/CopyEngine.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+
+using namespace CopyEngineReg;
+using namespace std;
+
+CopyEngine::CopyEngine(const Params *p)
+ : PciDev(p)
+{
+ // All Reg regs are initialized to 0 by default
+ regs.chanCount = p->ChanCnt;
+ regs.xferCap = findMsbSet(p->XferCap);
+ regs.attnStatus = 0;
+
+ if (regs.chanCount > 64)
+ fatal("CopyEngine interface doesn't support more than 64 DMA engines\n");
+
+ for (int x = 0; x < regs.chanCount; x++) {
+ CopyEngineChannel *ch = new CopyEngineChannel(this, x);
+ chan.push_back(ch);
+ }
+}
+
+
+CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
+ : ce(_ce), channelId(cid), busy(false), underReset(false),
+ refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
+ latAfterCompletion(ce->params()->latAfterCompletion),
+ completionDataReg(0), nextState(Idle), drainEvent(NULL),
+ fetchCompleteEvent(this), addrCompleteEvent(this),
+ readCompleteEvent(this), writeCompleteEvent(this),
+ statusCompleteEvent(this)
+
+{
+ cr.status.dma_transfer_status(3);
+ cr.descChainAddr = 0;
+ cr.completionAddr = 0;
+
+ curDmaDesc = new DmaDesc;
+ memset(curDmaDesc, 0, sizeof(DmaDesc));
+ copyBuffer = new uint8_t[ce->params()->XferCap];
+}
+
+CopyEngine::~CopyEngine()
+{
+ for (int x = 0; x < chan.size(); x++) {
+ delete chan[x];
+ }
+}
+
+CopyEngine::CopyEngineChannel::~CopyEngineChannel()
+{
+ delete curDmaDesc;
+ delete [] copyBuffer;
+ delete cePort;
+}
+
+void
+CopyEngine::init()
+{
+ PciDev::init();
+ for (int x = 0; x < chan.size(); x++)
+ chan[x]->init();
+}
+
+void
+CopyEngine::CopyEngineChannel::init()
+{
+ Port *peer;
+
+ cePort = new DmaPort(ce, ce->sys);
+ peer = ce->dmaPort->getPeer()->getOwner()->getPort("");
+ peer->setPeer(cePort);
+ cePort->setPeer(peer);
+}
+
+void
+CopyEngine::CopyEngineChannel::recvCommand()
+{
+ if (cr.command.start_dma()) {
+ assert(!busy);
+ cr.status.dma_transfer_status(0);
+ nextState = DescriptorFetch;
+ fetchAddress = cr.descChainAddr;
+ if (ce->getState() == SimObject::Running)
+ fetchDescriptor(cr.descChainAddr);
+ } else if (cr.command.append_dma()) {
+ if (!busy) {
+ nextState = AddressFetch;
+ if (ce->getState() == SimObject::Running)
+ fetchNextAddr(lastDescriptorAddr);
+ } else
+ refreshNext = true;
+ } else if (cr.command.reset_dma()) {
+ if (busy)
+ underReset = true;
+ else {
+ cr.status.dma_transfer_status(3);
+ nextState = Idle;
+ }
+ } else if (cr.command.resume_dma() || cr.command.abort_dma() ||
+ cr.command.suspend_dma())
+ panic("Resume, Abort, and Suspend are not supported\n");
+ cr.command(0);
+}
+
+Tick
+CopyEngine::read(PacketPtr pkt)
+{
+ int bar;
+ Addr daddr;
+
+ if (!getBAR(pkt->getAddr(), bar, daddr))
+ panic("Invalid PCI memory access to unmapped memory.\n");
+
+ // Only Memory register BAR is allowed
+ assert(bar == 0);
+
+ int size = pkt->getSize();
+ if (size != sizeof(uint64_t) && size != sizeof(uint32_t) &&
+ size != sizeof(uint16_t) && size != sizeof(uint8_t)) {
+ panic("Unknown size for MMIO access: %d\n", pkt->getSize());
+ }
+
+ DPRINTF(DMACopyEngine, "Read device register %#X size: %d\n", daddr, size);
+
+ pkt->allocate();
+
+ ///
+ /// Handle read of register here
+ ///
+
+ if (daddr < 0x80) {
+ switch (daddr) {
+ case GEN_CHANCOUNT:
+ assert(size == sizeof(regs.chanCount));
+ pkt->set<uint8_t>(regs.chanCount);
+ break;
+ case GEN_XFERCAP:
+ assert(size == sizeof(regs.xferCap));
+ pkt->set<uint8_t>(regs.xferCap);
+ break;
+ case GEN_INTRCTRL:
+ assert(size == sizeof(uint8_t));
+ pkt->set<uint8_t>(regs.intrctrl());
+ regs.intrctrl.master_int_enable(0);
+ break;
+ case GEN_ATTNSTATUS:
+ assert(size == sizeof(regs.attnStatus));
+ pkt->set<uint32_t>(regs.attnStatus);
+ regs.attnStatus = 0;
+ break;
+ default:
+ panic("Read request to unknown register number: %#x\n", daddr);
+ }
+ pkt->makeAtomicResponse();
+ return pioDelay;
+ }
+
+
+ // Find which channel we're accessing
+ int chanid = 0;
+ daddr -= 0x80;
+ while (daddr >= 0x80) {
+ chanid++;
+ daddr -= 0x80;
+ }
+
+ if (chanid >= regs.chanCount)
+ panic("Access to channel %d (device only configured for %d channels)",
+ chanid, regs.chanCount);
+
+ ///
+ /// Channel registers are handled here
+ ///
+ chan[chanid]->channelRead(pkt, daddr, size);
+
+ pkt->makeAtomicResponse();
+ return pioDelay;
+}
+
+void
+CopyEngine::CopyEngineChannel::channelRead(Packet *pkt, Addr daddr, int size)
+{
+ switch (daddr) {
+ case CHAN_CONTROL:
+ assert(size == sizeof(uint16_t));
+ pkt->set<uint16_t>(cr.ctrl());
+ cr.ctrl.in_use(1);
+ break;
+ case CHAN_STATUS:
+ assert(size == sizeof(uint64_t));
+ pkt->set<uint64_t>(cr.status() | ~busy);
+ break;
+ case CHAN_CHAINADDR:
+ assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+ if (size == sizeof(uint64_t))
+ pkt->set<uint64_t>(cr.descChainAddr);
+ else
+ pkt->set<uint32_t>(bits(cr.descChainAddr,0,31));
+ break;
+ case CHAN_CHAINADDR_HIGH:
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(bits(cr.descChainAddr,32,63));
+ break;
+ case CHAN_COMMAND:
+ assert(size == sizeof(uint8_t));
+ pkt->set<uint32_t>(cr.command());
+ break;
+ case CHAN_CMPLNADDR:
+ assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+ if (size == sizeof(uint64_t))
+ pkt->set<uint64_t>(cr.completionAddr);
+ else
+ pkt->set<uint32_t>(bits(cr.completionAddr,0,31));
+ break;
+ case CHAN_CMPLNADDR_HIGH:
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(bits(cr.completionAddr,32,63));
+ break;
+ case CHAN_ERROR:
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(cr.error());
+ break;
+ default:
+ panic("Read request to unknown channel register number: (%d)%#x\n",
+ channelId, daddr);
+ }
+}
+
+
+Tick
+CopyEngine::write(PacketPtr pkt)
+{
+ int bar;
+ Addr daddr;
+
+
+ if (!getBAR(pkt->getAddr(), bar, daddr))
+ panic("Invalid PCI memory access to unmapped memory.\n");
+
+ // Only Memory register BAR is allowed
+ assert(bar == 0);
+
+ int size = pkt->getSize();
+
+ ///
+ /// Handle write of register here
+ ///
+
+ if (size == sizeof(uint64_t)) {
+ uint64_t val M5_VAR_USED = pkt->get<uint64_t>();
+ DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+ } else if (size == sizeof(uint32_t)) {
+ uint32_t val M5_VAR_USED = pkt->get<uint32_t>();
+ DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+ } else if (size == sizeof(uint16_t)) {
+ uint16_t val M5_VAR_USED = pkt->get<uint16_t>();
+ DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+ } else if (size == sizeof(uint8_t)) {
+ uint8_t val M5_VAR_USED = pkt->get<uint8_t>();
+ DPRINTF(DMACopyEngine, "Wrote device register %#X value %#X\n", daddr, val);
+ } else {
+ panic("Unknown size for MMIO access: %d\n", size);
+ }
+
+ if (daddr < 0x80) {
+ switch (daddr) {
+ case GEN_CHANCOUNT:
+ case GEN_XFERCAP:
+ case GEN_ATTNSTATUS:
+ DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
+ daddr);
+ break;
+ case GEN_INTRCTRL:
+ regs.intrctrl.master_int_enable(bits(pkt->get<uint8_t>(),0,1));
+ break;
+ default:
+ panic("Read request to unknown register number: %#x\n", daddr);
+ }
+ pkt->makeAtomicResponse();
+ return pioDelay;
+ }
+
+ // Find which channel we're accessing
+ int chanid = 0;
+ daddr -= 0x80;
+ while (daddr >= 0x80) {
+ chanid++;
+ daddr -= 0x80;
+ }
+
+ if (chanid >= regs.chanCount)
+ panic("Access to channel %d (device only configured for %d channels)",
+ chanid, regs.chanCount);
+
+ ///
+ /// Channel registers are handled here
+ ///
+ chan[chanid]->channelWrite(pkt, daddr, size);
+
+ pkt->makeAtomicResponse();
+ return pioDelay;
+}
+
+void
+CopyEngine::CopyEngineChannel::channelWrite(Packet *pkt, Addr daddr, int size)
+{
+ switch (daddr) {
+ case CHAN_CONTROL:
+ assert(size == sizeof(uint16_t));
+ int old_int_disable;
+ old_int_disable = cr.ctrl.interrupt_disable();
+ cr.ctrl(pkt->get<uint16_t>());
+ if (cr.ctrl.interrupt_disable())
+ cr.ctrl.interrupt_disable(0);
+ else
+ cr.ctrl.interrupt_disable(old_int_disable);
+ break;
+ case CHAN_STATUS:
+ assert(size == sizeof(uint64_t));
+ DPRINTF(DMACopyEngine, "Warning, ignorning write to register %x\n",
+ daddr);
+ break;
+ case CHAN_CHAINADDR:
+ assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+ if (size == sizeof(uint64_t))
+ cr.descChainAddr = pkt->get<uint64_t>();
+ else
+ cr.descChainAddr = (uint64_t)pkt->get<uint32_t>() |
+ (cr.descChainAddr & ~mask(32));
+ DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
+ break;
+ case CHAN_CHAINADDR_HIGH:
+ assert(size == sizeof(uint32_t));
+ cr.descChainAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
+ (cr.descChainAddr & mask(32));
+ DPRINTF(DMACopyEngine, "Chain Address %x\n", cr.descChainAddr);
+ break;
+ case CHAN_COMMAND:
+ assert(size == sizeof(uint8_t));
+ cr.command(pkt->get<uint8_t>());
+ recvCommand();
+ break;
+ case CHAN_CMPLNADDR:
+ assert(size == sizeof(uint64_t) || size == sizeof(uint32_t));
+ if (size == sizeof(uint64_t))
+ cr.completionAddr = pkt->get<uint64_t>();
+ else
+ cr.completionAddr = pkt->get<uint32_t>() |
+ (cr.completionAddr & ~mask(32));
+ break;
+ case CHAN_CMPLNADDR_HIGH:
+ assert(size == sizeof(uint32_t));
+ cr.completionAddr = ((uint64_t)pkt->get<uint32_t>() <<32) |
+ (cr.completionAddr & mask(32));
+ break;
+ case CHAN_ERROR:
+ assert(size == sizeof(uint32_t));
+ cr.error(~pkt->get<uint32_t>() & cr.error());
+ break;
+ default:
+ panic("Read request to unknown channel register number: (%d)%#x\n",
+ channelId, daddr);
+ }
+}
+
+void
+CopyEngine::regStats()
+{
+ using namespace Stats;
+ bytesCopied
+ .init(regs.chanCount)
+ .name(name() + ".bytes_copied")
+ .desc("Number of bytes copied by each engine")
+ .flags(total)
+ ;
+ copiesProcessed
+ .init(regs.chanCount)
+ .name(name() + ".copies_processed")
+ .desc("Number of copies processed by each engine")
+ .flags(total)
+ ;
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchDescriptor(Addr address)
+{
+ anDq();
+ anBegin("FetchDescriptor");
+ DPRINTF(DMACopyEngine, "Reading descriptor from at memory location %#x(%#x)\n",
+ address, ce->platform->pciToDma(address));
+ assert(address);
+ busy = true;
+
+ DPRINTF(DMACopyEngine, "dmaAction: %#x, %d bytes, to addr %#x\n",
+ ce->platform->pciToDma(address), sizeof(DmaDesc), curDmaDesc);
+
+ cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address),
+ sizeof(DmaDesc), &fetchCompleteEvent, (uint8_t*)curDmaDesc,
+ latBeforeBegin);
+ lastDescriptorAddr = address;
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchDescComplete()
+{
+ DPRINTF(DMACopyEngine, "Read of descriptor complete\n");
+
+ if ((curDmaDesc->command & DESC_CTRL_NULL)) {
+ DPRINTF(DMACopyEngine, "Got NULL descriptor, skipping\n");
+ assert(!(curDmaDesc->command & DESC_CTRL_CP_STS));
+ if (curDmaDesc->command & DESC_CTRL_CP_STS) {
+ panic("Shouldn't be able to get here\n");
+ nextState = CompletionWrite;
+ if (inDrain()) return;
+ writeCompletionStatus();
+ } else {
+ anBegin("Idle");
+ anWait();
+ busy = false;
+ nextState = Idle;
+ inDrain();
+ }
+ return;
+ }
+
+ if (curDmaDesc->command & ~DESC_CTRL_CP_STS)
+ panic("Descriptor has flag other that completion status set\n");
+
+ nextState = DMARead;
+ if (inDrain()) return;
+ readCopyBytes();
+}
+
+void
+CopyEngine::CopyEngineChannel::readCopyBytes()
+{
+ anBegin("ReadCopyBytes");
+ DPRINTF(DMACopyEngine, "Reading %d bytes from buffer to memory location %#x(%#x)\n",
+ curDmaDesc->len, curDmaDesc->dest,
+ ce->platform->pciToDma(curDmaDesc->src));
+ cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(curDmaDesc->src),
+ curDmaDesc->len, &readCompleteEvent, copyBuffer, 0);
+}
+
+void
+CopyEngine::CopyEngineChannel::readCopyBytesComplete()
+{
+ DPRINTF(DMACopyEngine, "Read of bytes to copy complete\n");
+
+ nextState = DMAWrite;
+ if (inDrain()) return;
+ writeCopyBytes();
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCopyBytes()
+{
+ anBegin("WriteCopyBytes");
+ DPRINTF(DMACopyEngine, "Writing %d bytes from buffer to memory location %#x(%#x)\n",
+ curDmaDesc->len, curDmaDesc->dest,
+ ce->platform->pciToDma(curDmaDesc->dest));
+
+ cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(curDmaDesc->dest),
+ curDmaDesc->len, &writeCompleteEvent, copyBuffer, 0);
+
+ ce->bytesCopied[channelId] += curDmaDesc->len;
+ ce->copiesProcessed[channelId]++;
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCopyBytesComplete()
+{
+ DPRINTF(DMACopyEngine, "Write of bytes to copy complete user1: %#x\n",
+ curDmaDesc->user1);
+
+ cr.status.compl_desc_addr(lastDescriptorAddr >> 6);
+ completionDataReg = cr.status() | 1;
+
+ anQ("DMAUsedDescQ", channelId, 1);
+ anQ("AppRecvQ", curDmaDesc->user1, curDmaDesc->len);
+ if (curDmaDesc->command & DESC_CTRL_CP_STS) {
+ nextState = CompletionWrite;
+ if (inDrain()) return;
+ writeCompletionStatus();
+ return;
+ }
+
+ continueProcessing();
+}
+
+void
+CopyEngine::CopyEngineChannel::continueProcessing()
+{
+ busy = false;
+
+ if (underReset) {
+ anBegin("Reset");
+ anWait();
+ underReset = false;
+ refreshNext = false;
+ busy = false;
+ nextState = Idle;
+ return;
+ }
+
+ if (curDmaDesc->next) {
+ nextState = DescriptorFetch;
+ fetchAddress = curDmaDesc->next;
+ if (inDrain()) return;
+ fetchDescriptor(curDmaDesc->next);
+ } else if (refreshNext) {
+ nextState = AddressFetch;
+ refreshNext = false;
+ if (inDrain()) return;
+ fetchNextAddr(lastDescriptorAddr);
+ } else {
+ inDrain();
+ nextState = Idle;
+ anWait();
+ anBegin("Idle");
+ }
+}
+
+void
+CopyEngine::CopyEngineChannel::writeCompletionStatus()
+{
+ anBegin("WriteCompletionStatus");
+ DPRINTF(DMACopyEngine, "Writing completion status %#x to address %#x(%#x)\n",
+ completionDataReg, cr.completionAddr,
+ ce->platform->pciToDma(cr.completionAddr));
+
+ cePort->dmaAction(MemCmd::WriteReq, ce->platform->pciToDma(cr.completionAddr),
+ sizeof(completionDataReg), &statusCompleteEvent,
+ (uint8_t*)&completionDataReg, latAfterCompletion);
+}
+
+void
+CopyEngine::CopyEngineChannel::writeStatusComplete()
+{
+ DPRINTF(DMACopyEngine, "Writing completion status complete\n");
+ continueProcessing();
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchNextAddr(Addr address)
+{
+ anBegin("FetchNextAddr");
+ DPRINTF(DMACopyEngine, "Fetching next address...\n");
+ busy = true;
+ cePort->dmaAction(MemCmd::ReadReq, ce->platform->pciToDma(address +
+ offsetof(DmaDesc, next)), sizeof(Addr), &addrCompleteEvent,
+ (uint8_t*)curDmaDesc + offsetof(DmaDesc, next), 0);
+}
+
+void
+CopyEngine::CopyEngineChannel::fetchAddrComplete()
+{
+ DPRINTF(DMACopyEngine, "Fetching next address complete: %#x\n",
+ curDmaDesc->next);
+ if (!curDmaDesc->next) {
+ DPRINTF(DMACopyEngine, "Got NULL descriptor, nothing more to do\n");
+ busy = false;
+ nextState = Idle;
+ anWait();
+ anBegin("Idle");
+ inDrain();
+ return;
+ }
+ nextState = DescriptorFetch;
+ fetchAddress = curDmaDesc->next;
+ if (inDrain()) return;
+ fetchDescriptor(curDmaDesc->next);
+}
+
+bool
+CopyEngine::CopyEngineChannel::inDrain()
+{
+ if (ce->getState() == SimObject::Draining) {
+ DPRINTF(DMACopyEngine, "processing drain\n");
+ assert(drainEvent);
+ drainEvent->process();
+ drainEvent = NULL;
+ }
+
+ return ce->getState() != SimObject::Running;
+}
+
+unsigned int
+CopyEngine::CopyEngineChannel::drain(Event *de)
+{
+ if (nextState == Idle || ce->getState() != SimObject::Running)
+ return 0;
+ unsigned int count = 1;
+ count += cePort->drain(de);
+
+ DPRINTF(DMACopyEngine, "unable to drain, returning %d\n", count);
+ drainEvent = de;
+ return count;
+}
+
+unsigned int
+CopyEngine::drain(Event *de)
+{
+ unsigned int count;
+ count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de);
+ for (int x = 0;x < chan.size(); x++)
+ count += chan[x]->drain(de);
+
+ if (count)
+ changeState(Draining);
+ else
+ changeState(Drained);
+
+ DPRINTF(DMACopyEngine, "call to CopyEngine::drain() returning %d\n", count);
+ return count;
+}
+
+void
+CopyEngine::serialize(std::ostream &os)
+{
+ PciDev::serialize(os);
+ regs.serialize(os);
+ for (int x =0; x < chan.size(); x++) {
+ nameOut(os, csprintf("%s.channel%d", name(), x));
+ chan[x]->serialize(os);
+ }
+}
+
+void
+CopyEngine::unserialize(Checkpoint *cp, const std::string &section)
+{
+ PciDev::unserialize(cp, section);
+ regs.unserialize(cp, section);
+ for (int x = 0; x < chan.size(); x++)
+ chan[x]->unserialize(cp, csprintf("%s.channel%d", section, x));
+}
+
+void
+CopyEngine::CopyEngineChannel::serialize(std::ostream &os)
+{
+ SERIALIZE_SCALAR(channelId);
+ SERIALIZE_SCALAR(busy);
+ SERIALIZE_SCALAR(underReset);
+ SERIALIZE_SCALAR(refreshNext);
+ SERIALIZE_SCALAR(lastDescriptorAddr);
+ SERIALIZE_SCALAR(completionDataReg);
+ SERIALIZE_SCALAR(fetchAddress);
+ int nextState = this->nextState;
+ SERIALIZE_SCALAR(nextState);
+ arrayParamOut(os, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
+ SERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
+ cr.serialize(os);
+
+}
+void
+CopyEngine::CopyEngineChannel::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_SCALAR(channelId);
+ UNSERIALIZE_SCALAR(busy);
+ UNSERIALIZE_SCALAR(underReset);
+ UNSERIALIZE_SCALAR(refreshNext);
+ UNSERIALIZE_SCALAR(lastDescriptorAddr);
+ UNSERIALIZE_SCALAR(completionDataReg);
+ UNSERIALIZE_SCALAR(fetchAddress);
+ int nextState;
+ UNSERIALIZE_SCALAR(nextState);
+ this->nextState = (ChannelState)nextState;
+ arrayParamIn(cp, section, "curDmaDesc", (uint8_t*)curDmaDesc, sizeof(DmaDesc));
+ UNSERIALIZE_ARRAY(copyBuffer, ce->params()->XferCap);
+ cr.unserialize(cp, section);
+
+}
+
+void
+CopyEngine::CopyEngineChannel::restartStateMachine()
+{
+ switch(nextState) {
+ case AddressFetch:
+ fetchNextAddr(lastDescriptorAddr);
+ break;
+ case DescriptorFetch:
+ fetchDescriptor(fetchAddress);
+ break;
+ case DMARead:
+ readCopyBytes();
+ break;
+ case DMAWrite:
+ writeCopyBytes();
+ break;
+ case CompletionWrite:
+ writeCompletionStatus();
+ break;
+ case Idle:
+ break;
+ default:
+ panic("Unknown state for CopyEngineChannel\n");
+ }
+}
+
+void
+CopyEngine::resume()
+{
+ SimObject::resume();
+ for (int x = 0;x < chan.size(); x++)
+ chan[x]->resume();
+}
+
+
+void
+CopyEngine::CopyEngineChannel::resume()
+{
+ DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
+ restartStateMachine();
+}
+
+CopyEngine *
+CopyEngineParams::create()
+{
+ return new CopyEngine(this);
+}
diff --git a/src/dev/copy_engine.hh b/src/dev/copy_engine.hh
new file mode 100644
index 000000000..dfe469588
--- /dev/null
+++ b/src/dev/copy_engine.hh
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+/* @file
+ * Device model for Intel's I/O Acceleration Technology (I/OAT).
+ * A DMA asyncronous copy engine
+ */
+
+#ifndef __DEV_COPY_ENGINE_HH__
+#define __DEV_COPY_ENGINE_HH__
+
+#include <vector>
+
+#include "base/statistics.hh"
+#include "dev/copy_engine_defs.hh"
+#include "dev/pcidev.hh"
+#include "params/CopyEngine.hh"
+#include "sim/eventq.hh"
+
+class CopyEngine : public PciDev
+{
+ class CopyEngineChannel
+ {
+ private:
+ DmaPort *cePort;
+ CopyEngine *ce;
+ CopyEngineReg::ChanRegs cr;
+ int channelId;
+ CopyEngineReg::DmaDesc *curDmaDesc;
+ uint8_t *copyBuffer;
+
+ bool busy;
+ bool underReset;
+ bool refreshNext;
+ Addr lastDescriptorAddr;
+ Addr fetchAddress;
+
+ Tick latBeforeBegin;
+ Tick latAfterCompletion;
+
+ uint64_t completionDataReg;
+
+ enum ChannelState {
+ Idle,
+ AddressFetch,
+ DescriptorFetch,
+ DMARead,
+ DMAWrite,
+ CompletionWrite
+ };
+
+ ChannelState nextState;
+
+ Event *drainEvent;
+ public:
+ CopyEngineChannel(CopyEngine *_ce, int cid);
+ virtual ~CopyEngineChannel();
+ void init();
+
+ std::string name() { assert(ce); return ce->name() + csprintf("-chan%d", channelId); }
+ virtual void addressRanges(AddrRangeList &range_list) { range_list.clear(); }
+ virtual Tick read(PacketPtr pkt)
+ { panic("CopyEngineChannel has no I/O access\n");}
+ virtual Tick write(PacketPtr pkt)
+ { panic("CopyEngineChannel has no I/O access\n"); }
+
+ void channelRead(PacketPtr pkt, Addr daddr, int size);
+ void channelWrite(PacketPtr pkt, Addr daddr, int size);
+
+ unsigned int drain(Event *de);
+ void resume();
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+ private:
+ void fetchDescriptor(Addr address);
+ void fetchDescComplete();
+ EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchDescComplete>
+ fetchCompleteEvent;
+
+ void fetchNextAddr(Addr address);
+ void fetchAddrComplete();
+ EventWrapper<CopyEngineChannel, &CopyEngineChannel::fetchAddrComplete>
+ addrCompleteEvent;
+
+ void readCopyBytes();
+ void readCopyBytesComplete();
+ EventWrapper<CopyEngineChannel, &CopyEngineChannel::readCopyBytesComplete>
+ readCompleteEvent;
+
+ void writeCopyBytes();
+ void writeCopyBytesComplete();
+ EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeCopyBytesComplete>
+ writeCompleteEvent;
+
+ void writeCompletionStatus();
+ void writeStatusComplete();
+ EventWrapper <CopyEngineChannel, &CopyEngineChannel::writeStatusComplete>
+ statusCompleteEvent;
+
+
+ void continueProcessing();
+ void recvCommand();
+ bool inDrain();
+ void restartStateMachine();
+ inline void anBegin(const char *s)
+ {
+ CPA::cpa()->hwBegin(CPA::FL_NONE, ce->sys,
+ channelId, "CopyEngine", s);
+ }
+
+ inline void anWait()
+ {
+ CPA::cpa()->hwWe(CPA::FL_NONE, ce->sys,
+ channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+ }
+
+ inline void anDq()
+ {
+ CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
+ channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+ }
+
+ inline void anPq()
+ {
+ CPA::cpa()->hwDq(CPA::FL_NONE, ce->sys,
+ channelId, "CopyEngine", "DMAUnusedDescQ", channelId);
+ }
+
+ inline void anQ(const char * s, uint64_t id, int size = 1)
+ {
+ CPA::cpa()->hwQ(CPA::FL_NONE, ce->sys, channelId,
+ "CopyEngine", s, id, NULL, size);
+ }
+
+ };
+
+ private:
+
+ Stats::Vector bytesCopied;
+ Stats::Vector copiesProcessed;
+
+ // device registers
+ CopyEngineReg::Regs regs;
+
+ // Array of channels each one with regs/dma port/etc
+ std::vector<CopyEngineChannel*> chan;
+
+ public:
+ typedef CopyEngineParams Params;
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+ CopyEngine(const Params *params);
+ ~CopyEngine();
+
+ void regStats();
+ void init();
+
+ virtual Tick read(PacketPtr pkt);
+ virtual Tick write(PacketPtr pkt);
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+ virtual unsigned int drain(Event *de);
+ virtual void resume();
+};
+
+#endif //__DEV_COPY_ENGINE_HH__
+
diff --git a/src/dev/copy_engine_defs.hh b/src/dev/copy_engine_defs.hh
new file mode 100644
index 000000000..16bf57d58
--- /dev/null
+++ b/src/dev/copy_engine_defs.hh
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+/* @file
+ * Register and structure descriptions for Intel's I/O AT DMA Engine
+ */
+#include "base/bitfield.hh"
+#include "sim/serialize.hh"
+
+namespace CopyEngineReg {
+
+
+// General Channel independant registers, 128 bytes starting at 0x00
+const uint32_t GEN_CHANCOUNT = 0x00;
+const uint32_t GEN_XFERCAP = 0x01;
+const uint32_t GEN_INTRCTRL = 0x03;
+const uint32_t GEN_ATTNSTATUS = 0x04;
+
+
+// Channel specific registers, each block is 128 bytes, starting at 0x80
+const uint32_t CHAN_CONTROL = 0x00;
+const uint32_t CHAN_STATUS = 0x04;
+const uint32_t CHAN_CHAINADDR = 0x0C;
+const uint32_t CHAN_CHAINADDR_LOW = 0x0C;
+const uint32_t CHAN_CHAINADDR_HIGH = 0x10;
+const uint32_t CHAN_COMMAND = 0x14;
+const uint32_t CHAN_CMPLNADDR = 0x18;
+const uint32_t CHAN_CMPLNADDR_LOW = 0x18;
+const uint32_t CHAN_CMPLNADDR_HIGH = 0x1C;
+const uint32_t CHAN_ERROR = 0x28;
+
+
+const uint32_t DESC_CTRL_INT_GEN = 0x00000001;
+const uint32_t DESC_CTRL_SRC_SN = 0x00000002;
+const uint32_t DESC_CTRL_DST_SN = 0x00000004;
+const uint32_t DESC_CTRL_CP_STS = 0x00000008;
+const uint32_t DESC_CTRL_FRAME = 0x00000010;
+const uint32_t DESC_CTRL_NULL = 0x00000020;
+
+struct DmaDesc {
+ uint32_t len;
+ uint32_t command;
+ Addr src;
+ Addr dest;
+ Addr next;
+ uint64_t reserved1;
+ uint64_t reserved2;
+ uint64_t user1;
+ uint64_t user2;
+};
+
+#define ADD_FIELD8(NAME, OFFSET, BITS) \
+ inline uint8_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint8_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD16(NAME, OFFSET, BITS) \
+ inline uint16_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint16_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD32(NAME, OFFSET, BITS) \
+ inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD64(NAME, OFFSET, BITS) \
+ inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+ inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+template<class T>
+struct Reg {
+ T _data;
+ T operator()() { return _data; }
+ const Reg<T> &operator=(T d) { _data = d; return *this;}
+ bool operator==(T d) { return d == _data; }
+ void operator()(T d) { _data = d; }
+ Reg() { _data = 0; }
+ void serialize(std::ostream &os)
+ {
+ SERIALIZE_SCALAR(_data);
+ }
+ void unserialize(Checkpoint *cp, const std::string &section)
+ {
+ UNSERIALIZE_SCALAR(_data);
+ }
+};
+
+
+struct Regs {
+ uint8_t chanCount;
+ uint8_t xferCap;
+
+ struct INTRCTRL : public Reg<uint8_t> { // 0x03
+ using Reg<uint8_t>::operator =;
+ ADD_FIELD8(master_int_enable,0,1);
+ ADD_FIELD8(interrupt_status,1,1);
+ ADD_FIELD8(interrupt,2,1);
+ };
+ INTRCTRL intrctrl;
+
+ uint32_t attnStatus; // Read clears
+
+ void serialize(std::ostream &os)
+ {
+ SERIALIZE_SCALAR(chanCount);
+ SERIALIZE_SCALAR(xferCap);
+ paramOut(os, "intrctrl", intrctrl._data);
+ SERIALIZE_SCALAR(attnStatus);
+ }
+
+ void unserialize(Checkpoint *cp, const std::string &section)
+ {
+ UNSERIALIZE_SCALAR(chanCount);
+ UNSERIALIZE_SCALAR(xferCap);
+ paramIn(cp, section, "intrctrl", intrctrl._data);
+ UNSERIALIZE_SCALAR(attnStatus);
+ }
+
+};
+
+struct ChanRegs {
+ struct CHANCTRL : public Reg<uint16_t> { // channelX + 0x00
+ using Reg<uint16_t>::operator =;
+ ADD_FIELD16(interrupt_disable,0,1);
+ ADD_FIELD16(error_completion_enable, 2,1);
+ ADD_FIELD16(any_error_abort_enable,3,1);
+ ADD_FIELD16(error_int_enable,4,1);
+ ADD_FIELD16(desc_addr_snoop_control,5,1);
+ ADD_FIELD16(in_use, 8,1);
+ };
+ CHANCTRL ctrl;
+
+ struct CHANSTS : public Reg<uint64_t> { // channelX + 0x04
+ ADD_FIELD64(dma_transfer_status, 0, 3);
+ ADD_FIELD64(unaffiliated_error, 3, 1);
+ ADD_FIELD64(soft_error, 4, 1);
+ ADD_FIELD64(compl_desc_addr, 6, 58);
+ };
+ CHANSTS status;
+
+ uint64_t descChainAddr;
+
+ struct CHANCMD : public Reg<uint8_t> { // channelX + 0x14
+ ADD_FIELD8(start_dma,0,1);
+ ADD_FIELD8(append_dma,1,1);
+ ADD_FIELD8(suspend_dma,2,1);
+ ADD_FIELD8(abort_dma,3,1);
+ ADD_FIELD8(resume_dma,4,1);
+ ADD_FIELD8(reset_dma,5,1);
+ };
+ CHANCMD command;
+
+ uint64_t completionAddr;
+
+ struct CHANERR : public Reg<uint32_t> { // channel X + 0x28
+ ADD_FIELD32(source_addr_error,0,1);
+ ADD_FIELD32(dest_addr_error,1,1);
+ ADD_FIELD32(ndesc_addr_error,2,1);
+ ADD_FIELD32(desc_error,3,1);
+ ADD_FIELD32(chain_addr_error,4,1);
+ ADD_FIELD32(chain_cmd_error,5,1);
+ ADD_FIELD32(chipset_parity_error,6,1);
+ ADD_FIELD32(dma_parity_error,7,1);
+ ADD_FIELD32(read_data_error,8,1);
+ ADD_FIELD32(write_data_error,9,1);
+ ADD_FIELD32(desc_control_error,10,1);
+ ADD_FIELD32(desc_len_error,11,1);
+ ADD_FIELD32(completion_addr_error,12,1);
+ ADD_FIELD32(interrupt_config_error,13,1);
+ ADD_FIELD32(soft_error,14,1);
+ ADD_FIELD32(unaffiliated_error,15,1);
+ };
+ CHANERR error;
+
+ void serialize(std::ostream &os)
+ {
+ paramOut(os, "ctrl", ctrl._data);
+ paramOut(os, "status", status._data);
+ SERIALIZE_SCALAR(descChainAddr);
+ paramOut(os, "command", command._data);
+ SERIALIZE_SCALAR(completionAddr);
+ paramOut(os, "error", error._data);
+ }
+
+ void unserialize(Checkpoint *cp, const std::string &section)
+ {
+ paramIn(cp, section, "ctrl", ctrl._data);
+ paramIn(cp, section, "status", status._data);
+ UNSERIALIZE_SCALAR(descChainAddr);
+ paramIn(cp, section, "command", command._data);
+ UNSERIALIZE_SCALAR(completionAddr);
+ paramIn(cp, section, "error", error._data);
+ }
+
+
+};
+
+} //namespace CopyEngineReg
+
+
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
index 2316bfed9..063a594e7 100644
--- a/src/dev/etherbus.cc
+++ b/src/dev/etherbus.cc
@@ -49,7 +49,7 @@ using namespace std;
EtherBus::EtherBus(const Params *p)
: EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback),
- event(&mainEventQueue, this), sender(0), dump(p->dump)
+ event(this), sender(0), dump(p->dump)
{
}
@@ -99,7 +99,7 @@ EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
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);
+ schedule(event, curTick + delay);
return true;
}
diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh
index 624ceb81a..6408f7f1f 100644
--- a/src/dev/etherbus.hh
+++ b/src/dev/etherbus.hh
@@ -59,8 +59,7 @@ class EtherBus : public EtherObject
EtherBus *bus;
public:
- DoneEvent(EventQueue *q, EtherBus *b)
- : Event(q), bus(b) {}
+ DoneEvent(EtherBus *b) : bus(b) {}
virtual void process() { bus->txDone(); }
virtual const char *description() const
{ return "ethernet bus completion"; }
diff --git a/src/dev/etherdevice.cc b/src/dev/etherdevice.cc
new file mode 100644
index 000000000..5341c02c4
--- /dev/null
+++ b/src/dev/etherdevice.cc
@@ -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.
+ *
+ * Authors: Nathan Binkert
+ * Lisa Hsu
+ */
+
+#include "dev/etherdevice.hh"
+#include "sim/stats.hh"
+
+void
+EtherDevice::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;
+}
diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh
index a0df0d741..5d86275b4 100644
--- a/src/dev/etherdevice.hh
+++ b/src/dev/etherdevice.hh
@@ -36,6 +36,7 @@
#ifndef __DEV_ETHERDEVICE_HH__
#define __DEV_ETHERDEVICE_HH__
+#include "base/statistics.hh"
#include "dev/pcidev.hh"
#include "params/EtherDevice.hh"
#include "sim/sim_object.hh"
@@ -64,6 +65,59 @@ class EtherDevice : public PciDev
/** Additional function to return the Port of a memory object. */
virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
+ public:
+ void regStats();
+
+ protected:
+ 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;
};
#endif //__DEV_ETHERDEVICE_HH__
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
index 471093521..c41ce4e1f 100644
--- a/src/dev/etherdump.cc
+++ b/src/dev/etherdump.cc
@@ -45,75 +45,62 @@
using std::string;
EtherDump::EtherDump(const Params *p)
- : SimObject(p), stream(simout.resolve(p->file).c_str()),
+ : SimObject(p), stream(simout.create(p->file, true)),
maxlen(p->maxlen)
{
}
-#define DLT_EN10MB 1 // Ethernet (10Mb)
-#define TCPDUMP_MAGIC 0xa1b2c3d4
-#define PCAP_VERSION_MAJOR 2
-#define PCAP_VERSION_MINOR 4
+#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_*)
+ 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)
+ 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.thiszone = 0;
hdr.snaplen = 1500;
hdr.sigfigs = 0;
hdr.linktype = DLT_EN10MB;
- stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
+ 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();
+ stream->flush();
}
void
EtherDump::dumpPacket(EthPacketPtr &packet)
{
pcap_pkthdr pkthdr;
- pkthdr.seconds = curtime + (curTick / Clock::Int::s);
+ pkthdr.seconds = 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();
+ stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+ stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
+ stream->flush();
}
EtherDump *
diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh
index 1027ce4d0..18a5d2c44 100644
--- a/src/dev/etherdump.hh
+++ b/src/dev/etherdump.hh
@@ -46,13 +46,11 @@
class EtherDump : public SimObject
{
private:
- std::ofstream stream;
+ std::ostream *stream;
const int maxlen;
void dumpPacket(EthPacketPtr &packet);
void init();
- Tick curtime;
-
public:
typedef EtherDumpParams Params;
EtherDump(const Params *p);
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
index b1266000b..f3f38fc20 100644
--- a/src/dev/etherlink.cc
+++ b/src/dev/etherlink.cc
@@ -135,7 +135,7 @@ class LinkDelayEvent : public Event
public:
// non-scheduling version for createForUnserialize()
LinkDelayEvent();
- LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when);
+ LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt);
void process();
@@ -153,7 +153,8 @@ EtherLink::Link::txDone()
if (linkDelay > 0) {
DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
- new LinkDelayEvent(this, packet, curTick + linkDelay);
+ Event *event = new LinkDelayEvent(this, packet);
+ parent->schedule(event, curTick + linkDelay);
} else {
txComplete(packet);
}
@@ -182,7 +183,7 @@ EtherLink::Link::transmit(EthPacketPtr pkt)
DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
delay, ticksPerByte);
- doneEvent.schedule(curTick + delay);
+ parent->schedule(doneEvent, curTick + delay);
return true;
}
@@ -220,23 +221,22 @@ EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
if (event_scheduled) {
Tick event_time;
paramIn(cp, section, base + ".event_time", event_time);
- doneEvent.schedule(event_time);
+ parent->schedule(doneEvent, event_time);
}
}
LinkDelayEvent::LinkDelayEvent()
- : Event(&mainEventQueue), link(NULL)
+ : link(NULL)
{
setFlags(AutoSerialize);
setFlags(AutoDelete);
}
-LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when)
- : Event(&mainEventQueue), link(l), packet(p)
+LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p)
+ : link(l), packet(p)
{
setFlags(AutoSerialize);
setFlags(AutoDelete);
- schedule(when);
}
void
diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc
index 5c552b4bd..2c8343eb0 100644
--- a/src/dev/etherpkt.cc
+++ b/src/dev/etherpkt.cc
@@ -40,7 +40,6 @@ void
EthPacketData::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".length", length);
- paramOut(os, base + ".slack", slack);
arrayParamOut(os, base + ".data", data, length);
}
@@ -49,7 +48,6 @@ EthPacketData::unserialize(const string &base, Checkpoint *cp,
const string &section)
{
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
index db2e0d6b5..623895ba8 100644
--- a/src/dev/etherpkt.hh
+++ b/src/dev/etherpkt.hh
@@ -60,24 +60,17 @@ class EthPacketData : public RefCounted
*/
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)
+ EthPacketData()
+ : data(NULL), length(0)
{ }
explicit EthPacketData(size_t size)
- : data(new uint8_t[size]), length(0), slack(0)
+ : data(new uint8_t[size]), length(0)
{ }
- EthPacketData(std::auto_ptr<uint8_t> d, int l, int s = 0)
- : data(d.release()), length(l), slack(s)
+ EthPacketData(std::auto_ptr<uint8_t> d, int l)
+ : data(d.release()), length(l)
{ }
~EthPacketData() { if (data) delete [] data; }
diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc
index 81b84d179..85d6370be 100644
--- a/src/dev/ethertap.cc
+++ b/src/dev/ethertap.cc
@@ -130,6 +130,9 @@ EtherTap::EtherTap(const Params *p)
: EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump),
interface(NULL), txEvent(this)
{
+ if (ListenSocket::allDisabled())
+ fatal("All listeners are disabled! EtherTap can't work!");
+
buffer = new char[buflen];
listener = new TapListener(this, p->port);
listener->listen();
@@ -179,8 +182,12 @@ EtherTap::recvPacket(EthPacketPtr packet)
DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
DDUMP(EthernetData, packet->data, packet->length);
uint32_t len = htonl(packet->length);
- write(socket, &len, sizeof(len));
- write(socket, packet->data, packet->length);
+ ssize_t ret = write(socket, &len, sizeof(len));
+ if (ret != sizeof(len))
+ return false;
+ ret = write(socket, packet->data, packet->length);
+ if (ret != packet->length)
+ return false;
interface->recvDone();
@@ -239,7 +246,7 @@ EtherTap::process(int revent)
DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
packetBuffer.push(packet);
if (!txEvent.scheduled())
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
} else if (dump) {
dump->dump(packet);
}
@@ -262,7 +269,7 @@ EtherTap::retransmit()
}
if (!packetBuffer.empty() && !txEvent.scheduled())
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
}
EtherInt*
diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh
index be3d73a24..ac287cecb 100644
--- a/src/dev/ethertap.hh
+++ b/src/dev/ethertap.hh
@@ -90,8 +90,7 @@ class EtherTap : public EtherObject
EtherTap *tap;
public:
- TxEvent(EtherTap *_tap)
- : Event(&mainEventQueue), tap(_tap) {}
+ TxEvent(EtherTap *_tap) : tap(_tap) {}
void process() { tap->retransmit(); }
virtual const char *description() const
{ return "EtherTap retransmit"; }
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
index 3f56ec53a..274f60e39 100644
--- a/src/dev/i8254xGBe.cc
+++ b/src/dev/i8254xGBe.cc
@@ -57,10 +57,15 @@ using namespace Net;
IGbE::IGbE(const Params *p)
: EtherDevice(p), etherInt(NULL), drainEvent(NULL), useFlowControl(p->use_flow_control),
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
- txTick(false), txFifoTick(false), rxDmaPacket(false), rdtrEvent(this), radvEvent(this),
+ txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
+ fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
+ fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay),
+ rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),
+ rdtrEvent(this), radvEvent(this),
tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
- txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size), clock(p->clock)
+ txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
+ clock(p->clock), lastInterrupt(0)
{
etherInt = new IGbEInt(name() + ".int", this);
@@ -80,6 +85,9 @@ IGbE::IGbE(const Params *p)
regs.rxdctl.gran(1);
regs.rxdctl.wthresh(1);
regs.fcrth(1);
+ regs.tdwba = 0;
+ regs.rlpml = 0;
+ regs.sw_fw_sync = 0;
regs.pba.rxa(0x30);
regs.pba.txa(0x10);
@@ -105,10 +113,20 @@ IGbE::IGbE(const Params *p)
// Magic happy checksum value
flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
+ // Store the MAC address as queue ID
+ macAddr = p->hardware_address;
+
rxFifo.clear();
txFifo.clear();
}
+void
+IGbE::init()
+{
+ cpa = CPA::cpa();
+ PciDev::init();
+}
+
EtherInt*
IGbE::getEthPort(const std::string &if_name, int idx)
{
@@ -192,6 +210,11 @@ IGbE::read(PacketPtr pkt)
regs.imr &= ~regs.iam;
chkInterrupt();
break;
+ case REG_EICR:
+ // This is only useful for MSI, but the driver reads it every time
+ // Just don't do anything
+ pkt->set<uint32_t>(0);
+ break;
case REG_ITR:
pkt->set<uint32_t>(regs.itr());
break;
@@ -226,6 +249,9 @@ IGbE::read(PacketPtr pkt)
case REG_RDLEN:
pkt->set<uint32_t>(regs.rdlen());
break;
+ case REG_SRRCTL:
+ pkt->set<uint32_t>(regs.srrctl());
+ break;
case REG_RDH:
pkt->set<uint32_t>(regs.rdh());
break;
@@ -241,6 +267,9 @@ IGbE::read(PacketPtr pkt)
regs.rdtr.fpd(0);
}
break;
+ case REG_RXDCTL:
+ pkt->set<uint32_t>(regs.rxdctl());
+ break;
case REG_RADV:
pkt->set<uint32_t>(regs.radv());
break;
@@ -256,6 +285,9 @@ IGbE::read(PacketPtr pkt)
case REG_TDH:
pkt->set<uint32_t>(regs.tdh());
break;
+ case REG_TXDCA_CTL:
+ pkt->set<uint32_t>(regs.txdca_ctl());
+ break;
case REG_TDT:
pkt->set<uint32_t>(regs.tdt());
break;
@@ -268,12 +300,34 @@ IGbE::read(PacketPtr pkt)
case REG_TADV:
pkt->set<uint32_t>(regs.tadv());
break;
+ case REG_TDWBAL:
+ pkt->set<uint32_t>(regs.tdwba & mask(32));
+ break;
+ case REG_TDWBAH:
+ pkt->set<uint32_t>(regs.tdwba >> 32);
+ break;
case REG_RXCSUM:
pkt->set<uint32_t>(regs.rxcsum());
break;
+ case REG_RLPML:
+ pkt->set<uint32_t>(regs.rlpml);
+ break;
+ case REG_RFCTL:
+ pkt->set<uint32_t>(regs.rfctl());
+ break;
case REG_MANC:
pkt->set<uint32_t>(regs.manc());
break;
+ case REG_SWSM:
+ pkt->set<uint32_t>(regs.swsm());
+ regs.swsm.smbi(1);
+ break;
+ case REG_FWSM:
+ pkt->set<uint32_t>(regs.fwsm());
+ break;
+ case REG_SWFWSYNC:
+ pkt->set<uint32_t>(regs.sw_fw_sync);
+ break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@@ -380,6 +434,14 @@ IGbE::write(PacketPtr pkt)
break;
case REG_EERD:
regs.eerd = val;
+ if (regs.eerd.start()) {
+ regs.eerd.done(1);
+ assert(regs.eerd.addr() < EEPROM_SIZE);
+ regs.eerd.data(flash[regs.eerd.addr()]);
+ regs.eerd.start(0);
+ DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
+ regs.eerd.addr(), regs.eerd.data());
+ }
break;
case REG_MDIC:
regs.mdic = val;
@@ -394,10 +456,10 @@ IGbE::write(PacketPtr pkt)
regs.mdic.data(0x796D); // link up
break;
case PHY_PID:
- regs.mdic.data(0x02A8);
+ regs.mdic.data(params()->phy_pid);
break;
case PHY_EPID:
- regs.mdic.data(0x0380);
+ regs.mdic.data(params()->phy_epid);
break;
case PHY_GSTATUS:
regs.mdic.data(0x7C00);
@@ -480,6 +542,9 @@ IGbE::write(PacketPtr pkt)
case REG_TIPG:
; // We don't care, so don't store anything
break;
+ case REG_IVAR0:
+ warn("Writing to IVAR0, ignoring...\n");
+ break;
case REG_FCRTL:
regs.fcrtl = val;
break;
@@ -498,6 +563,9 @@ IGbE::write(PacketPtr pkt)
regs.rdlen = val & ~mask(7);
rxDescCache.areaChanged();
break;
+ case REG_SRRCTL:
+ regs.srrctl = val;
+ break;
case REG_RDH:
regs.rdh = val;
rxDescCache.areaChanged();
@@ -518,6 +586,9 @@ IGbE::write(PacketPtr pkt)
case REG_RADV:
regs.radv = val;
break;
+ case REG_RXDCTL:
+ regs.rxdctl = val;
+ break;
case REG_TDBAL:
regs.tdba.tdbal( val & ~mask(4));
txDescCache.areaChanged();
@@ -534,6 +605,11 @@ IGbE::write(PacketPtr pkt)
regs.tdh = val;
txDescCache.areaChanged();
break;
+ case REG_TXDCA_CTL:
+ regs.txdca_ctl = val;
+ if (regs.txdca_ctl.enabled())
+ panic("No support for DCA\n");
+ break;
case REG_TDT:
regs.tdt = val;
DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
@@ -553,12 +629,38 @@ IGbE::write(PacketPtr pkt)
case REG_TADV:
regs.tadv = val;
break;
+ case REG_TDWBAL:
+ regs.tdwba &= ~mask(32);
+ regs.tdwba |= val;
+ txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
+ break;
+ case REG_TDWBAH:
+ regs.tdwba &= mask(32);
+ regs.tdwba |= (uint64_t)val << 32;
+ txDescCache.completionWriteback(regs.tdwba & ~mask(1), regs.tdwba & mask(1));
+ break;
case REG_RXCSUM:
regs.rxcsum = val;
break;
+ case REG_RLPML:
+ regs.rlpml = val;
+ break;
+ case REG_RFCTL:
+ regs.rfctl = val;
+ if (regs.rfctl.exsten())
+ panic("Extended RX descriptors not implemented\n");
+ break;
case REG_MANC:
regs.manc = val;
break;
+ case REG_SWSM:
+ regs.swsm = val;
+ if (regs.fwsm.eep_fw_semaphore())
+ regs.swsm.swesmbi(0);
+ break;
+ case REG_SWFWSYNC:
+ regs.sw_fw_sync = val;
+ break;
default:
if (!(daddr >= REG_VFTA && daddr < (REG_VFTA + VLAN_FILTER_TABLE_SIZE*4)) &&
!(daddr >= REG_RAL && daddr < (REG_RAL + RCV_ADDRESS_TABLE_SIZE*8)) &&
@@ -580,16 +682,23 @@ IGbE::postInterrupt(IntTypes t, bool now)
return;
regs.icr = regs.icr() | t;
- if (regs.itr.interval() == 0 || now) {
+
+ Tick itr_interval = Clock::Int::ns * 256 * regs.itr.interval();
+ DPRINTF(EthernetIntr, "EINT: postInterrupt() curTick: %d itr: %d interval: %d\n",
+ curTick, regs.itr.interval(), itr_interval);
+
+ if (regs.itr.interval() == 0 || now || lastInterrupt + itr_interval <= curTick) {
if (interEvent.scheduled()) {
- interEvent.deschedule();
+ deschedule(interEvent);
}
cpuPostInt();
} else {
- DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for %d ticks\n",
- Clock::Int::ns * 256 * regs.itr.interval());
+ Tick int_time = lastInterrupt + itr_interval;
+ assert(int_time > 0);
+ DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
+ int_time);
if (!interEvent.scheduled()) {
- interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ schedule(interEvent, int_time);
}
}
}
@@ -605,6 +714,8 @@ void
IGbE::cpuPostInt()
{
+ postedInterrupts++;
+
if (!(regs.icr() & regs.imr)) {
DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
return;
@@ -614,24 +725,24 @@ IGbE::cpuPostInt()
if (interEvent.scheduled()) {
- interEvent.deschedule();
+ deschedule(interEvent);
}
if (rdtrEvent.scheduled()) {
regs.icr.rxt0(1);
- rdtrEvent.deschedule();
+ deschedule(rdtrEvent);
}
if (radvEvent.scheduled()) {
regs.icr.rxt0(1);
- radvEvent.deschedule();
+ deschedule(radvEvent);
}
if (tadvEvent.scheduled()) {
regs.icr.txdw(1);
- tadvEvent.deschedule();
+ deschedule(tadvEvent);
}
if (tidvEvent.scheduled()) {
regs.icr.txdw(1);
- tidvEvent.deschedule();
+ deschedule(tidvEvent);
}
regs.icr.int_assert(1);
@@ -640,6 +751,7 @@ IGbE::cpuPostInt()
intrPost();
+ lastInterrupt = curTick;
}
void
@@ -662,7 +774,7 @@ IGbE::chkInterrupt()
if (!(regs.icr() & regs.imr)) {
DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
if (interEvent.scheduled())
- interEvent.deschedule();
+ deschedule(interEvent);
if (regs.icr.int_assert())
cpuClearInt();
}
@@ -676,7 +788,8 @@ IGbE::chkInterrupt()
if (!interEvent.scheduled()) {
DPRINTF(Ethernet, "Scheduling for %d\n", curTick + Clock::Int::ns
* 256 * regs.itr.interval());
- interEvent.schedule(curTick + Clock::Int::ns * 256 * regs.itr.interval());
+ schedule(interEvent,
+ curTick + Clock::Int::ns * 256 * regs.itr.interval());
}
}
}
@@ -686,27 +799,125 @@ IGbE::chkInterrupt()
IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
- : DescCache<RxDesc>(i, n, s), pktDone(false), pktEvent(this)
+ : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0),
+ pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
{
+ annSmFetch = "RX Desc Fetch";
+ annSmWb = "RX Desc Writeback";
+ annUnusedDescQ = "RX Unused Descriptors";
+ annUnusedCacheQ = "RX Unused Descriptor Cache";
+ annUsedCacheQ = "RX Used Descriptor Cache";
+ annUsedDescQ = "RX Used Descriptors";
+ annDescQ = "RX Descriptors";
}
void
-IGbE::RxDescCache::writePacket(EthPacketPtr packet)
+IGbE::RxDescCache::pktSplitDone()
{
- // We shouldn't have to deal with any of these yet
- DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
- packet->length, igbe->regs.rctl.descSize());
- assert(packet->length < igbe->regs.rctl.descSize());
+ splitCount++;
+ DPRINTF(EthernetDesc, "Part of split packet done: splitcount now %d\n", splitCount);
+ assert(splitCount <= 2);
+ if (splitCount != 2)
+ return;
+ splitCount = 0;
+ DPRINTF(EthernetDesc, "Part of split packet done: calling pktComplete()\n");
+ pktComplete();
+}
- assert(unusedCache.size());
+int
+IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
+{
+ assert(unusedCache.size());
//if (!unusedCache.size())
// return false;
pktPtr = packet;
pktDone = false;
- igbe->dmaWrite(igbe->platform->pciToDma(unusedCache.front()->buf),
- packet->length, &pktEvent, packet->data);
+ int buf_len, hdr_len;
+
+ RxDesc *desc = unusedCache.front();
+ switch (igbe->regs.srrctl.desctype()) {
+ case RXDT_LEGACY:
+ assert(pkt_offset == 0);
+ bytesCopied = packet->length;
+ DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
+ packet->length, igbe->regs.rctl.descSize());
+ assert(packet->length < igbe->regs.rctl.descSize());
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->legacy.buf), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ break;
+ case RXDT_ADV_ONEBUF:
+ assert(pkt_offset == 0);
+ bytesCopied = packet->length;
+ buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+ igbe->regs.rctl.descSize();
+ DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
+ packet->length, igbe->regs.srrctl(), buf_len);
+ assert(packet->length < buf_len);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(0);
+ desc->adv_wb.sph = htole(0);
+ desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
+ break;
+ case RXDT_ADV_SPLIT_A:
+ int split_point;
+
+ buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+ igbe->regs.rctl.descSize();
+ hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0;
+ DPRINTF(EthernetDesc, "lpe: %d Packet Length: %d offset: %d srrctl: %#x hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
+ igbe->regs.rctl.lpe(), packet->length, pkt_offset, igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len, desc->adv_read.pkt, buf_len);
+
+ split_point = hsplit(pktPtr);
+
+ if (packet->length <= hdr_len) {
+ bytesCopied = packet->length;
+ assert(pkt_offset == 0);
+ DPRINTF(EthernetDesc, "Header Splitting: Entire packet being placed in header\n");
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), packet->length, &pktEvent,
+ packet->data, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole((uint16_t)packet->length);
+ desc->adv_wb.sph = htole(0);
+ desc->adv_wb.pkt_len = htole(0);
+ } else if (split_point) {
+ if (pkt_offset) {
+ // we are only copying some data, header/data has already been
+ // copied
+ int max_to_copy = std::min(packet->length - pkt_offset, buf_len);
+ bytesCopied += max_to_copy;
+ DPRINTF(EthernetDesc, "Header Splitting: Continuing data buffer copy\n");
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),max_to_copy, &pktEvent,
+ packet->data + pkt_offset, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(0);
+ desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
+ desc->adv_wb.sph = htole(0);
+ } else {
+ int max_to_copy = std::min(packet->length - split_point, buf_len);
+ bytesCopied += max_to_copy + split_point;
+
+ DPRINTF(EthernetDesc, "Header Splitting: splitting at %d\n",
+ split_point);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.hdr), split_point, &pktHdrEvent,
+ packet->data, igbe->rxWriteDelay);
+ igbe->dmaWrite(igbe->platform->pciToDma(desc->adv_read.pkt),
+ max_to_copy, &pktDataEvent, packet->data + split_point, igbe->rxWriteDelay);
+ desc->adv_wb.header_len = htole(split_point);
+ desc->adv_wb.sph = 1;
+ desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
+ }
+ } else {
+ panic("Header split not fitting within header buffer or undecodable"
+ " packet not fitting in header unsupported\n");
+ }
+ break;
+ default:
+ panic("Unimplemnted RX receive buffer type: %d\n",
+ igbe->regs.srrctl.desctype());
+ }
+ return bytesCopied;
+
}
void
@@ -716,10 +927,11 @@ IGbE::RxDescCache::pktComplete()
RxDesc *desc;
desc = unusedCache.front();
+ igbe->anBegin("RXS", "Update Desc");
+
uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
- desc->len = htole((uint16_t)(pktPtr->length + crcfixup));
- DPRINTF(EthernetDesc, "pktPtr->length: %d stripcrc offset: %d value written: %d %d\n",
- pktPtr->length, crcfixup,
+ DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d stripcrc offset: %d value written: %d %d\n",
+ pktPtr->length, bytesCopied, crcfixup,
htole((uint16_t)(pktPtr->length + crcfixup)),
(uint16_t)(pktPtr->length + crcfixup));
@@ -728,20 +940,32 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
- uint8_t status = RXDS_DD | RXDS_EOP;
+ uint16_t status = RXDS_DD;
uint8_t err = 0;
+ uint16_t ext_err = 0;
+ uint16_t csum = 0;
+ uint16_t ptype = 0;
+ uint16_t ip_id = 0;
+
+ assert(bytesCopied <= pktPtr->length);
+ if (bytesCopied == pktPtr->length)
+ status |= RXDS_EOP;
IpPtr ip(pktPtr);
if (ip) {
DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
+ ptype |= RXDP_IPV4;
+ ip_id = ip->id();
if (igbe->regs.rxcsum.ipofld()) {
DPRINTF(EthernetDesc, "Checking IP checksum\n");
status |= RXDS_IPCS;
- desc->csum = htole(cksum(ip));
+ csum = htole(cksum(ip));
+ igbe->rxIpChecksums++;
if (cksum(ip) != 0) {
err |= RXDE_IPE;
+ ext_err |= RXDEE_IPE;
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
}
}
@@ -749,10 +973,13 @@ IGbE::RxDescCache::pktComplete()
if (tcp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking TCP checksum\n");
status |= RXDS_TCPCS;
- desc->csum = htole(cksum(tcp));
+ ptype |= RXDP_TCP;
+ csum = htole(cksum(tcp));
+ igbe->rxTcpChecksums++;
if (cksum(tcp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
err |= RXDE_TCPE;
+ ext_err |= RXDEE_TCPE;
}
}
@@ -760,9 +987,12 @@ IGbE::RxDescCache::pktComplete()
if (udp && igbe->regs.rxcsum.tuofld()) {
DPRINTF(EthernetDesc, "Checking UDP checksum\n");
status |= RXDS_UDPCS;
- desc->csum = htole(cksum(udp));
+ ptype |= RXDP_UDP;
+ csum = htole(cksum(udp));
+ igbe->rxUdpChecksums++;
if (cksum(udp) != 0) {
DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+ ext_err |= RXDEE_TCPE;
err |= RXDE_TCPE;
}
}
@@ -770,53 +1000,83 @@ IGbE::RxDescCache::pktComplete()
DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
}
+ switch (igbe->regs.srrctl.desctype()) {
+ case RXDT_LEGACY:
+ desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
+ desc->legacy.status = htole(status);
+ desc->legacy.errors = htole(err);
+ // No vlan support at this point... just set it to 0
+ desc->legacy.vlan = 0;
+ break;
+ case RXDT_ADV_SPLIT_A:
+ case RXDT_ADV_ONEBUF:
+ desc->adv_wb.rss_type = htole(0);
+ desc->adv_wb.pkt_type = htole(ptype);
+ if (igbe->regs.rxcsum.pcsd()) {
+ // no rss support right now
+ desc->adv_wb.rss_hash = htole(0);
+ } else {
+ desc->adv_wb.id = htole(ip_id);
+ desc->adv_wb.csum = htole(csum);
+ }
+ desc->adv_wb.status = htole(status);
+ desc->adv_wb.errors = htole(ext_err);
+ // no vlan support
+ desc->adv_wb.vlan_tag = htole(0);
+ break;
+ default:
+ panic("Unimplemnted RX receive buffer type %d\n",
+ igbe->regs.srrctl.desctype());
+ }
- desc->status = htole(status);
- desc->errors = htole(err);
-
- // No vlan support at this point... just set it to 0
- desc->vlan = 0;
+ DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
+ desc->adv_read.pkt, desc->adv_read.hdr);
- // Deal with the rx timer interrupts
- if (igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
- igbe->regs.rdtr.delay() * igbe->intClock());
- igbe->rdtrEvent.reschedule(curTick + igbe->regs.rdtr.delay() *
- igbe->intClock(),true);
- }
+ if (bytesCopied == pktPtr->length) {
+ DPRINTF(EthernetDesc, "Packet completely written to descriptor buffers\n");
+ // Deal with the rx timer interrupts
+ if (igbe->regs.rdtr.delay()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n",
+ igbe->regs.rdtr.delay() * igbe->intClock());
+ igbe->reschedule(igbe->rdtrEvent,
+ curTick + igbe->regs.rdtr.delay() * igbe->intClock(), true);
+ }
- if (igbe->regs.radv.idv() && igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
- igbe->regs.radv.idv() * igbe->intClock());
- if (!igbe->radvEvent.scheduled()) {
- igbe->radvEvent.schedule(curTick + igbe->regs.radv.idv() *
- igbe->intClock());
+ if (igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n",
+ igbe->regs.radv.idv() * igbe->intClock());
+ if (!igbe->radvEvent.scheduled()) {
+ igbe->schedule(igbe->radvEvent,
+ curTick + igbe->regs.radv.idv() * igbe->intClock());
+ }
}
- }
- // if neither radv or rdtr, maybe itr is set...
- if (!igbe->regs.rdtr.delay()) {
- DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
- igbe->postInterrupt(IT_RXT);
- }
+ // if neither radv or rdtr, maybe itr is set...
+ if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
+ DPRINTF(EthernetSM, "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
+ igbe->postInterrupt(IT_RXT);
+ }
- // If the packet is small enough, interrupt appropriately
- // I wonder if this is delayed or not?!
- if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
- DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
- igbe->postInterrupt(IT_SRPD);
+ // If the packet is small enough, interrupt appropriately
+ // I wonder if this is delayed or not?!
+ if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
+ DPRINTF(EthernetSM, "RXS: Posting IT_SRPD beacuse small packet received\n");
+ igbe->postInterrupt(IT_SRPD);
+ }
+ bytesCopied = 0;
}
- DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
- unusedCache.pop_front();
- usedCache.push_back(desc);
-
-
pktPtr = NULL;
+ igbe->checkDrain();
enableSm();
pktDone = true;
- igbe->checkDrain();
+ igbe->anBegin("RXS", "Done Updating Desc");
+ DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
+ igbe->anDq("RXS", annUnusedCacheQ);
+ unusedCache.pop_front();
+ igbe->anQ("RXS", annUsedCacheQ);
+ usedCache.push_back(desc);
}
void
@@ -842,7 +1102,9 @@ bool
IGbE::RxDescCache::hasOutstandingEvents()
{
return pktEvent.scheduled() || wbEvent.scheduled() ||
- fetchEvent.scheduled();
+ fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
+ pktDataEvent.scheduled();
+
}
void
@@ -850,6 +1112,8 @@ IGbE::RxDescCache::serialize(std::ostream &os)
{
DescCache<RxDesc>::serialize(os);
SERIALIZE_SCALAR(pktDone);
+ SERIALIZE_SCALAR(splitCount);
+ SERIALIZE_SCALAR(bytesCopied);
}
void
@@ -857,6 +1121,8 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
{
DescCache<RxDesc>::unserialize(cp, section);
UNSERIALIZE_SCALAR(pktDone);
+ UNSERIALIZE_SCALAR(splitCount);
+ UNSERIALIZE_SCALAR(bytesCopied);
}
@@ -864,45 +1130,154 @@ IGbE::RxDescCache::unserialize(Checkpoint *cp, const std::string &section)
IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
: DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false), pktWaiting(false),
- pktEvent(this)
+ completionAddress(0), completionEnabled(false),
+ useTso(false), pktEvent(this), headerEvent(this), nullEvent(this)
{
+ annSmFetch = "TX Desc Fetch";
+ annSmWb = "TX Desc Writeback";
+ annUnusedDescQ = "TX Unused Descriptors";
+ annUnusedCacheQ = "TX Unused Descriptor Cache";
+ annUsedCacheQ = "TX Used Descriptor Cache";
+ annUsedDescQ = "TX Used Descriptors";
+ annDescQ = "TX Descriptors";
}
-int
-IGbE::TxDescCache::getPacketSize()
+void
+IGbE::TxDescCache::processContextDesc()
{
assert(unusedCache.size());
-
TxDesc *desc;
+
+ DPRINTF(EthernetDesc, "Checking and processing context descriptors\n");
- DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
-
- while (unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
- DPRINTF(EthernetDesc, "Got context descriptor type... skipping\n");
+ while (!useTso && unusedCache.size() && TxdOp::isContext(unusedCache.front())) {
+ DPRINTF(EthernetDesc, "Got context descriptor type...\n");
- // I think we can just ignore these for now?
desc = unusedCache.front();
- DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", desc->d1,
- desc->d2);
+ DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n",
+ desc->d1, desc->d2);
+
+
// is this going to be a tcp or udp packet?
isTcp = TxdOp::tcp(desc) ? true : false;
- // make sure it's ipv4
- //assert(TxdOp::ip(desc));
+ // setup all the TSO variables, they'll be ignored if we don't use
+ // tso for this connection
+ tsoHeaderLen = TxdOp::hdrlen(desc);
+ tsoMss = TxdOp::mss(desc);
+
+ if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
+ DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: %d mss: %d paylen %d\n",
+ TxdOp::hdrlen(desc), TxdOp::mss(desc), TxdOp::getLen(desc));
+ useTso = true;
+ tsoTotalLen = TxdOp::getLen(desc);
+ tsoLoadedHeader = false;
+ tsoDescBytesUsed = 0;
+ tsoUsedLen = 0;
+ tsoPrevSeq = 0;
+ tsoPktHasHeader = false;
+ tsoPkts = 0;
+
+ }
TxdOp::setDd(desc);
unusedCache.pop_front();
+ igbe->anDq("TXS", annUnusedCacheQ);
usedCache.push_back(desc);
+ igbe->anQ("TXS", annUsedCacheQ);
}
if (!unusedCache.size())
+ return;
+
+ desc = unusedCache.front();
+ if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && TxdOp::tse(desc)) {
+ DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet hdrlen: %d mss: %d paylen %d\n",
+ tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
+ useTso = true;
+ tsoTotalLen = TxdOp::getTsoLen(desc);
+ tsoLoadedHeader = false;
+ tsoDescBytesUsed = 0;
+ tsoUsedLen = 0;
+ tsoPrevSeq = 0;
+ tsoPktHasHeader = false;
+ tsoPkts = 0;
+ }
+
+ if (useTso && !tsoLoadedHeader) {
+ // we need to fetch a header
+ DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
+ assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
+ pktWaiting = true;
+ assert(tsoHeaderLen <= 256);
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
+ tsoHeaderLen, &headerEvent, tsoHeader, 0);
+ }
+}
+
+void
+IGbE::TxDescCache::headerComplete()
+{
+ DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
+ pktWaiting = false;
+
+ assert(unusedCache.size());
+ TxDesc *desc = unusedCache.front();
+ DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
+ TxdOp::getLen(desc), tsoHeaderLen);
+
+ if (TxdOp::getLen(desc) == tsoHeaderLen) {
+ tsoDescBytesUsed = 0;
+ tsoLoadedHeader = true;
+ unusedCache.pop_front();
+ usedCache.push_back(desc);
+ } else {
+ // I don't think this case happens, I think the headrer is always
+ // it's own packet, if it wasn't it might be as simple as just
+ // incrementing descBytesUsed by the header length, but I'm not
+ // completely sure
+ panic("TSO header part of bigger packet, not implemented\n");
+ }
+ enableSm();
+ igbe->checkDrain();
+}
+
+int
+IGbE::TxDescCache::getPacketSize(EthPacketPtr p)
+{
+ TxDesc *desc;
+
+
+ if (!unusedCache.size())
return -1;
+
+ DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
- DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
- TxdOp::getLen(unusedCache.front()));
+ assert(!useTso || tsoLoadedHeader);
+ desc = unusedCache.front();
+
+
+ if (useTso) {
+ DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
+ useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
+ DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d this descLen: %d\n",
+ tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
+ DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
+
+ if (tsoPktHasHeader)
+ tsoCopyBytes = std::min((tsoMss + tsoHeaderLen) - p->length, TxdOp::getLen(desc) - tsoDescBytesUsed);
+ else
+ tsoCopyBytes = std::min(tsoMss, TxdOp::getLen(desc) - tsoDescBytesUsed);
+ Addr pkt_size = tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen);
+ DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
+ return pkt_size;
+ }
- return TxdOp::getLen(unusedCache.front());
+ DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
+ TxdOp::getLen(unusedCache.front()));
+ return TxdOp::getLen(desc);
}
void
@@ -913,17 +1288,37 @@ IGbE::TxDescCache::getPacketData(EthPacketPtr p)
TxDesc *desc;
desc = unusedCache.front();
+ DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
pktPtr = p;
pktWaiting = true;
- DPRINTF(EthernetDesc, "Starting DMA of packet\n");
- igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
- TxdOp::getLen(desc), &pktEvent, p->data + p->length);
-
-
+ DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
+
+ if (useTso) {
+ assert(tsoLoadedHeader);
+ if (!tsoPktHasHeader) {
+ DPRINTF(EthernetDesc, "Loading TSO header (%d bytes) into start of packet\n",
+ tsoHeaderLen);
+ memcpy(p->data, &tsoHeader,tsoHeaderLen);
+ p->length +=tsoHeaderLen;
+ tsoPktHasHeader = true;
+ }
+ }
+
+ if (useTso) {
+ tsoDescBytesUsed += tsoCopyBytes;
+ assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
+ DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d length: %d\n",
+ p->length, tsoCopyBytes);
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)) + tsoDescBytesUsed,
+ tsoCopyBytes, &pktEvent, p->data + p->length, igbe->txReadDelay);
+ } else {
+ igbe->dmaRead(igbe->platform->pciToDma(TxdOp::getBuf(desc)),
+ TxdOp::getLen(desc), &pktEvent, p->data + p->length, igbe->txReadDelay);
+ }
}
void
@@ -934,6 +1329,8 @@ IGbE::TxDescCache::pktComplete()
assert(unusedCache.size());
assert(pktPtr);
+ igbe->anBegin("TXS", "Update Desc");
+
DPRINTF(EthernetDesc, "DMA of packet complete\n");
@@ -941,40 +1338,83 @@ IGbE::TxDescCache::pktComplete()
assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) && TxdOp::getLen(desc));
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d used: %d loaded hdr: %d\n",
+ useTso, tsoHeaderLen, tsoMss, tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
- if (!TxdOp::eop(desc)) {
- // This only supports two descriptors per tx packet
- assert(pktPtr->length == 0);
- pktPtr->length = TxdOp::getLen(desc);
+ // Set the length of the data in the EtherPacket
+ if (useTso) {
+ pktPtr->length += tsoCopyBytes;
+ tsoUsedLen += tsoCopyBytes;
+ } else
+ pktPtr->length += TxdOp::getLen(desc);
+
+ DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
+ tsoDescBytesUsed, tsoCopyBytes);
+
+
+ if ((!TxdOp::eop(desc) && !useTso) ||
+ (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
+ tsoTotalLen != tsoUsedLen && useTso)) {
+ assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
+ igbe->anDq("TXS", annUnusedCacheQ);
unusedCache.pop_front();
+ igbe->anQ("TXS", annUsedCacheQ);
usedCache.push_back(desc);
+
+ tsoDescBytesUsed = 0;
pktDone = true;
pktWaiting = false;
+ pktMultiDesc = true;
+
+ DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
+ pktPtr->length);
pktPtr = NULL;
- DPRINTF(EthernetDesc, "Partial Packet Descriptor Done\n");
enableSm();
igbe->checkDrain();
return;
}
- // Set the length of the data in the EtherPacket
- pktPtr->length += TxdOp::getLen(desc);
+ pktMultiDesc = false;
// no support for vlans
assert(!TxdOp::vle(desc));
- // we alway report status
- assert(TxdOp::rs(desc));
-
// we only support single packet descriptors at this point
- assert(TxdOp::eop(desc));
+ if (!useTso)
+ assert(TxdOp::eop(desc));
// set that this packet is done
- TxdOp::setDd(desc);
+ if (TxdOp::rs(desc))
+ TxdOp::setDd(desc);
DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+ if (useTso) {
+ IpPtr ip(pktPtr);
+ if (ip) {
+ DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
+ tsoPkts);
+ ip->id(ip->id() + tsoPkts++);
+ ip->len(pktPtr->length - EthPtr(pktPtr)->size());
+
+ TcpPtr tcp(ip);
+ if (tcp) {
+ DPRINTF(EthernetDesc, "TSO: Modifying TCP header. old seq %d + %d\n",
+ tcp->seq(), tsoPrevSeq);
+ tcp->seq(tcp->seq() + tsoPrevSeq);
+ if (tsoUsedLen != tsoTotalLen)
+ tcp->flags(tcp->flags() & ~9); // clear fin & psh
+ }
+ UdpPtr udp(ip);
+ if (udp) {
+ DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
+ udp->len(pktPtr->length - EthPtr(pktPtr)->size());
+ }
+ }
+ tsoPrevSeq = tsoUsedLen;
+ }
+
if (DTRACE(EthernetDesc)) {
IpPtr ip(pktPtr);
if (ip)
@@ -988,10 +1428,11 @@ IGbE::TxDescCache::pktComplete()
if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
IpPtr ip(pktPtr);
-
+ assert(ip);
if (TxdOp::ixsm(desc)) {
ip->sum(0);
ip->sum(cksum(ip));
+ igbe->txIpChecksums++;
DPRINTF(EthernetDesc, "Calculated IP checksum\n");
}
if (TxdOp::txsm(desc)) {
@@ -1000,11 +1441,13 @@ IGbE::TxDescCache::pktComplete()
if (tcp) {
tcp->sum(0);
tcp->sum(cksum(tcp));
+ igbe->txTcpChecksums++;
DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
} else if (udp) {
assert(udp);
udp->sum(0);
udp->sum(cksum(udp));
+ igbe->txUdpChecksums++;
DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
} else {
panic("Told to checksum, but don't know how\n");
@@ -1017,47 +1460,100 @@ IGbE::TxDescCache::pktComplete()
DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
if (igbe->regs.tidv.idv()) {
DPRINTF(EthernetDesc, "setting tidv\n");
- igbe->tidvEvent.reschedule(curTick + igbe->regs.tidv.idv() *
- igbe->intClock(), true);
+ igbe->reschedule(igbe->tidvEvent,
+ curTick + igbe->regs.tidv.idv() * igbe->intClock(), true);
}
if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
DPRINTF(EthernetDesc, "setting tadv\n");
if (!igbe->tadvEvent.scheduled()) {
- igbe->tadvEvent.schedule(curTick + igbe->regs.tadv.idv() *
- igbe->intClock());
+ igbe->schedule(igbe->tadvEvent,
+ curTick + igbe->regs.tadv.idv() * igbe->intClock());
}
}
}
+ if (!useTso || TxdOp::getLen(desc) == tsoDescBytesUsed) {
+ DPRINTF(EthernetDesc, "Descriptor Done\n");
+ igbe->anDq("TXS", annUnusedCacheQ);
+ unusedCache.pop_front();
+ igbe->anQ("TXS", annUsedCacheQ);
+ usedCache.push_back(desc);
+ tsoDescBytesUsed = 0;
+ }
+
+ if (useTso && tsoUsedLen == tsoTotalLen)
+ useTso = false;
+
- unusedCache.pop_front();
- usedCache.push_back(desc);
+ DPRINTF(EthernetDesc, "------Packet of %d bytes ready for transmission-------\n",
+ pktPtr->length);
pktDone = true;
pktWaiting = false;
pktPtr = NULL;
-
- DPRINTF(EthernetDesc, "Descriptor Done\n");
+ tsoPktHasHeader = false;
if (igbe->regs.txdctl.wthresh() == 0) {
+ igbe->anBegin("TXS", "Desc Writeback");
DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
writeback(0);
+ } else if (igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() >=
+ descInBlock(usedCache.size())) {
+ DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+ igbe->anBegin("TXS", "Desc Writeback");
+ writeback((igbe->cacheBlockSize()-1)>>4);
} else if (igbe->regs.txdctl.wthresh() >= usedCache.size()) {
DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+ igbe->anBegin("TXS", "Desc Writeback");
writeback((igbe->cacheBlockSize()-1)>>4);
}
+
enableSm();
igbe->checkDrain();
}
void
+IGbE::TxDescCache::actionAfterWb()
+{
+ DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
+ completionEnabled);
+ igbe->postInterrupt(iGbReg::IT_TXDW);
+ if (completionEnabled) {
+ descEnd = igbe->regs.tdh();
+ DPRINTF(EthernetDesc, "Completion writing back value: %d to addr: %#x\n", descEnd,
+ completionAddress);
+ igbe->dmaWrite(igbe->platform->pciToDma(mbits(completionAddress, 63, 2)),
+ sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
+ }
+}
+
+void
IGbE::TxDescCache::serialize(std::ostream &os)
{
DescCache<TxDesc>::serialize(os);
SERIALIZE_SCALAR(pktDone);
SERIALIZE_SCALAR(isTcp);
SERIALIZE_SCALAR(pktWaiting);
+ SERIALIZE_SCALAR(pktMultiDesc);
+
+ SERIALIZE_SCALAR(useTso);
+ SERIALIZE_SCALAR(tsoHeaderLen);
+ SERIALIZE_SCALAR(tsoMss);
+ SERIALIZE_SCALAR(tsoTotalLen);
+ SERIALIZE_SCALAR(tsoUsedLen);
+ SERIALIZE_SCALAR(tsoPrevSeq);;
+ SERIALIZE_SCALAR(tsoPktPayloadBytes);
+ SERIALIZE_SCALAR(tsoLoadedHeader);
+ SERIALIZE_SCALAR(tsoPktHasHeader);
+ SERIALIZE_ARRAY(tsoHeader, 256);
+ SERIALIZE_SCALAR(tsoDescBytesUsed);
+ SERIALIZE_SCALAR(tsoCopyBytes);
+ SERIALIZE_SCALAR(tsoPkts);
+
+ SERIALIZE_SCALAR(completionAddress);
+ SERIALIZE_SCALAR(completionEnabled);
+ SERIALIZE_SCALAR(descEnd);
}
void
@@ -1067,6 +1563,25 @@ IGbE::TxDescCache::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(pktDone);
UNSERIALIZE_SCALAR(isTcp);
UNSERIALIZE_SCALAR(pktWaiting);
+ UNSERIALIZE_SCALAR(pktMultiDesc);
+
+ UNSERIALIZE_SCALAR(useTso);
+ UNSERIALIZE_SCALAR(tsoHeaderLen);
+ UNSERIALIZE_SCALAR(tsoMss);
+ UNSERIALIZE_SCALAR(tsoTotalLen);
+ UNSERIALIZE_SCALAR(tsoUsedLen);
+ UNSERIALIZE_SCALAR(tsoPrevSeq);;
+ UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
+ UNSERIALIZE_SCALAR(tsoLoadedHeader);
+ UNSERIALIZE_SCALAR(tsoPktHasHeader);
+ UNSERIALIZE_ARRAY(tsoHeader, 256);
+ UNSERIALIZE_SCALAR(tsoDescBytesUsed);
+ UNSERIALIZE_SCALAR(tsoCopyBytes);
+ UNSERIALIZE_SCALAR(tsoPkts);
+
+ UNSERIALIZE_SCALAR(completionAddress);
+ UNSERIALIZE_SCALAR(completionEnabled);
+ UNSERIALIZE_SCALAR(descEnd);
}
bool
@@ -1101,9 +1616,9 @@ IGbE::TxDescCache::hasOutstandingEvents()
void
IGbE::restartClock()
{
- if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) && getState() ==
- SimObject::Running)
- tickEvent.schedule((curTick/ticks(1)) * ticks(1) + ticks(1));
+ if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
+ getState() == SimObject::Running)
+ schedule(tickEvent, (curTick / ticks(1)) * ticks(1) + ticks(1));
}
unsigned int
@@ -1122,13 +1637,14 @@ IGbE::drain(Event *de)
rxTick = false;
if (tickEvent.scheduled())
- tickEvent.deschedule();
+ deschedule(tickEvent);
if (count)
changeState(Draining);
else
changeState(Drained);
+ DPRINTF(EthernetSM, "got drain() returning %d", count);
return count;
}
@@ -1142,6 +1658,7 @@ IGbE::resume()
rxTick = true;
restartClock();
+ DPRINTF(EthernetSM, "resuming from drain");
}
void
@@ -1150,6 +1667,7 @@ IGbE::checkDrain()
if (!drainEvent)
return;
+ DPRINTF(EthernetSM, "checkDrain() in drain\n");
txFifoTick = false;
txTick = false;
rxTick = false;
@@ -1172,20 +1690,22 @@ IGbE::txStateMachine()
// If we have a packet available and it's length is not 0 (meaning it's not
// a multidescriptor packet) put it in the fifo, otherwise an the next
// iteration we'll get the rest of the data
- if (txPacket && txDescCache.packetAvailable() && txPacket->length) {
+ if (txPacket && txDescCache.packetAvailable()
+ && !txDescCache.packetMultiDesc() && txPacket->length) {
bool success;
+ anQ("TXS", "TX FIFO Q");
DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
success = txFifo.push(txPacket);
txFifoTick = true && !drainEvent;
assert(success);
txPacket = NULL;
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback((cacheBlockSize()-1)>>4);
return;
}
// Only support descriptor granularity
- assert(regs.txdctl.gran());
if (regs.txdctl.lwthresh() && txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
postInterrupt(IT_TXDLOW);
@@ -1198,7 +1718,10 @@ IGbE::txStateMachine()
if (!txDescCache.packetWaiting()) {
if (txDescCache.descLeft() == 0) {
postInterrupt(IT_TXQE);
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback(0);
+ anBegin("TXS", "Desc Fetch");
+ anWe("TXS", txDescCache.annUnusedCacheQ);
txDescCache.fetchDescriptors();
DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
"writeback stopping ticking and posting TXQE\n");
@@ -1208,16 +1731,28 @@ IGbE::txStateMachine()
if (!(txDescCache.descUnused())) {
+ anBegin("TXS", "Desc Fetch");
txDescCache.fetchDescriptors();
+ anWe("TXS", txDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "TXS: No descriptors available in cache, fetching and stopping ticking\n");
txTick = false;
return;
}
+ anPq("TXS", txDescCache.annUnusedCacheQ);
+
+ txDescCache.processContextDesc();
+ if (txDescCache.packetWaiting()) {
+ DPRINTF(EthernetSM, "TXS: Fetching TSO header, stopping ticking\n");
+ txTick = false;
+ return;
+ }
int size;
- size = txDescCache.getPacketSize();
+ size = txDescCache.getPacketSize(txPacket);
if (size > 0 && txFifo.avail() > size) {
+ anRq("TXS", "TX FIFO Q");
+ anBegin("TXS", "DMA Packet");
DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and begining "
"DMA of next packet\n", size);
txFifo.reserve(size);
@@ -1225,8 +1760,10 @@ IGbE::txStateMachine()
} else if (size <= 0) {
DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
DPRINTF(EthernetSM, "TXS: No packets to get, writing back used descriptors\n");
+ anBegin("TXS", "Desc Writeback");
txDescCache.writeback(0);
} else {
+ anWf("TXS", "TX FIFO Q");
DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
"available in FIFO\n");
txTick = false;
@@ -1242,10 +1779,16 @@ IGbE::txStateMachine()
bool
IGbE::ethRxPkt(EthPacketPtr pkt)
{
+ rxBytes += pkt->length;
+ rxPackets++;
+
DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
+ anBegin("RXQ", "Wire Recv");
+
if (!regs.rctl.en()) {
DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
+ anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
return true;
}
@@ -1259,9 +1802,23 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
if (!rxFifo.push(pkt)) {
DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
postInterrupt(IT_RXO, true);
+ anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
return false;
}
+ if (CPA::available() && cpa->enabled()) {
+ assert(sys->numSystemsRunning <= 2);
+ System *other_sys;
+ if (sys->systemList[0] == sys)
+ other_sys = sys->systemList[1];
+ else
+ other_sys = sys->systemList[0];
+
+ cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+ anQ("RXQ", "RX FIFO Q");
+ cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+ }
+
return true;
}
@@ -1280,6 +1837,8 @@ IGbE::rxStateMachine()
rxDmaPacket = false;
DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
int descLeft = rxDescCache.descLeft();
+ DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
+ descLeft, regs.rctl.rdmts(), regs.rdlen());
switch (regs.rctl.rdmts()) {
case 2: if (descLeft > .125 * regs.rdlen()) break;
case 1: if (descLeft > .250 * regs.rdlen()) break;
@@ -1289,7 +1848,11 @@ IGbE::rxStateMachine()
break;
}
+ if (rxFifo.empty())
+ rxDescCache.writeback(0);
+
if (descLeft == 0) {
+ anBegin("RXS", "Writeback Descriptors");
rxDescCache.writeback(0);
DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
" writeback and stopping ticking\n");
@@ -1301,6 +1864,7 @@ IGbE::rxStateMachine()
if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
DPRINTF(EthernetSM, "RXS: Writing back because WTHRESH >= descUsed\n");
+ anBegin("RXS", "Writeback Descriptors");
if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
rxDescCache.writeback(regs.rxdctl.wthresh()-1);
else
@@ -1310,11 +1874,14 @@ IGbE::rxStateMachine()
if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
((rxDescCache.descLeft() - rxDescCache.descUnused()) > regs.rxdctl.hthresh())) {
DPRINTF(EthernetSM, "RXS: Fetching descriptors because descUnused < PTHRESH\n");
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
}
if (rxDescCache.descUnused() == 0) {
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
+ anWe("RXS", rxDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
"fetching descriptors and stopping ticking\n");
rxTick = false;
@@ -1329,42 +1896,58 @@ IGbE::rxStateMachine()
}
if (!rxDescCache.descUnused()) {
+ anBegin("RXS", "Fetch Descriptors");
rxDescCache.fetchDescriptors();
+ anWe("RXS", rxDescCache.annUnusedCacheQ);
DPRINTF(EthernetSM, "RXS: No descriptors available in cache, stopping ticking\n");
rxTick = false;
DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
return;
}
+ anPq("RXS", rxDescCache.annUnusedCacheQ);
if (rxFifo.empty()) {
+ anWe("RXS", "RX FIFO Q");
DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
rxTick = false;
return;
}
+ anPq("RXS", "RX FIFO Q");
+ anBegin("RXS", "Get Desc");
EthPacketPtr pkt;
pkt = rxFifo.front();
- rxDescCache.writePacket(pkt);
+ pktOffset = rxDescCache.writePacket(pkt, pktOffset);
DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
- DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
- rxFifo.pop();
+ if (pktOffset == pkt->length) {
+ anBegin( "RXS", "FIFO Dequeue");
+ DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
+ pktOffset = 0;
+ anDq("RXS", "RX FIFO Q");
+ rxFifo.pop();
+ }
+
DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
rxTick = false;
rxDmaPacket = true;
+ anBegin("RXS", "DMA Packet");
}
void
IGbE::txWire()
{
if (txFifo.empty()) {
+ anWe("TXQ", "TX FIFO Q");
txFifoTick = false;
return;
}
+ anPq("TXQ", "TX FIFO Q");
if (etherInt->sendPacket(txFifo.front())) {
+ cpa->hwQ(CPA::FL_NONE, sys, macAddr, "TXQ", "WireQ", 0);
if (DTRACE(EthernetSM)) {
IpPtr ip(txFifo.front());
if (ip)
@@ -1373,8 +1956,15 @@ IGbE::txWire()
else
DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
}
+ anDq("TXQ", "TX FIFO Q");
+ anBegin("TXQ", "Wire Send");
DPRINTF(EthernetSM, "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
txFifo.avail());
+
+ txBytes += txFifo.front()->length;
+ txPackets++;
+ txFifoTick = false;
+
txFifo.pop();
} else {
// We'll get woken up when the packet ethTxDone() gets called
@@ -1398,12 +1988,13 @@ IGbE::tick()
if (rxTick || txTick || txFifoTick)
- tickEvent.schedule(curTick + ticks(1));
+ schedule(tickEvent, curTick + ticks(1));
}
void
IGbE::ethTxDone()
{
+ anBegin("TXQ", "Send Done");
// restart the tx state machines if they are stopped
// fifo to send another packet
// tx sm to put more data into the fifo
@@ -1412,6 +2003,7 @@ IGbE::ethTxDone()
txTick = true;
restartClock();
+ txWire();
DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
}
@@ -1426,6 +2018,7 @@ IGbE::serialize(std::ostream &os)
SERIALIZE_SCALAR(eeDataBits);
SERIALIZE_SCALAR(eeOpcode);
SERIALIZE_SCALAR(eeAddr);
+ SERIALIZE_SCALAR(lastInterrupt);
SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
rxFifo.serialize("rxfifo", os);
@@ -1459,6 +2052,8 @@ IGbE::serialize(std::ostream &os)
inter_time = interEvent.when();
SERIALIZE_SCALAR(inter_time);
+ SERIALIZE_SCALAR(pktOffset);
+
nameOut(os, csprintf("%s.TxDescCache", name()));
txDescCache.serialize(os);
@@ -1477,6 +2072,7 @@ IGbE::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(eeDataBits);
UNSERIALIZE_SCALAR(eeOpcode);
UNSERIALIZE_SCALAR(eeAddr);
+ UNSERIALIZE_SCALAR(lastInterrupt);
UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
rxFifo.unserialize("rxfifo", cp, section);
@@ -1501,19 +2097,21 @@ IGbE::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(inter_time);
if (rdtr_time)
- rdtrEvent.schedule(rdtr_time);
+ schedule(rdtrEvent, rdtr_time);
if (radv_time)
- radvEvent.schedule(radv_time);
+ schedule(radvEvent, radv_time);
if (tidv_time)
- tidvEvent.schedule(tidv_time);
+ schedule(tidvEvent, tidv_time);
if (tadv_time)
- tadvEvent.schedule(tadv_time);
+ schedule(tadvEvent, tadv_time);
if (inter_time)
- interEvent.schedule(inter_time);
+ schedule(interEvent, inter_time);
+
+ UNSERIALIZE_SCALAR(pktOffset);
txDescCache.unserialize(cp, csprintf("%s.TxDescCache", section));
diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh
index 9403c87b6..308cfabde 100644
--- a/src/dev/i8254xGBe.hh
+++ b/src/dev/i8254xGBe.hh
@@ -38,8 +38,8 @@
#include <deque>
#include <string>
+#include "base/cp_annotate.hh"
#include "base/inet.hh"
-#include "base/statistics.hh"
#include "dev/etherdevice.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
@@ -55,6 +55,7 @@ class IGbE : public EtherDevice
{
private:
IGbEInt *etherInt;
+ CPA *cpa;
// device registers
iGbReg::Regs regs;
@@ -84,11 +85,19 @@ class IGbE : public EtherDevice
bool rxDmaPacket;
+ // Number of bytes copied from current RX packet
+ int pktOffset;
+
+ // Delays in managaging descriptors
+ Tick fetchDelay, wbDelay;
+ Tick fetchCompDelay, wbCompDelay;
+ Tick rxWriteDelay, txReadDelay;
+
// Event and function to deal with RDTR timer expiring
void rdtrProcess() {
rxDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting RXT interrupt because RDTR timer expired\n");
- postInterrupt(iGbReg::IT_RXT, true);
+ postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
@@ -98,7 +107,7 @@ class IGbE : public EtherDevice
void radvProcess() {
rxDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting RXT interrupt because RADV timer expired\n");
- postInterrupt(iGbReg::IT_RXT, true);
+ postInterrupt(iGbReg::IT_RXT);
}
//friend class EventWrapper<IGbE, &IGbE::radvProcess>;
@@ -108,7 +117,7 @@ class IGbE : public EtherDevice
void tadvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting TXDW interrupt because TADV timer expired\n");
- postInterrupt(iGbReg::IT_TXDW, true);
+ postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
@@ -118,7 +127,7 @@ class IGbE : public EtherDevice
void tidvProcess() {
txDescCache.writeback(0);
DPRINTF(EthernetIntr, "Posting TXDW interrupt because TIDV timer expired\n");
- postInterrupt(iGbReg::IT_TXDW, true);
+ postInterrupt(iGbReg::IT_TXDW);
}
//friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
@@ -129,6 +138,8 @@ class IGbE : public EtherDevice
EventWrapper<IGbE, &IGbE::tick> tickEvent;
+ uint64_t macAddr;
+
void rxStateMachine();
void txStateMachine();
void txWire();
@@ -167,6 +178,35 @@ class IGbE : public EtherDevice
*/
void checkDrain();
+ void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
+ cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
+ }
+
+ void anQ(std::string sm, std::string q) {
+ cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+ }
+
+ void anDq(std::string sm, std::string q) {
+ cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+ }
+
+ void anPq(std::string sm, std::string q, int num = 1) {
+ cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+ }
+
+ void anRq(std::string sm, std::string q, int num = 1) {
+ cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+ }
+
+ void anWe(std::string sm, std::string q) {
+ cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+ }
+
+ void anWf(std::string sm, std::string q) {
+ cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+ }
+
+
template<class T>
class DescCache
{
@@ -177,7 +217,7 @@ class IGbE : public EtherDevice
virtual long descLen() const = 0;
virtual void updateHead(long h) = 0;
virtual void enableSm() = 0;
- virtual void intAfterWb() const {}
+ virtual void actionAfterWb() {}
virtual void fetchAfterWb() = 0;
std::deque<T*> usedCache;
@@ -216,9 +256,14 @@ class IGbE : public EtherDevice
EthPacketPtr pktPtr;
public:
+ /** Annotate sm*/
+ std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
+ annUsedDescQ, annUnusedCacheQ, annDescQ;
+
DescCache(IGbE *i, const std::string n, int s)
: igbe(i), _name(n), cachePnt(0), size(s), curFetching(0), wbOut(0),
- pktPtr(NULL), fetchEvent(this), wbEvent(this)
+ pktPtr(NULL), wbDelayEvent(this), fetchDelayEvent(this),
+ fetchEvent(this), wbEvent(this)
{
fetchBuf = new T[size];
wbBuf = new T[size];
@@ -248,62 +293,92 @@ class IGbE : public EtherDevice
int curHead = descHead();
int max_to_wb = usedCache.size();
- DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
- "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
- curHead, descTail(), descLen(), cachePnt, max_to_wb,
- descLeft());
-
// Check if this writeback is less restrictive that the previous
// and if so setup another one immediately following it
- if (wbOut && (aMask < wbAlignment)) {
- moreToWb = true;
- wbAlignment = aMask;
+ if (wbOut) {
+ if (aMask < wbAlignment) {
+ moreToWb = true;
+ wbAlignment = aMask;
+ }
DPRINTF(EthernetDesc, "Writing back already in process, returning\n");
return;
}
-
moreToWb = false;
wbAlignment = aMask;
+
+
+ DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
+ "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+ curHead, descTail(), descLen(), cachePnt, max_to_wb,
+ descLeft());
if (max_to_wb + curHead >= descLen()) {
max_to_wb = descLen() - curHead;
moreToWb = true;
// this is by definition aligned correctly
- } else if (aMask != 0) {
+ } else if (wbAlignment != 0) {
// align the wb point to the mask
- max_to_wb = max_to_wb & ~aMask;
+ max_to_wb = max_to_wb & ~wbAlignment;
}
DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
- if (max_to_wb <= 0 || wbOut)
+ if (max_to_wb <= 0) {
+ if (usedCache.size())
+ igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
+ else
+ igbe->anWe(annSmWb, annUsedCacheQ);
return;
+ }
wbOut = max_to_wb;
+ assert(!wbDelayEvent.scheduled());
+ igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+ igbe->anBegin(annSmWb, "Prepare Writeback Desc");
+ }
+
+ void writeback1()
+ {
+ // If we're draining delay issuing this DMA
+ if (igbe->getState() != SimObject::Running) {
+ igbe->schedule(wbDelayEvent, curTick + igbe->wbDelay);
+ return;
+ }
+
+ DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
+
for (int x = 0; x < wbOut; x++) {
assert(usedCache.size());
- memcpy(&wbBuf[x], usedCache[0], sizeof(T));
- delete usedCache[0];
- usedCache.pop_front();
+ memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+ igbe->anPq(annSmWb, annUsedCacheQ);
+ igbe->anPq(annSmWb, annDescQ);
+ igbe->anQ(annSmWb, annUsedDescQ);
}
+
+ igbe->anBegin(annSmWb, "Writeback Desc DMA");
assert(wbOut);
- igbe->dmaWrite(igbe->platform->pciToDma(descBase() + curHead * sizeof(T)),
- wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf);
+ igbe->dmaWrite(igbe->platform->pciToDma(descBase() + descHead() * sizeof(T)),
+ wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
+ igbe->wbCompDelay);
}
+ EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
/** Fetch a chunk of descriptors into the descriptor cache.
* Calls fetchComplete when the memory system returns the data
*/
+
void fetchDescriptors()
{
size_t max_to_fetch;
- if (curFetching)
+ if (curFetching) {
+ DPRINTF(EthernetDesc, "Currently fetching %d descriptors, returning\n", curFetching);
return;
+ }
if (descTail() >= cachePnt)
max_to_fetch = descTail() - cachePnt;
@@ -312,7 +387,20 @@ class IGbE : public EtherDevice
size_t free_cache = size - usedCache.size() - unusedCache.size();
+ if (!max_to_fetch)
+ igbe->anWe(annSmFetch, annUnusedDescQ);
+ else
+ igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
+
+ if (max_to_fetch) {
+ if (!free_cache)
+ igbe->anWf(annSmFetch, annDescQ);
+ else
+ igbe->anRq(annSmFetch, annDescQ, free_cache);
+ }
+
max_to_fetch = std::min(max_to_fetch, free_cache);
+
DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
"%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
@@ -322,31 +410,53 @@ class IGbE : public EtherDevice
// Nothing to do
if (max_to_fetch == 0)
return;
-
+
// So we don't have two descriptor fetches going on at once
curFetching = max_to_fetch;
+ assert(!fetchDelayEvent.scheduled());
+ igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+ igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
+ }
+
+ void fetchDescriptors1()
+ {
+ // If we're draining delay issuing this DMA
+ if (igbe->getState() != SimObject::Running) {
+ igbe->schedule(fetchDelayEvent, curTick + igbe->fetchDelay);
+ return;
+ }
+
+ igbe->anBegin(annSmFetch, "Fetch Desc");
+
DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
descBase() + cachePnt * sizeof(T),
igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
curFetching * sizeof(T));
assert(curFetching);
igbe->dmaRead(igbe->platform->pciToDma(descBase() + cachePnt * sizeof(T)),
- curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf);
+ curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
+ igbe->fetchCompDelay);
}
+ EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
/** Called by event when dma to read descriptors is completed
*/
void fetchComplete()
{
T *newDesc;
+ igbe->anBegin(annSmFetch, "Fetch Complete");
for (int x = 0; x < curFetching; x++) {
newDesc = new T;
memcpy(newDesc, &fetchBuf[x], sizeof(T));
unusedCache.push_back(newDesc);
+ igbe->anDq(annSmFetch, annUnusedDescQ);
+ igbe->anQ(annSmFetch, annUnusedCacheQ);
+ igbe->anQ(annSmFetch, annDescQ);
}
+
#ifndef NDEBUG
int oldCp = cachePnt;
#endif
@@ -361,6 +471,16 @@ class IGbE : public EtherDevice
DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
oldCp, cachePnt);
+ if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
+ cachePnt)) == 0)
+ {
+ igbe->anWe(annSmFetch, annUnusedDescQ);
+ } else if (!(size - usedCache.size() - unusedCache.size())) {
+ igbe->anWf(annSmFetch, annDescQ);
+ } else {
+ igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
+ }
+
enableSm();
igbe->checkDrain();
}
@@ -372,10 +492,21 @@ class IGbE : public EtherDevice
void wbComplete()
{
+ igbe->anBegin(annSmWb, "Finish Writeback");
+
long curHead = descHead();
#ifndef NDEBUG
long oldHead = curHead;
#endif
+
+ for (int x = 0; x < wbOut; x++) {
+ assert(usedCache.size());
+ delete usedCache[0];
+ usedCache.pop_front();
+
+ igbe->anDq(annSmWb, annUsedCacheQ);
+ igbe->anDq(annSmWb, annDescQ);
+ }
curHead += wbOut;
wbOut = 0;
@@ -390,14 +521,19 @@ class IGbE : public EtherDevice
oldHead, curHead);
// If we still have more to wb, call wb now
- intAfterWb();
+ actionAfterWb();
if (moreToWb) {
+ moreToWb = false;
DPRINTF(EthernetDesc, "Writeback has more todo\n");
writeback(wbAlignment);
}
if (!wbOut) {
igbe->checkDrain();
+ if (usedCache.size())
+ igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
+ else
+ igbe->anWe(annSmWb, annUsedCacheQ);
}
fetchAfterWb();
}
@@ -411,8 +547,8 @@ class IGbE : public EtherDevice
int descLeft() const
{
int left = unusedCache.size();
- if (cachePnt - descTail() >= 0)
- left += (cachePnt - descTail());
+ if (cachePnt >= descTail())
+ left += (descLen() - cachePnt + descTail());
else
left += (descTail() - cachePnt);
@@ -464,6 +600,16 @@ class IGbE : public EtherDevice
arrayParamOut(os, csprintf("unusedCache_%d", x),
(uint8_t*)unusedCache[x],sizeof(T));
}
+
+ Tick fetch_delay = 0, wb_delay = 0;
+ if (fetchDelayEvent.scheduled())
+ fetch_delay = fetchDelayEvent.when();
+ SERIALIZE_SCALAR(fetch_delay);
+ if (wbDelayEvent.scheduled())
+ wb_delay = wbDelayEvent.when();
+ SERIALIZE_SCALAR(wb_delay);
+
+
}
virtual void unserialize(Checkpoint *cp, const std::string &section)
@@ -492,6 +638,15 @@ class IGbE : public EtherDevice
(uint8_t*)temp,sizeof(T));
unusedCache.push_back(temp);
}
+ Tick fetch_delay = 0, wb_delay = 0;
+ UNSERIALIZE_SCALAR(fetch_delay);
+ UNSERIALIZE_SCALAR(wb_delay);
+ if (fetch_delay)
+ igbe->schedule(fetchDelayEvent, fetch_delay);
+ if (wb_delay)
+ igbe->schedule(wbDelayEvent, wb_delay);
+
+
}
virtual bool hasOutstandingEvents() {
return wbEvent.scheduled() || fetchEvent.scheduled();
@@ -516,6 +671,12 @@ class IGbE : public EtherDevice
bool pktDone;
+ /** Variable to head with header/data completion events */
+ int splitCount;
+
+ /** Bytes of packet that have been copied, so we know when to set EOP */
+ int bytesCopied;
+
public:
RxDescCache(IGbE *i, std::string n, int s);
@@ -523,20 +684,28 @@ class IGbE : public EtherDevice
* descriptor and update the book keeping. Should only be called when
* there are no dma's pending.
* @param packet ethernet packet to write
- * @return if the packet could be written (there was a free descriptor)
+ * @param pkt_offset bytes already copied from the packet to memory
+ * @return pkt_offset + number of bytes copied during this call
*/
- void writePacket(EthPacketPtr packet);
+ int writePacket(EthPacketPtr packet, int pkt_offset);
+
/** Called by event when dma to write packet is completed
*/
void pktComplete();
- /** Check if the dma on the packet has completed.
+ /** Check if the dma on the packet has completed and RX state machine
+ * can continue
*/
-
bool packetDone();
EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
+ // Event to handle issuing header and data write at the same time
+ // and only callking pktComplete() when both are completed
+ void pktSplitDone();
+ EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
+ EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
+
virtual bool hasOutstandingEvents();
virtual void serialize(std::ostream &os);
@@ -555,15 +724,37 @@ class IGbE : public EtherDevice
virtual long descLen() const { return igbe->regs.tdlen() >> 4; }
virtual void updateHead(long h) { igbe->regs.tdh(h); }
virtual void enableSm();
- virtual void intAfterWb() const { igbe->postInterrupt(iGbReg::IT_TXDW); }
+ virtual void actionAfterWb();
virtual void fetchAfterWb() {
if (!igbe->txTick && igbe->getState() == SimObject::Running)
fetchDescriptors();
}
+
+
bool pktDone;
bool isTcp;
bool pktWaiting;
+ bool pktMultiDesc;
+ Addr completionAddress;
+ bool completionEnabled;
+ uint32_t descEnd;
+
+
+ // tso variables
+ bool useTso;
+ Addr tsoHeaderLen;
+ Addr tsoMss;
+ Addr tsoTotalLen;
+ Addr tsoUsedLen;
+ Addr tsoPrevSeq;;
+ Addr tsoPktPayloadBytes;
+ bool tsoLoadedHeader;
+ bool tsoPktHasHeader;
+ uint8_t tsoHeader[256];
+ Addr tsoDescBytesUsed;
+ Addr tsoCopyBytes;
+ int tsoPkts;
public:
TxDescCache(IGbE *i, std::string n, int s);
@@ -572,9 +763,15 @@ class IGbE : public EtherDevice
* return the size the of the packet to reserve space in tx fifo.
* @return size of the packet
*/
- int getPacketSize();
+ int getPacketSize(EthPacketPtr p);
void getPacketData(EthPacketPtr p);
+ void processContextDesc();
+ /** Return the number of dsecriptors in a cache block for threshold
+ * operations.
+ */
+ int descInBlock(int num_desc) { return num_desc /
+ igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc); }
/** Ask if the packet has been transfered so the state machine can give
* it to the fifo.
* @return packet available in descriptor cache
@@ -586,13 +783,35 @@ class IGbE : public EtherDevice
*/
bool packetWaiting() { return pktWaiting; }
+ /** Ask if this packet is composed of multiple descriptors
+ * so even if we've got data, we need to wait for more before
+ * we can send it out.
+ * @return packet can't be sent out because it's a multi-descriptor
+ * packet
+ */
+ bool packetMultiDesc() { return pktMultiDesc;}
+
/** Called by event when dma to write packet is completed
*/
void pktComplete();
EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
+ void headerComplete();
+ EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
+
+
+ void completionWriteback(Addr a, bool enabled) {
+ DPRINTF(EthernetDesc, "Completion writeback Addr: %#x enabled: %d\n",
+ a, enabled);
+ completionAddress = a;
+ completionEnabled = enabled;
+ }
+
virtual bool hasOutstandingEvents();
+ void nullCallback() { DPRINTF(EthernetDesc, "Completion writeback complete\n"); }
+ EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
+
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
@@ -610,10 +829,12 @@ class IGbE : public EtherDevice
}
IGbE(const Params *params);
~IGbE() {}
+ virtual void init();
virtual EtherInt *getEthPort(const std::string &if_name, int idx);
Tick clock;
+ Tick lastInterrupt;
inline Tick ticks(int numCycles) const { return numCycles * clock; }
virtual Tick read(PacketPtr pkt);
diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh
index 91b3eacc9..4634dd9a3 100644
--- a/src/dev/i8254xGBe_defs.hh
+++ b/src/dev/i8254xGBe_defs.hh
@@ -59,11 +59,14 @@ const uint32_t REG_FCTTV = 0x00170;
const uint32_t REG_TIPG = 0x00410;
const uint32_t REG_AIFS = 0x00458;
const uint32_t REG_LEDCTL = 0x00e00;
+const uint32_t REG_EICR = 0x01580;
+const uint32_t REG_IVAR0 = 0x01700;
const uint32_t REG_FCRTL = 0x02160;
const uint32_t REG_FCRTH = 0x02168;
const uint32_t REG_RDBAL = 0x02800;
const uint32_t REG_RDBAH = 0x02804;
const uint32_t REG_RDLEN = 0x02808;
+const uint32_t REG_SRRCTL = 0x0280C;
const uint32_t REG_RDH = 0x02810;
const uint32_t REG_RDT = 0x02818;
const uint32_t REG_RDTR = 0x02820;
@@ -74,12 +77,17 @@ const uint32_t REG_TDBAL = 0x03800;
const uint32_t REG_TDBAH = 0x03804;
const uint32_t REG_TDLEN = 0x03808;
const uint32_t REG_TDH = 0x03810;
+const uint32_t REG_TXDCA_CTL = 0x03814;
const uint32_t REG_TDT = 0x03818;
const uint32_t REG_TIDV = 0x03820;
const uint32_t REG_TXDCTL = 0x03828;
const uint32_t REG_TADV = 0x0382C;
+const uint32_t REG_TDWBAL = 0x03838;
+const uint32_t REG_TDWBAH = 0x0383C;
const uint32_t REG_CRCERRS = 0x04000;
const uint32_t REG_RXCSUM = 0x05000;
+const uint32_t REG_RLPML = 0x05004;
+const uint32_t REG_RFCTL = 0x05008;
const uint32_t REG_MTA = 0x05200;
const uint32_t REG_RAL = 0x05400;
const uint32_t REG_RAH = 0x05404;
@@ -87,6 +95,9 @@ const uint32_t REG_VFTA = 0x05600;
const uint32_t REG_WUC = 0x05800;
const uint32_t REG_MANC = 0x05820;
+const uint32_t REG_SWSM = 0x05B50;
+const uint32_t REG_FWSM = 0x05B54;
+const uint32_t REG_SWFWSYNC = 0x05B5C;
const uint8_t EEPROM_READ_OPCODE_SPI = 0x03;
const uint8_t EEPROM_RDSR_OPCODE_SPI = 0x05;
@@ -94,9 +105,9 @@ const uint8_t EEPROM_SIZE = 64;
const uint16_t EEPROM_CSUM = 0xBABA;
const uint8_t VLAN_FILTER_TABLE_SIZE = 128;
-const uint8_t RCV_ADDRESS_TABLE_SIZE = 16;
+const uint8_t RCV_ADDRESS_TABLE_SIZE = 24;
const uint8_t MULTICAST_TABLE_SIZE = 128;
-const uint32_t STATS_REGS_SIZE = 0x124;
+const uint32_t STATS_REGS_SIZE = 0x228;
// Registers in that are accessed in the PHY
@@ -108,14 +119,17 @@ const uint8_t PHY_EPSTATUS = 15;
const uint8_t PHY_AGC = 18;
// Receive Descriptor Status Flags
-const uint8_t RXDS_PIF = 0x80;
-const uint8_t RXDS_IPCS = 0x40;
-const uint8_t RXDS_TCPCS = 0x20;
-const uint8_t RXDS_UDPCS = 0x10;
-const uint8_t RXDS_VP = 0x08;
-const uint8_t RXDS_IXSM = 0x04;
-const uint8_t RXDS_EOP = 0x02;
-const uint8_t RXDS_DD = 0x01;
+const uint16_t RXDS_DYNINT = 0x800;
+const uint16_t RXDS_UDPV = 0x400;
+const uint16_t RXDS_CRCV = 0x100;
+const uint16_t RXDS_PIF = 0x080;
+const uint16_t RXDS_IPCS = 0x040;
+const uint16_t RXDS_TCPCS = 0x020;
+const uint16_t RXDS_UDPCS = 0x010;
+const uint16_t RXDS_VP = 0x008;
+const uint16_t RXDS_IXSM = 0x004;
+const uint16_t RXDS_EOP = 0x002;
+const uint16_t RXDS_DD = 0x001;
// Receive Descriptor Error Flags
const uint8_t RXDE_RXE = 0x80;
@@ -125,6 +139,32 @@ const uint8_t RXDE_SEQ = 0x04;
const uint8_t RXDE_SE = 0x02;
const uint8_t RXDE_CE = 0x01;
+// Receive Descriptor Extended Error Flags
+const uint16_t RXDEE_HBO = 0x008;
+const uint16_t RXDEE_CE = 0x010;
+const uint16_t RXDEE_LE = 0x020;
+const uint16_t RXDEE_PE = 0x080;
+const uint16_t RXDEE_OSE = 0x100;
+const uint16_t RXDEE_USE = 0x200;
+const uint16_t RXDEE_TCPE = 0x400;
+const uint16_t RXDEE_IPE = 0x800;
+
+
+// Receive Descriptor Types
+const uint8_t RXDT_LEGACY = 0x00;
+const uint8_t RXDT_ADV_ONEBUF = 0x01;
+const uint8_t RXDT_ADV_SPLIT_A = 0x05;
+
+// Receive Descriptor Packet Types
+const uint16_t RXDP_IPV4 = 0x001;
+const uint16_t RXDP_IPV4E = 0x002;
+const uint16_t RXDP_IPV6 = 0x004;
+const uint16_t RXDP_IPV6E = 0x008;
+const uint16_t RXDP_TCP = 0x010;
+const uint16_t RXDP_UDP = 0x020;
+const uint16_t RXDP_SCTP = 0x040;
+const uint16_t RXDP_NFS = 0x080;
+
// Interrupt types
enum IntTypes
{
@@ -147,12 +187,38 @@ enum IntTypes
// Receive Descriptor struct
struct RxDesc {
- Addr buf;
- uint16_t len;
- uint16_t csum;
- uint8_t status;
- uint8_t errors;
- uint16_t vlan;
+ union {
+ struct {
+ Addr buf;
+ uint16_t len;
+ uint16_t csum;
+ uint8_t status;
+ uint8_t errors;
+ uint16_t vlan;
+ } legacy;
+ struct {
+ Addr pkt;
+ Addr hdr;
+ } adv_read;
+ struct {
+ uint16_t rss_type:4;
+ uint16_t pkt_type:12;
+ uint16_t __reserved1:5;
+ uint16_t header_len:10;
+ uint16_t sph:1;
+ union {
+ struct {
+ uint16_t id;
+ uint16_t csum;
+ };
+ uint32_t rss_hash;
+ };
+ uint32_t status:20;
+ uint32_t errors:12;
+ uint16_t pkt_len;
+ uint16_t vlan_tag;
+ } adv_wb ;
+ };
};
struct TxDesc {
@@ -163,24 +229,33 @@ struct TxDesc {
namespace TxdOp {
const uint8_t TXD_CNXT = 0x0;
const uint8_t TXD_DATA = 0x1;
+const uint8_t TXD_ADVCNXT = 0x2;
+const uint8_t TXD_ADVDATA = 0x3;
bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); }
uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); }
-bool isContext(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_CNXT; }
-bool isData(TxDesc *d) { return !isLegacy(d) && getType(d) == TXD_DATA; }
+bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; }
+bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); }
+bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT); }
+bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); }
+bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); }
Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
-void setDd(TxDesc *d)
-{
- replaceBits(d->d2, 35, 32, ULL(1));
-}
+void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
-bool ide(TxDesc *d) { return bits(d->d2, 31,31); }
+bool ide(TxDesc *d) { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); }
bool vle(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
bool rs(TxDesc *d) { return bits(d->d2, 27,27); }
bool ic(TxDesc *d) { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
-bool tse(TxDesc *d) { return (isData(d) || isContext(d)) && bits(d->d2, 26,26); }
+bool tse(TxDesc *d) {
+ if (isTypes(d, TXD_CNXT, TXD_DATA))
+ return bits(d->d2, 26,26);
+ if (isType(d, TXD_ADVDATA))
+ return bits(d->d2, 31, 31);
+ return false;
+}
+
bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
bool eop(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
bool ip(TxDesc *d) { assert(isContext(d)); return bits(d->d2, 25,25); }
@@ -199,7 +274,15 @@ int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
-int hdrlen(TxDesc *d) { assert(isContext(d)); return bits(d->d2,47,40); }
+int hdrlen(TxDesc *d) {
+ assert(isContext(d));
+ if (!isAdvDesc(d))
+ return bits(d->d2,47,40);
+ return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9);
+}
+
+int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); }
+int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); }
} // namespace TxdOp
@@ -303,8 +386,8 @@ struct Regs {
struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(start,0,1); // start read
- ADD_FIELD32(done,4,1); // done read
- ADD_FIELD32(addr,8,8); // address
+ ADD_FIELD32(done,1,1); // done read
+ ADD_FIELD32(addr,2,14); // address
ADD_FIELD32(data,16,16); // data
};
EERD eerd;
@@ -470,6 +553,17 @@ struct Regs {
};
RDLEN rdlen;
+ struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(pktlen, 0, 8);
+ ADD_FIELD32(hdrlen, 8, 8); // guess based on header, not documented
+ ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv,
+ //101 hdr split
+ int bufLen() { return pktlen() << 10; }
+ int hdrLen() { return hdrlen() << 6; }
+ };
+ SRRCTL srrctl;
+
struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(rdh,0,16); // head of the descriptor ring
@@ -531,6 +625,14 @@ struct Regs {
};
TDH tdh;
+ struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(cpu_mask, 0, 5);
+ ADD_FIELD32(enabled, 5,1);
+ ADD_FIELD32(relax_ordering, 6, 1);
+ };
+ TXDCA_CTL txdca_ctl;
+
struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
@@ -563,15 +665,42 @@ struct Regs {
ADD_FIELD32(idv,0,16); // absolute interrupt delay
};
TADV tadv;
+/*
+ struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register
+ using Reg<uint64_t>::operator=;
+ ADD_FIELD64(en,0,1); // enable transmit description ring address writeback
+ ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback
+ ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring
+ };
+ TDWBA tdwba;*/
+ uint64_t tdwba;
struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(pcss,0,8);
ADD_FIELD32(ipofld,8,1);
ADD_FIELD32(tuofld,9,1);
+ ADD_FIELD32(pcsd, 13,1);
};
RXCSUM rxcsum;
+ uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size
+
+ struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(iscsi_dis,0,1);
+ ADD_FIELD32(iscsi_dwc,1,5);
+ ADD_FIELD32(nfsw_dis,6,1);
+ ADD_FIELD32(nfsr_dis,7,1);
+ ADD_FIELD32(nfs_ver,8,2);
+ ADD_FIELD32(ipv6_dis,10,1);
+ ADD_FIELD32(ipv6xsum_dis,11,1);
+ ADD_FIELD32(ackdis,13,1);
+ ADD_FIELD32(ipfrsp_dis,14,1);
+ ADD_FIELD32(exsten,15,1);
+ };
+ RFCTL rfctl;
+
struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
using Reg<uint32_t>::operator=;
ADD_FIELD32(smbus,0,1); // SMBus enabled #####
@@ -604,6 +733,32 @@ struct Regs {
};
MANC manc;
+ struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(smbi,0,1); // Semaphone bit
+ ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore
+ ADD_FIELD32(wmng, 2,1); // Wake MNG clock
+ ADD_FIELD32(reserved, 3, 29);
+ };
+ SWSM swsm;
+
+ struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register
+ using Reg<uint32_t>::operator=;
+ ADD_FIELD32(eep_fw_semaphore,0,1);
+ ADD_FIELD32(fw_mode, 1,3);
+ ADD_FIELD32(ide, 4,1);
+ ADD_FIELD32(sol, 5,1);
+ ADD_FIELD32(eep_roload, 6,1);
+ ADD_FIELD32(reserved, 7,8);
+ ADD_FIELD32(fw_val_bit, 15, 1);
+ ADD_FIELD32(reset_cnt, 16, 3);
+ ADD_FIELD32(ext_err_ind, 19, 6);
+ ADD_FIELD32(reserved2, 25, 7);
+ };
+ FWSM fwsm;
+
+ uint32_t sw_fw_sync;
+
void serialize(std::ostream &os)
{
paramOut(os, "ctrl", ctrl._data);
@@ -624,6 +779,7 @@ struct Regs {
paramOut(os, "fcrth", fcrth._data);
paramOut(os, "rdba", rdba._data);
paramOut(os, "rdlen", rdlen._data);
+ paramOut(os, "srrctl", srrctl._data);
paramOut(os, "rdh", rdh._data);
paramOut(os, "rdt", rdt._data);
paramOut(os, "rdtr", rdtr._data);
@@ -633,12 +789,20 @@ struct Regs {
paramOut(os, "tdba", tdba._data);
paramOut(os, "tdlen", tdlen._data);
paramOut(os, "tdh", tdh._data);
+ paramOut(os, "txdca_ctl", txdca_ctl._data);
paramOut(os, "tdt", tdt._data);
paramOut(os, "tidv", tidv._data);
paramOut(os, "txdctl", txdctl._data);
paramOut(os, "tadv", tadv._data);
+ //paramOut(os, "tdwba", tdwba._data);
+ SERIALIZE_SCALAR(tdwba);
paramOut(os, "rxcsum", rxcsum._data);
+ SERIALIZE_SCALAR(rlpml);
+ paramOut(os, "rfctl", rfctl._data);
paramOut(os, "manc", manc._data);
+ paramOut(os, "swsm", swsm._data);
+ paramOut(os, "fwsm", fwsm._data);
+ SERIALIZE_SCALAR(sw_fw_sync);
}
void unserialize(Checkpoint *cp, const std::string &section)
@@ -661,6 +825,7 @@ struct Regs {
paramIn(cp, section, "fcrth", fcrth._data);
paramIn(cp, section, "rdba", rdba._data);
paramIn(cp, section, "rdlen", rdlen._data);
+ paramIn(cp, section, "srrctl", srrctl._data);
paramIn(cp, section, "rdh", rdh._data);
paramIn(cp, section, "rdt", rdt._data);
paramIn(cp, section, "rdtr", rdtr._data);
@@ -670,12 +835,20 @@ struct Regs {
paramIn(cp, section, "tdba", tdba._data);
paramIn(cp, section, "tdlen", tdlen._data);
paramIn(cp, section, "tdh", tdh._data);
+ paramIn(cp, section, "txdca_ctl", txdca_ctl._data);
paramIn(cp, section, "tdt", tdt._data);
paramIn(cp, section, "tidv", tidv._data);
paramIn(cp, section, "txdctl", txdctl._data);
paramIn(cp, section, "tadv", tadv._data);
+ UNSERIALIZE_SCALAR(tdwba);
+ //paramIn(cp, section, "tdwba", tdwba._data);
paramIn(cp, section, "rxcsum", rxcsum._data);
+ UNSERIALIZE_SCALAR(rlpml);
+ paramIn(cp, section, "rfctl", rfctl._data);
paramIn(cp, section, "manc", manc._data);
+ paramIn(cp, section, "swsm", swsm._data);
+ paramIn(cp, section, "fwsm", fwsm._data);
+ UNSERIALIZE_SCALAR(sw_fw_sync);
}
};
} // iGbReg namespace
diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc
index 6d7f1baf1..3d4e71888 100644
--- a/src/dev/ide_ctrl.cc
+++ b/src/dev/ide_ctrl.cc
@@ -30,203 +30,114 @@
* Miguel Serrano
*/
-#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 "mem/packet_access.hh"
#include "params/IdeController.hh"
-#include "sim/sim_object.hh"
#include "sim/byteswap.hh"
using namespace std;
-////
-// Initialization and destruction
-////
-
-IdeController::IdeController(Params *p)
- : PciDev(p)
+// Bus master IDE registers
+enum BMIRegOffset {
+ BMICommand = 0x0,
+ BMIStatus = 0x2,
+ BMIDescTablePtr = 0x4
+};
+
+// PCI config space registers
+enum ConfRegOffset {
+ PrimaryTiming = 0x40,
+ SecondaryTiming = 0x42,
+ DeviceTiming = 0x44,
+ UDMAControl = 0x48,
+ UDMATiming = 0x4A,
+ IDEConfig = 0x54
+};
+
+static const uint16_t timeRegWithDecodeEn = 0x8000;
+
+IdeController::Channel::Channel(
+ string newName, Addr _cmdSize, Addr _ctrlSize) :
+ _name(newName),
+ cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
+ master(NULL), slave(NULL), selected(NULL)
{
- // 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);
- }
+ memset(&bmiRegs, 0, sizeof(bmiRegs));
+ bmiRegs.status.dmaCap0 = 1;
+ bmiRegs.status.dmaCap1 = 1;
}
-IdeController::~IdeController()
+IdeController::Channel::~Channel()
{
- for (int i = 0; i < 4; i++)
- if (disks[i])
- delete disks[i];
+ delete master;
+ delete slave;
}
-////
-// Utility functions
-///
-
-void
-IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
- IdeRegType &reg_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)
+IdeController::IdeController(Params *p)
+ : PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
+ secondary(name() + ".secondary", BARSize[2], BARSize[3]),
+ bmiAddr(0), bmiSize(BARSize[4]),
+ primaryTiming(htole(timeRegWithDecodeEn)),
+ secondaryTiming(htole(timeRegWithDecodeEn)),
+ deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
+ ioEnabled(false), bmEnabled(false)
{
- int disk = 0;
- uint8_t *devBit = &dev[0];
-
- if (channel == SECONDARY) {
- disk += 2;
- devBit = &dev[1];
- }
-
- disk += *devBit;
+ if (params()->disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
- assert(*devBit == 0 || *devBit == 1);
+ // Assign the disks to channels
+ int numDisks = params()->disks.size();
+ if (numDisks > 0)
+ primary.master = params()->disks[0];
+ if (numDisks > 1)
+ primary.slave = params()->disks[1];
+ if (numDisks > 2)
+ secondary.master = params()->disks[2];
+ if (numDisks > 3)
+ secondary.slave = params()->disks[3];
- return disk;
-}
-
-int
-IdeController::getDisk(IdeDisk *diskPtr)
-{
- for (int i = 0; i < 4; i++) {
- if ((long)diskPtr == (long)disks[i])
- return i;
+ for (int i = 0; i < params()->disks.size(); i++) {
+ params()->disks[i]->setController(this);
}
- return -1;
+ primary.select(false);
+ secondary.select(false);
}
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");
+ return (primary.selected == diskPtr || secondary.selected == diskPtr);
}
-////
-// Command completion
-////
+void
+IdeController::intrPost()
+{
+ primary.bmiRegs.status.intStatus = 1;
+ PciDev::intrPost();
+}
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;
+ Channel *channel;
+ if (disk == primary.master || disk == primary.slave) {
+ channel = &primary;
+ } else if (disk == secondary.master || disk == secondary.slave) {
+ channel = &secondary;
} 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;
+ panic("Unable to find disk based on pointer %#x\n", disk);
}
-}
-
-////
-// Read and write handling
-////
+ channel->bmiRegs.command.startStop = 0;
+ channel->bmiRegs.status.active = 0;
+ channel->bmiRegs.status.intStatus = 1;
+}
Tick
IdeController::readConfig(PacketPtr pkt)
@@ -236,30 +147,28 @@ IdeController::readConfig(PacketPtr pkt)
return PciDev::readConfig(pkt);
}
- assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
-
pkt->allocate();
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
- case IDE_CTRL_CONF_DEV_TIMING:
- pkt->set<uint8_t>(config_regs.sidetim);
+ case DeviceTiming:
+ pkt->set<uint8_t>(deviceTiming);
break;
- case IDE_CTRL_CONF_UDMA_CNTRL:
- pkt->set<uint8_t>(config_regs.udmactl);
+ case UDMAControl:
+ pkt->set<uint8_t>(udmaControl);
break;
- case IDE_CTRL_CONF_PRIM_TIMING+1:
- pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);
+ case PrimaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
break;
- case IDE_CTRL_CONF_SEC_TIMING+1:
- pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);
+ case SecondaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);
+ case IDEConfig:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
break;
- case IDE_CTRL_CONF_IDE_CONFIG+1:
- pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);
+ case IDEConfig + 1:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
break;
default:
panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
@@ -270,17 +179,17 @@ IdeController::readConfig(PacketPtr pkt)
break;
case sizeof(uint16_t):
switch (offset) {
- case IDE_CTRL_CONF_PRIM_TIMING:
- pkt->set<uint16_t>(config_regs.idetim0);
+ case PrimaryTiming:
+ pkt->set<uint16_t>(primaryTiming);
break;
- case IDE_CTRL_CONF_SEC_TIMING:
- pkt->set<uint16_t>(config_regs.idetim1);
+ case SecondaryTiming:
+ pkt->set<uint16_t>(secondaryTiming);
break;
- case IDE_CTRL_CONF_UDMA_TIMING:
- pkt->set<uint16_t>(config_regs.udmatim);
+ case UDMATiming:
+ pkt->set<uint16_t>(udmaTiming);
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- pkt->set<uint16_t>(config_regs.ideconfig);
+ case IDEConfig:
+ pkt->set<uint16_t>(ideConfig);
break;
default:
panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
@@ -309,48 +218,45 @@ IdeController::writeConfig(PacketPtr pkt)
if (offset < PCI_DEVICE_SPECIFIC) {
PciDev::writeConfig(pkt);
} else {
- assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);
-
switch (pkt->getSize()) {
case sizeof(uint8_t):
switch (offset) {
- case IDE_CTRL_CONF_DEV_TIMING:
- config_regs.sidetim = pkt->get<uint8_t>();
+ case DeviceTiming:
+ deviceTiming = pkt->get<uint8_t>();
break;
- case IDE_CTRL_CONF_UDMA_CNTRL:
- config_regs.udmactl = pkt->get<uint8_t>();
+ case UDMAControl:
+ udmaControl = pkt->get<uint8_t>();
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |
- (pkt->get<uint8_t>());
+ case IDEConfig:
+ replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
break;
- case IDE_CTRL_CONF_IDE_CONFIG+1:
- config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |
- pkt->get<uint8_t>() << 8;
+ case IDEConfig + 1:
+ replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
break;
default:
- panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
- offset);
+ panic("Invalid PCI configuration write "
+ "for size 1 offset: %#x!\n", offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
offset, (uint32_t)pkt->get<uint8_t>());
break;
case sizeof(uint16_t):
switch (offset) {
- case IDE_CTRL_CONF_PRIM_TIMING:
- config_regs.idetim0 = pkt->get<uint16_t>();
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_SEC_TIMING:
- config_regs.idetim1 = pkt->get<uint16_t>();
+ case SecondaryTiming:
+ secondaryTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_UDMA_TIMING:
- config_regs.udmatim = pkt->get<uint16_t>();
+ case UDMATiming:
+ udmaTiming = pkt->get<uint16_t>();
break;
- case IDE_CTRL_CONF_IDE_CONFIG:
- config_regs.ideconfig = pkt->get<uint16_t>();
+ case IDEConfig:
+ ideConfig = pkt->get<uint16_t>();
break;
default:
- panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
+ panic("Invalid PCI configuration write "
+ "for size 2 offset: %#x!\n",
offset);
}
DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
@@ -370,317 +276,223 @@ IdeController::writeConfig(PacketPtr pkt)
switch(offset) {
case PCI0_BASE_ADDR0:
if (BARAddrs[0] != 0)
- pri_cmd_addr = BARAddrs[0];
+ primary.cmdAddr = BARAddrs[0];
break;
case PCI0_BASE_ADDR1:
if (BARAddrs[1] != 0)
- pri_ctrl_addr = BARAddrs[1];
+ primary.ctrlAddr = BARAddrs[1];
break;
case PCI0_BASE_ADDR2:
if (BARAddrs[2] != 0)
- sec_cmd_addr = BARAddrs[2];
+ secondary.cmdAddr = BARAddrs[2];
break;
case PCI0_BASE_ADDR3:
if (BARAddrs[3] != 0)
- sec_ctrl_addr = BARAddrs[3];
+ secondary.ctrlAddr = BARAddrs[3];
break;
case PCI0_BASE_ADDR4:
if (BARAddrs[4] != 0)
- bmi_addr = BARAddrs[4];
+ bmiAddr = BARAddrs[4];
break;
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;
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
break;
}
return configDelay;
}
-
-Tick
-IdeController::read(PacketPtr pkt)
+void
+IdeController::Channel::accessCommand(Addr offset,
+ int size, uint8_t *data, bool read)
{
- Addr offset;
- IdeChannel channel;
- IdeRegType reg_type;
- int disk;
-
- 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->makeAtomicResponse();
- 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);
+ const Addr SelectOffset = 6;
+ const uint8_t SelectDevBit = 0x10;
- if (disks[disk] == NULL) {
- pkt->set<uint8_t>(0);
- break;
- }
+ if (!read && offset == SelectOffset)
+ select(*data & SelectDevBit);
- 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 (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readCommand(offset, size, data);
+ } else {
+ selected->writeCommand(offset, size, data);
}
- 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->makeAtomicResponse();
- return pioDelay;
}
-Tick
-IdeController::write(PacketPtr pkt)
+void
+IdeController::Channel::accessControl(Addr offset,
+ int size, uint8_t *data, bool read)
{
- Addr offset;
- IdeChannel channel;
- IdeRegType reg_type;
- int disk;
- uint8_t oldVal, newVal;
-
- parseAddr(pkt->getAddr(), offset, channel, reg_type);
-
- if (!io_enabled) {
- pkt->makeAtomicResponse();
- DPRINTF(IdeCtrl, "io not enabled\n");
- return pioDelay;
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readControl(offset, size, data);
+ } else {
+ selected->writeControl(offset, size, data);
}
+}
- switch (reg_type) {
- case BMI_BLOCK:
- if (!bm_enabled) {
- pkt->makeAtomicResponse();
- return pioDelay;
- }
-
+void
+IdeController::Channel::accessBMI(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ assert(offset + size <= sizeof(BMIRegs));
+ if (read) {
+ memcpy(data, (uint8_t *)&bmiRegs + offset, size);
+ } else {
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");
+ case BMICommand:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", size);
- // clear the BMIDEA bit
- bmi_regs.chan[channel].bmis =
- bmi_regs.chan[channel].bmis & ~BMIDEA;
+ BMICommandReg oldVal = bmiRegs.command;
+ BMICommandReg newVal = *data;
- if (disks[disk] == NULL)
- panic("DMA stop for disk %d which does not exist\n",
- disk);
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal.startStop && oldVal.rw != newVal.rw)
+ oldVal.rw = newVal.rw;
- // inform the disk of the DMA transfer abort
- disks[disk]->abortDma();
- } else {
- // starting DMA transfer
- DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ if (oldVal.startStop != newVal.startStop) {
+ if (selected == NULL)
+ panic("DMA start for disk which does not exist\n");
- // set the BMIDEA bit
- bmi_regs.chan[channel].bmis =
- bmi_regs.chan[channel].bmis | BMIDEA;
+ if (oldVal.startStop) {
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+ bmiRegs.status.active = 0;
- if (disks[disk] == NULL)
- panic("DMA start for disk %d which does not exist\n",
- disk);
+ selected->abortDma();
+ } else {
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ bmiRegs.status.active = 1;
- // inform the disk of the DMA transfer start
- disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
+ selected->startDma(letoh(bmiRegs.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;
+ bmiRegs.command = newVal;
+ }
break;
-
- // Bus master IDE descriptor table pointer register
- case BMIDTP0:
- case BMIDTP1:
+ case BMIStatus:
{
- 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);
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIS write size: %x\n", size);
+
+ BMIStatusReg oldVal = bmiRegs.status;
+ BMIStatusReg newVal = *data;
+
+ // the BMIDEA bit is read only
+ newVal.active = oldVal.active;
+
+ // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
+ if (oldVal.intStatus && newVal.intStatus)
+ newVal.intStatus = 0; // clear the interrupt?
+ else
+ newVal.intStatus = oldVal.intStatus;
+ if (oldVal.dmaError && newVal.dmaError)
+ newVal.dmaError = 0;
+ else
+ newVal.dmaError = oldVal.dmaError;
+
+ bmiRegs.status = newVal;
}
break;
-
+ case BMIDescTablePtr:
+ if (size != sizeof(uint32_t))
+ panic("Invalid BMIDTP write size: %x\n", size);
+ bmiRegs.bmidtp = htole(*(uint32_t *)data & ~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());
+ if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
+ size != sizeof(uint32_t))
+ panic("IDE controller write of invalid write size: %x\n", size);
+ memcpy((uint8_t *)&bmiRegs + offset, data, size);
}
- 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;
+void
+IdeController::dispatchAccess(PacketPtr pkt, bool read)
+{
+ pkt->allocate();
+ if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
+ panic("Bad IDE read size: %d\n", pkt->getSize());
- switch (offset) {
- case DATA_OFFSET:
- switch (pkt->getSize()) {
- case sizeof(uint16_t):
- disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
- break;
+ if (!ioEnabled) {
+ pkt->makeAtomicResponse();
+ DPRINTF(IdeCtrl, "io not enabled\n");
+ return;
+ }
- 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());
+ Addr addr = pkt->getAddr();
+ int size = pkt->getSize();
+ uint8_t *dataPtr = pkt->getPtr<uint8_t>();
+
+ if (addr >= primary.cmdAddr &&
+ addr < (primary.cmdAddr + primary.cmdSize)) {
+ addr -= primary.cmdAddr;
+ primary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= primary.ctrlAddr &&
+ addr < (primary.ctrlAddr + primary.ctrlSize)) {
+ addr -= primary.ctrlAddr;
+ primary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= secondary.cmdAddr &&
+ addr < (secondary.cmdAddr + secondary.cmdSize)) {
+ addr -= secondary.cmdAddr;
+ secondary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= secondary.ctrlAddr &&
+ addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
+ addr -= secondary.ctrlAddr;
+ secondary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
+ if (!read && !bmEnabled)
+ return;
+ addr -= bmiAddr;
+ if (addr < sizeof(Channel::BMIRegs)) {
+ primary.accessBMI(addr, size, dataPtr, read);
+ } else {
+ addr -= sizeof(Channel::BMIRegs);
+ secondary.accessBMI(addr, size, dataPtr, read);
}
- break;
- default:
- panic("IDE controller write of unknown register block type!\n");
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
}
+ uint32_t data;
if (pkt->getSize() == 1)
- DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
+ data = 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>());
+ data = pkt->get<uint16_t>();
else
- DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
- offset, pkt->getSize(), pkt->get<uint32_t>());
-
+ data = pkt->get<uint32_t>();
+ DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
+ read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
pkt->makeAtomicResponse();
+}
+
+Tick
+IdeController::read(PacketPtr pkt)
+{
+ dispatchAccess(pkt, true);
return pioDelay;
}
-////
-// Serialization
-////
+Tick
+IdeController::write(PacketPtr pkt)
+{
+ dispatchAccess(pkt, false);
+ return pioDelay;
+}
void
IdeController::serialize(std::ostream &os)
@@ -688,30 +500,40 @@ 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 channels
+ primary.serialize("primary", os);
+ secondary.serialize("secondary", os);
+
+ // Serialize config registers
+ SERIALIZE_SCALAR(primaryTiming);
+ SERIALIZE_SCALAR(secondaryTiming);
+ SERIALIZE_SCALAR(deviceTiming);
+ SERIALIZE_SCALAR(udmaControl);
+ SERIALIZE_SCALAR(udmaTiming);
+ SERIALIZE_SCALAR(ideConfig);
// 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]));
+ SERIALIZE_SCALAR(ioEnabled);
+ SERIALIZE_SCALAR(bmEnabled);
+ SERIALIZE_SCALAR(bmiAddr);
+ SERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::serialize(const std::string &base, std::ostream &os)
+{
+ paramOut(os, base + ".cmdAddr", cmdAddr);
+ paramOut(os, base + ".cmdSize", cmdSize);
+ paramOut(os, base + ".ctrlAddr", ctrlAddr);
+ paramOut(os, base + ".ctrlSize", ctrlSize);
+ uint8_t command = bmiRegs.command;
+ paramOut(os, base + ".bmiRegs.command", command);
+ paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status = bmiRegs.status;
+ paramOut(os, base + ".bmiRegs.status", status);
+ paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramOut(os, base + ".selectBit", selectBit);
}
void
@@ -720,30 +542,44 @@ IdeController::unserialize(Checkpoint *cp, const std::string &section)
// 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 channels
+ primary.unserialize("primary", cp, section);
+ secondary.unserialize("secondary", cp, section);
+
+ // Unserialize config registers
+ UNSERIALIZE_SCALAR(primaryTiming);
+ UNSERIALIZE_SCALAR(secondaryTiming);
+ UNSERIALIZE_SCALAR(deviceTiming);
+ UNSERIALIZE_SCALAR(udmaControl);
+ UNSERIALIZE_SCALAR(udmaTiming);
+ UNSERIALIZE_SCALAR(ideConfig);
// 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]));
+ UNSERIALIZE_SCALAR(ioEnabled);
+ UNSERIALIZE_SCALAR(bmEnabled);
+ UNSERIALIZE_SCALAR(bmiAddr);
+ UNSERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section)
+{
+ paramIn(cp, section, base + ".cmdAddr", cmdAddr);
+ paramIn(cp, section, base + ".cmdSize", cmdSize);
+ paramIn(cp, section, base + ".ctrlAddr", ctrlAddr);
+ paramIn(cp, section, base + ".ctrlSize", ctrlSize);
+ uint8_t command;
+ paramIn(cp, section, base +".bmiRegs.command", command);
+ bmiRegs.command = command;
+ paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status;
+ paramIn(cp, section, base + ".bmiRegs.status", status);
+ bmiRegs.status = status;
+ paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramIn(cp, section, base + ".selectBit", selectBit);
+ select(selectBit);
}
IdeController *
diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh
index f22d83e9c..89dc1ee9d 100644
--- a/src/dev/ide_ctrl.hh
+++ b/src/dev/ide_ctrl.hh
@@ -37,61 +37,13 @@
#ifndef __IDE_CTRL_HH__
#define __IDE_CTRL_HH__
+#include "base/bitunion.hh"
#include "dev/pcidev.hh"
#include "dev/pcireg.h"
#include "dev/io_device.hh"
#include "params/IdeController.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
@@ -99,137 +51,109 @@ class Platform;
class IdeController : public PciDev
{
- friend class IdeDisk;
+ private:
+ // Bus master IDE status register bit fields
+ BitUnion8(BMIStatusReg)
+ Bitfield<6> dmaCap0;
+ Bitfield<5> dmaCap1;
+ Bitfield<2> intStatus;
+ Bitfield<1> dmaError;
+ Bitfield<0> active;
+ EndBitUnion(BMIStatusReg)
+
+ BitUnion8(BMICommandReg)
+ Bitfield<3> rw;
+ Bitfield<0> startStop;
+ EndBitUnion(BMICommandReg)
+
+ struct Channel
+ {
+ std::string _name;
+
+ const std::string
+ name()
+ {
+ return _name;
+ }
+
+ /** Command and control block registers */
+ Addr cmdAddr, cmdSize, ctrlAddr, ctrlSize;
+
+ /** Registers used for bus master interface */
+ struct BMIRegs
+ {
+ BMICommandReg command;
+ uint8_t reserved0;
+ BMIStatusReg status;
+ uint8_t reserved1;
+ uint32_t bmidtp;
+ } bmiRegs;
- enum IdeChannel {
- PRIMARY = 0,
- SECONDARY = 1
- };
+ /** IDE disks connected to this controller */
+ IdeDisk *master, *slave;
- 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;
+ /** Currently selected disk */
+ IdeDisk *selected;
- 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];
+ bool selectBit;
- } 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;
+ void
+ select(bool selSlave)
+ {
+ selectBit = selSlave;
+ selected = selectBit ? slave : master;
+ }
- // Internal management variables
- bool io_enabled;
- bool bm_enabled;
- bool cmd_in_progress[4];
+ void accessCommand(Addr offset, int size, uint8_t *data, bool read);
+ void accessControl(Addr offset, int size, uint8_t *data, bool read);
+ void accessBMI(Addr offset, int size, uint8_t *data, bool read);
- private:
- /** IDE disks connected to controller */
- IdeDisk *disks[4];
+ Channel(std::string newName, Addr _cmdSize, Addr _ctrlSize);
+ ~Channel();
- private:
- /** Parse the access address to pass on to device */
- void parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
- IdeRegType &reg_type);
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
- /** Select the disk based on the channel and device bit */
- int getDisk(IdeChannel channel);
+ Channel primary;
+ Channel secondary;
- /** Select the disk based on a pointer */
- int getDisk(IdeDisk *diskPtr);
+ /** Bus master interface (BMI) registers */
+ Addr bmiAddr, bmiSize;
- public:
- /** See if a disk is selected based on its pointer */
- bool isDiskSelected(IdeDisk *diskPtr);
+ /** Registers used in device specific PCI configuration */
+ uint16_t primaryTiming, secondaryTiming;
+ uint8_t deviceTiming;
+ uint8_t udmaControl;
+ uint16_t udmaTiming;
+ uint16_t ideConfig;
+
+ // Internal management variables
+ bool ioEnabled;
+ bool bmEnabled;
+
+ void dispatchAccess(PacketPtr pkt, bool read);
public:
typedef IdeControllerParams Params;
const Params *params() const { return (const Params *)_params; }
IdeController(Params *p);
- ~IdeController();
- virtual Tick writeConfig(PacketPtr pkt);
- virtual Tick readConfig(PacketPtr pkt);
+ /** See if a disk is selected based on its pointer */
+ bool isDiskSelected(IdeDisk *diskPtr);
+
+ void intrPost();
+
+ Tick writeConfig(PacketPtr pkt);
+ Tick readConfig(PacketPtr pkt);
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(PacketPtr 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(PacketPtr 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 &section);
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
};
#endif // __IDE_CTRL_HH_
diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc
index 8f9999beb..83faf508e 100644
--- a/src/dev/ide_disk.cc
+++ b/src/dev/ide_disk.cc
@@ -177,7 +177,7 @@ Addr
IdeDisk::pciToDma(Addr pciAddr)
{
if (ctrl)
- return ctrl->plat->pciToDma(pciAddr);
+ return ctrl->pciToDma(pciAddr);
else
panic("Access to unset controller!\n");
}
@@ -187,120 +187,127 @@ IdeDisk::pciToDma(Addr pciAddr)
////
void
-IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
+IdeDisk::readCommand(const Addr offset, int size, 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);
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ } else if (size == sizeof(uint32_t)) {
+ *(uint16_t *)data = cmdReg.data;
+ updateState(ACT_DATA_READ_SHORT);
+ *((uint16_t *)data + 1) = cmdReg.data;
+ } else {
+ panic("Data read of unsupported size %d.\n", size);
}
+ updateState(ACT_DATA_READ_SHORT);
+ return;
+ }
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case ERROR_OFFSET:
+ *data = cmdReg.error;
break;
- case CONTROL_BLOCK:
- if (offset == ALTSTAT_OFFSET)
- *data = status;
- else
- panic("Invalid IDE control register offset: %#x\n", offset);
+ 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;
+ updateState(ACT_STAT_READ);
break;
default:
- panic("Unknown register block!\n");
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
- DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,
- (uint32_t)*data);
-
- if (action != ACT_NONE)
- updateState(action);
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
}
void
-IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
+IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
{
- DevAction_t action = ACT_NONE;
+ assert(size == sizeof(uint8_t));
+ *data = status;
+ if (offset != ALTSTAT_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+ DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
+}
- 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);
+void
+IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset == DATA_OFFSET) {
+ if (size == sizeof(uint16_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ } else if (size == sizeof(uint32_t)) {
+ cmdReg.data = *(const uint16_t *)data;
+ updateState(ACT_DATA_WRITE_SHORT);
+ cmdReg.data = *((const uint16_t *)data + 1);
+ } else {
+ panic("Data write of unsupported size %d.\n", size);
}
+ updateState(ACT_DATA_WRITE_SHORT);
+ return;
+ }
+
+ assert(size == sizeof(uint8_t));
+ switch (offset) {
+ case FEATURES_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);
+ 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;
+ updateState(ACT_SELECT_WRITE);
+ break;
+ case COMMAND_OFFSET:
+ cmdReg.command = *data;
+ updateState(ACT_CMD_WRITE);
break;
default:
- panic("Unknown register block!\n");
+ panic("Invalid IDE command register offset: %#x\n", offset);
}
+ DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
+ (uint32_t)*data);
+}
+
+void
+IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
+{
+ if (offset != CONTROL_OFFSET)
+ panic("Invalid IDE control register offset: %#x\n", offset);
+
+ if (*data & CONTROL_RST_BIT) {
+ // force the device into the reset state
+ devState = Device_Srst;
+ updateState(ACT_SRST_SET);
+ } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
+ updateState(ACT_SRST_CLEAR);
+ }
+
+ nIENBit = *data & CONTROL_IEN_BIT;
DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
(uint32_t)*data);
- if (action != ACT_NONE)
- updateState(action);
}
////
@@ -315,7 +322,7 @@ IdeDisk::doDmaTransfer()
dmaState, devState);
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaTransferEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else
ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
@@ -349,7 +356,7 @@ IdeDisk::doDmaDataRead()
DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
diskDelay, totalDiskDelay);
- dmaReadWaitEvent.schedule(curTick + totalDiskDelay);
+ schedule(dmaReadWaitEvent, curTick + totalDiskDelay);
}
void
@@ -395,7 +402,7 @@ IdeDisk::doDmaRead()
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaReadWaitEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaReadCG->done()) {
assert(dmaReadCG->complete() < MAX_DMA_SIZE);
@@ -457,7 +464,7 @@ IdeDisk::doDmaDataWrite()
cmdBytesLeft -= SectorSize;
}
- dmaWriteWaitEvent.schedule(curTick + totalDiskDelay);
+ schedule(dmaWriteWaitEvent, curTick + totalDiskDelay);
}
void
@@ -470,7 +477,7 @@ IdeDisk::doDmaWrite()
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
- dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
+ schedule(dmaWriteWaitEvent, curTick + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaWriteCG->done()) {
assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
@@ -545,7 +552,7 @@ IdeDisk::startDma(const uint32_t &prdTableBase)
dmaState = Dma_Transfer;
// schedule dma transfer (doDmaTransfer)
- dmaTransferEvent.schedule(curTick + 1);
+ schedule(dmaTransferEvent, curTick + 1);
}
void
@@ -683,7 +690,6 @@ IdeDisk::intrPost()
// talk to controller to set interrupt
if (ctrl) {
- ctrl->bmi_regs.bmis0 |= IDEINTS;
ctrl->intrPost();
}
}
@@ -1073,12 +1079,12 @@ IdeDisk::unserialize(Checkpoint *cp, const string &section)
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;
+ case Transfer : schedule(dmaTransferEvent, reschedule); break;
+ case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
+ case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
+ case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
+ case DmaRead : schedule(dmaReadEvent, reschedule); break;
+ case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
}
// Unserialize device registers
diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh
index 62c89add4..1b455e8ad 100644
--- a/src/dev/ide_disk.hh
+++ b/src/dev/ide_disk.hh
@@ -238,12 +238,12 @@ class IdeDisk : public SimObject
/** Interrupt pending */
bool intrPending;
- Stats::Scalar<> dmaReadFullPages;
- Stats::Scalar<> dmaReadBytes;
- Stats::Scalar<> dmaReadTxs;
- Stats::Scalar<> dmaWriteFullPages;
- Stats::Scalar<> dmaWriteBytes;
- Stats::Scalar<> dmaWriteTxs;
+ Stats::Scalar dmaReadFullPages;
+ Stats::Scalar dmaReadBytes;
+ Stats::Scalar dmaReadTxs;
+ Stats::Scalar dmaWriteFullPages;
+ Stats::Scalar dmaWriteBytes;
+ Stats::Scalar dmaWriteTxs;
Stats::Formula rdBandwidth;
Stats::Formula wrBandwidth;
Stats::Formula totBandwidth;
@@ -278,8 +278,10 @@ class IdeDisk : public SimObject
}
// 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);
+ void readCommand(const Addr offset, int size, uint8_t *data);
+ void readControl(const Addr offset, int size, uint8_t *data);
+ void writeCommand(const Addr offset, int size, const uint8_t *data);
+ void writeControl(const Addr offset, int size, const uint8_t *data);
// Start/abort functions
void startDma(const uint32_t &prdTableBase);
diff --git a/src/dev/intel_8254_timer.cc b/src/dev/intel_8254_timer.cc
new file mode 100644
index 000000000..d5dd043e1
--- /dev/null
+++ b/src/dev/intel_8254_timer.cc
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2004, 2005
+ * The Regents of The University of Michigan
+ * All Rights Reserved
+ *
+ * This code is part of the M5 simulator.
+ *
+ * Permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any
+ * purpose, so long as the copyright notice above, this grant of
+ * permission, and the disclaimer below appear in all copies made; and
+ * so long as the name of The University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+ * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
+ * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
+ * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGES.
+ *
+ * Authors: Ali G. Saidi
+ * Andrew L. Schultz
+ * Miguel J. Serrano
+ */
+
+#include "base/misc.hh"
+#include "dev/intel_8254_timer.hh"
+
+using namespace std;
+
+Intel8254Timer::Intel8254Timer(EventManager *em, const string &name,
+ Counter *counter0, Counter *counter1, Counter *counter2) :
+ EventManager(em), _name(name)
+{
+ counter[0] = counter0;
+ counter[1] = counter1;
+ counter[2] = counter2;
+}
+
+Intel8254Timer::Intel8254Timer(EventManager *em, const string &name) :
+ EventManager(em), _name(name)
+{
+ counter[0] = new Counter(this, name + ".counter0", 0);
+ counter[1] = new Counter(this, name + ".counter1", 1);
+ counter[2] = new Counter(this, name + ".counter2", 2);
+}
+
+void
+Intel8254Timer::writeControl(const CtrlReg data)
+{
+ int sel = data.sel;
+
+ if (sel == ReadBackCommand)
+ panic("PITimer Read-Back Command is not implemented.\n");
+
+ if (data.rw == LatchCommand)
+ counter[sel]->latchCount();
+ else {
+ counter[sel]->setRW(data.rw);
+ counter[sel]->setMode(data.mode);
+ counter[sel]->setBCD(data.bcd);
+ }
+}
+
+void
+Intel8254Timer::serialize(const string &base, ostream &os)
+{
+ // serialize the counters
+ counter[0]->serialize(base + ".counter0", os);
+ counter[1]->serialize(base + ".counter1", os);
+ counter[2]->serialize(base + ".counter2", os);
+}
+
+void
+Intel8254Timer::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ // unserialze the counters
+ counter[0]->unserialize(base + ".counter0", cp, section);
+ counter[1]->unserialize(base + ".counter1", cp, section);
+ counter[2]->unserialize(base + ".counter2", cp, section);
+}
+
+Intel8254Timer::Counter::Counter(Intel8254Timer *p,
+ const string &name, unsigned int _num)
+ : _name(name), num(_num), event(this), count(0),
+ latched_count(0), period(0), mode(0), output_high(false),
+ latch_on(false), read_byte(LSB), write_byte(LSB), parent(p)
+{
+
+}
+
+void
+Intel8254Timer::Counter::latchCount()
+{
+ // behave like a real latch
+ if(!latch_on) {
+ latch_on = true;
+ read_byte = LSB;
+ latched_count = count;
+ }
+}
+
+uint8_t
+Intel8254Timer::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
+Intel8254Timer::Counter::write(const uint8_t data)
+{
+ switch (write_byte) {
+ case LSB:
+ count = (count & 0xFF00) | data;
+
+ if (event.scheduled())
+ parent->deschedule(event);
+ output_high = false;
+ write_byte = MSB;
+ break;
+
+ case MSB:
+ count = (count & 0x00FF) | (data << 8);
+ // In the RateGen or SquareWave modes, the timer wraps around and
+ // triggers on a value of 1, not 0.
+ if (mode == RateGen || mode == SquareWave)
+ period = count - 1;
+ else
+ period = count;
+
+ if (period > 0)
+ event.setTo(period);
+
+ write_byte = LSB;
+ break;
+ }
+}
+
+void
+Intel8254Timer::Counter::setRW(int rw_val)
+{
+ if (rw_val != TwoPhase)
+ panic("Only LSB/MSB read/write is implemented.\n");
+}
+
+void
+Intel8254Timer::Counter::setMode(int mode_val)
+{
+ if(mode_val != InitTc && mode_val != RateGen &&
+ mode_val != SquareWave)
+ panic("PIT mode %#x is not implemented: \n", mode_val);
+
+ mode = mode_val;
+}
+
+void
+Intel8254Timer::Counter::setBCD(int bcd_val)
+{
+ if (bcd_val)
+ panic("PITimer does not implement BCD counts.\n");
+}
+
+bool
+Intel8254Timer::Counter::outputHigh()
+{
+ return output_high;
+}
+
+void
+Intel8254Timer::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
+Intel8254Timer::Counter::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ 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)
+ parent->schedule(event, event_tick);
+}
+
+Intel8254Timer::Counter::CounterEvent::CounterEvent(Counter* c_ptr)
+{
+ interval = (Tick)(Clock::Float::s / 1193180.0);
+ counter = c_ptr;
+}
+
+void
+Intel8254Timer::Counter::CounterEvent::process()
+{
+ switch (counter->mode) {
+ case InitTc:
+ counter->output_high = true;
+ break;
+ case RateGen:
+ case SquareWave:
+ setTo(counter->period);
+ break;
+ default:
+ panic("Unimplemented PITimer mode.\n");
+ }
+ counter->parent->counterInterrupt(counter->num);
+}
+
+void
+Intel8254Timer::Counter::CounterEvent::setTo(int clocks)
+{
+ if (clocks == 0)
+ panic("Timer can't be set to go off instantly.\n");
+ DPRINTF(Intel8254Timer, "Timer set to curTick + %d\n",
+ clocks * interval);
+ counter->parent->schedule(this, curTick + clocks * interval);
+}
+
+const char *
+Intel8254Timer::Counter::CounterEvent::description() const
+{
+ return "Intel 8254 Interval timer";
+}
diff --git a/src/dev/intel_8254_timer.hh b/src/dev/intel_8254_timer.hh
new file mode 100644
index 000000000..bb650d33b
--- /dev/null
+++ b/src/dev/intel_8254_timer.hh
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2004, 2005
+ * The Regents of The University of Michigan
+ * All Rights Reserved
+ *
+ * This code is part of the M5 simulator.
+ *
+ * Permission is granted to use, copy, create derivative works and
+ * redistribute this software and such derivative works for any
+ * purpose, so long as the copyright notice above, this grant of
+ * permission, and the disclaimer below appear in all copies made; and
+ * so long as the name of The University of Michigan is not used in
+ * any advertising or publicity pertaining to the use or distribution
+ * of this software without specific, written prior authorization.
+ *
+ * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
+ * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND
+ * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT,
+ * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM
+ * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
+ * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGES.
+ *
+ * Authors: Ali G. Saidi
+ * Andrew L. Schultz
+ * Miguel J. Serrano
+ */
+
+#ifndef __DEV_8254_HH__
+#define __DEV_8254_HH__
+
+#include <string>
+#include <iostream>
+
+#include "base/bitunion.hh"
+#include "sim/eventq.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+
+/** Programmable Interval Timer (Intel 8254) */
+class Intel8254Timer : public EventManager
+{
+ protected:
+ BitUnion8(CtrlReg)
+ Bitfield<7, 6> sel;
+ Bitfield<5, 4> rw;
+ Bitfield<3, 1> mode;
+ Bitfield<0> bcd;
+ EndBitUnion(CtrlReg)
+
+ enum SelectVal {
+ SelectCounter0,
+ SelectCounter1,
+ SelectCounter2,
+ ReadBackCommand
+ };
+
+ enum ReadWriteVal {
+ LatchCommand,
+ LsbOnly,
+ MsbOnly,
+ TwoPhase
+ };
+
+ enum ModeVal {
+ InitTc,
+ OneShot,
+ RateGen,
+ SquareWave,
+ SoftwareStrobe,
+ HardwareStrobe
+ };
+
+ /** 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 */
+ void process();
+
+ /** Event description */
+ virtual const char *description() const;
+
+ friend class Counter;
+
+ void setTo(int clocks);
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ unsigned int num;
+
+ 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;
+
+ /** Pointer to container */
+ Intel8254Timer *parent;
+
+ public:
+ Counter(Intel8254Timer *p, const std::string &name, unsigned int num);
+
+ /** 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 base The base name of the counter object.
+ * @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 base The base name of the counter object.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+ };
+
+ protected:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ /** PIT has three seperate counters */
+ Counter *counter[3];
+
+ virtual void
+ counterInterrupt(unsigned int num)
+ {
+ DPRINTF(Intel8254Timer, "Timer interrupt from counter %d.\n", num);
+ }
+
+ public:
+
+ virtual
+ ~Intel8254Timer()
+ {}
+
+ Intel8254Timer(EventManager *em, const std::string &name,
+ Counter *counter0, Counter *counter1, Counter *counter2);
+
+ Intel8254Timer(EventManager *em, const std::string &name);
+
+ /** Write control word */
+ void writeControl(const CtrlReg data);
+
+ uint8_t
+ readCounter(unsigned int num)
+ {
+ assert(num < 3);
+ return counter[num]->read();
+ }
+
+ void
+ writeCounter(unsigned int num, const uint8_t data)
+ {
+ assert(num < 3);
+ counter[num]->write(data);
+ }
+
+ bool
+ outputHigh(unsigned int num)
+ {
+ assert(num < 3);
+ return counter[num]->outputHigh();
+ }
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param base The base name of the counter object.
+ * @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 base The base name of the counter object.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+};
+
+#endif // __DEV_8254_HH__
diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc
index 527397ed8..cdba171a6 100644
--- a/src/dev/io_device.cc
+++ b/src/dev/io_device.cc
@@ -117,7 +117,7 @@ DmaPort::recvTiming(PacketPtr pkt)
else if (backoffTime < device->maxBackoffDelay)
backoffTime <<= 1;
- backoffEvent.reschedule(curTick + backoffTime, true);
+ reschedule(backoffEvent, curTick + backoffTime, true);
DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime);
@@ -138,7 +138,10 @@ DmaPort::recvTiming(PacketPtr pkt)
state->numBytes += pkt->req->getSize();
assert(state->totBytes >= state->numBytes);
if (state->totBytes == state->numBytes) {
- state->completionEvent->process();
+ if (state->delay)
+ schedule(state->completionEvent, curTick + state->delay);
+ else
+ state->completionEvent->process();
delete state;
}
delete pkt->req;
@@ -187,9 +190,9 @@ void
DmaPort::recvRetry()
{
assert(transmitList.size());
- PacketPtr pkt = transmitList.front();
bool result = true;
do {
+ PacketPtr pkt = transmitList.front();
DPRINTF(DMA, "Retry on %s addr %#x\n",
pkt->cmdString(), pkt->getAddr());
result = sendTiming(pkt);
@@ -206,7 +209,7 @@ DmaPort::recvRetry()
if (transmitList.size() && backoffTime && !inRetry) {
DPRINTF(DMA, "Scheduling backoff for %d\n", curTick+backoffTime);
if (!backoffEvent.scheduled())
- backoffEvent.schedule(backoffTime+curTick);
+ schedule(backoffEvent, backoffTime + curTick);
}
DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n",
transmitList.size(), backoffTime, inRetry,
@@ -216,13 +219,13 @@ DmaPort::recvRetry()
void
DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
- uint8_t *data)
+ uint8_t *data, Tick delay)
{
assert(event);
assert(device->getState() == SimObject::Running);
- DmaReqState *reqState = new DmaReqState(event, this, size);
+ DmaReqState *reqState = new DmaReqState(event, this, size, delay);
DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
@@ -294,7 +297,7 @@ DmaPort::sendDma()
!backoffEvent.scheduled()) {
DPRINTF(DMA, "-- Scheduling backoff timer for %d\n",
backoffTime+curTick);
- backoffEvent.schedule(backoffTime+curTick);
+ schedule(backoffEvent, backoffTime + curTick);
}
} else if (state == Enums::atomic) {
transmitList.pop_front();
@@ -314,7 +317,7 @@ DmaPort::sendDma()
if (state->totBytes == state->numBytes) {
assert(!state->completionEvent->scheduled());
- state->completionEvent->schedule(curTick + lat);
+ schedule(state->completionEvent, curTick + lat + state->delay);
delete state;
delete pkt->req;
}
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
index 876166adb..70af6093d 100644
--- a/src/dev/io_device.hh
+++ b/src/dev/io_device.hh
@@ -32,6 +32,7 @@
#ifndef __DEV_IO_DEVICE_HH__
#define __DEV_IO_DEVICE_HH__
+#include "base/fast_alloc.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/tport.hh"
@@ -73,7 +74,7 @@ class PioPort : public SimpleTimingPort
class DmaPort : public Port
{
protected:
- struct DmaReqState : public Packet::SenderState
+ struct DmaReqState : public Packet::SenderState, public FastAlloc
{
/** Event to call on the device when this transaction (all packets)
* complete. */
@@ -88,8 +89,12 @@ class DmaPort : public Port
/** Number of bytes that have been acked for this transaction. */
Addr numBytes;
- DmaReqState(Event *ce, Port *p, Addr tb)
- : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0)
+ /** Amount to delay completion of dma by */
+ Tick delay;
+
+ DmaReqState(Event *ce, Port *p, Addr tb, Tick _delay)
+ : completionEvent(ce), outPort(p), totBytes(tb), numBytes(0),
+ delay(_delay)
{}
};
@@ -143,7 +148,7 @@ class DmaPort : public Port
DmaPort(DmaDevice *dev, System *s);
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
- uint8_t *data = NULL);
+ uint8_t *data, Tick delay);
bool dmaPending() { return pendingCount > 0; }
@@ -207,7 +212,8 @@ class PioDevice : public MemObject
{
if (if_name == "pio") {
if (pioPort != NULL)
- panic("pio port already connected to.");
+ fatal("%s: pio port already connected to %s",
+ name(), pioPort->getPeer()->name());
pioPort = new PioPort(this, sys);
return pioPort;
} else
@@ -264,14 +270,14 @@ class DmaDevice : public PioDevice
return dynamic_cast<const Params *>(_params);
}
- void dmaWrite(Addr addr, int size, Event *event, uint8_t *data)
+ void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
{
- dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data);
+ dmaPort->dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
}
- void dmaRead(Addr addr, int size, Event *event, uint8_t *data)
+ void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay = 0)
{
- dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data);
+ dmaPort->dmaAction(MemCmd::ReadReq, addr, size, event, data, delay);
}
bool dmaPending() { return dmaPort->dmaPending(); }
@@ -284,12 +290,14 @@ class DmaDevice : public PioDevice
{
if (if_name == "pio") {
if (pioPort != NULL)
- panic("pio port already connected to.");
+ fatal("%s: pio port already connected to %s",
+ name(), pioPort->getPeer()->name());
pioPort = new PioPort(this, sys);
return pioPort;
} else if (if_name == "dma") {
if (dmaPort != NULL)
- panic("dma port already connected to.");
+ fatal("%s: dma port already connected to %s",
+ name(), dmaPort->getPeer()->name());
dmaPort = new DmaPort(this, sys);
return dmaPort;
} else
diff --git a/src/dev/mc146818.cc b/src/dev/mc146818.cc
new file mode 100644
index 000000000..c01d945b3
--- /dev/null
+++ b/src/dev/mc146818.cc
@@ -0,0 +1,192 @@
+/*
+ * 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.
+ *
+ * Authors: Ali Saidi
+ * Andrew Schultz
+ * Miguel Serrano
+ */
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <string>
+
+#include "base/bitfield.hh"
+#include "base/time.hh"
+#include "base/trace.hh"
+#include "dev/mc146818.hh"
+#include "dev/rtcreg.h"
+
+using namespace std;
+
+MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
+ bool bcd, Tick frequency)
+ : EventManager(em), _name(n), event(this, frequency)
+{
+ memset(clock_data, 0, sizeof(clock_data));
+ stat_regA = RTCA_32768HZ | RTCA_1024HZ;
+ stat_regB = RTCB_PRDC_IE | RTCB_24HR;
+ if (!bcd)
+ stat_regB |= RTCB_BIN;
+
+ year = time.tm_year;
+
+ if (bcd) {
+ // The datasheet says that the year field can be either BCD or
+ // years since 1900. Linux seems to be happy with years since
+ // 1900.
+ year = year % 100;
+ int tens = year / 10;
+ int ones = year % 10;
+ year = (tens << 4) + ones;
+ }
+
+ // Unix is 0-11 for month, data seet says start at 1
+ mon = time.tm_mon + 1;
+ mday = time.tm_mday;
+ hour = time.tm_hour;
+ min = time.tm_min;
+ sec = time.tm_sec;
+
+ // Datasheet says 1 is sunday
+ wday = time.tm_wday + 1;
+
+ DPRINTFN("Real-time clock set to %s", asctime(&time));
+}
+
+MC146818::~MC146818()
+{
+}
+
+void
+MC146818::writeData(const uint8_t addr, const uint8_t data)
+{
+ if (addr < RTC_STAT_REGA)
+ clock_data[addr] = data;
+ else {
+ switch (addr) {
+ case RTC_STAT_REGA:
+ // The "update in progress" bit is read only.
+ if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ))
+ panic("Unimplemented RTC register A value write!\n");
+ replaceBits(stat_regA, data, 6, 0);
+ 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())
+ deschedule(event);
+ }
+ 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
+MC146818::readData(uint8_t addr)
+{
+ 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
+MC146818::serialize(const string &base, ostream &os)
+{
+ 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
+MC146818::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ 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
+ reschedule(event, curTick + event.interval);
+}
+
+MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
+ : parent(_parent), interval(i)
+{
+ DPRINTF(MC146818, "RTC Event Initilizing\n");
+ parent->schedule(this, curTick + interval);
+}
+
+void
+MC146818::RTCEvent::scheduleIntr()
+{
+ parent->schedule(this, curTick + interval);
+}
+
+void
+MC146818::RTCEvent::process()
+{
+ DPRINTF(MC146818, "RTC Timer Interrupt\n");
+ parent->schedule(this, curTick + interval);
+ parent->handleEvent();
+}
+
+const char *
+MC146818::RTCEvent::description() const
+{
+ return "RTC interrupt";
+}
diff --git a/src/dev/mc146818.hh b/src/dev/mc146818.hh
new file mode 100644
index 000000000..e145ad3fd
--- /dev/null
+++ b/src/dev/mc146818.hh
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ * Authors: Ali Saidi
+ * Andrew Schultz
+ * Miguel Serrano
+ */
+
+#ifndef __DEV_MC146818_HH__
+#define __DEV_MC146818_HH__
+
+#include "base/range.hh"
+#include "sim/eventq.hh"
+
+/** Real-Time Clock (MC146818) */
+class MC146818 : public EventManager
+{
+ protected:
+ virtual void handleEvent()
+ {
+ warn("No RTC event handler defined.\n");
+ }
+
+ private:
+ /** Event for RTC periodic interrupt */
+ struct RTCEvent : public Event
+ {
+ MC146818 * parent;
+ Tick interval;
+
+ RTCEvent(MC146818 * _parent, Tick i);
+
+ /** Schedule the RTC periodic interrupt */
+ void scheduleIntr();
+
+ /** Event process to occur at interrupt*/
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description() const;
+ };
+
+ private:
+ std::string _name;
+ const std::string &name() const { return _name; }
+
+ /** RTC periodic interrupt event */
+ RTCEvent event;
+
+ /** 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:
+ MC146818(EventManager *em, const std::string &name, const struct tm time,
+ bool bcd, Tick frequency);
+ virtual ~MC146818();
+
+ /** RTC write data */
+ void writeData(const uint8_t addr, const uint8_t data);
+
+ /** RTC read data */
+ uint8_t readData(const uint8_t addr);
+
+ /**
+ * Serialize this object to the given output stream.
+ * @param base The base name of the counter object.
+ * @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 base The base name of the counter object.
+ * @param cp The checkpoint use.
+ * @param section The section name of this object
+ */
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+};
+
+#endif // __DEV_MC146818_HH__
diff --git a/src/dev/mips/Malta.py b/src/dev/mips/Malta.py
index d321a6361..d215bf329 100755
--- a/src/dev/mips/Malta.py
+++ b/src/dev/mips/Malta.py
@@ -28,12 +28,13 @@
from m5.params import *
from m5.proxy import *
+
+from BadDevice import BadDevice
from Device import BasicPioDevice
+from MipsBackdoor import MipsBackdoor
+from Pci import PciConfigAll
from Platform import Platform
-from MipsConsole import MipsConsole
from Uart import Uart8250
-from Pci import PciConfigAll
-from BadDevice import BadDevice
class MaltaCChip(BasicPioDevice):
type = 'MaltaCChip'
@@ -56,7 +57,7 @@ class Malta(Platform):
cchip = MaltaCChip(pio_addr=0x801a0000000)
io = MaltaIO(pio_addr=0x801fc000000)
uart = Uart8250(pio_addr=0xBFD003F8)
- console = MipsConsole(pio_addr=0xBFD00F00, disk=Parent.simple_disk)
+ backdoor = MipsBackdoor(pio_addr=0xBFD00F00, disk=Parent.simple_disk)
# Attach I/O devices to specified bus object. Can't do this
# earlier, since the bus object itself is typically defined at the
@@ -65,4 +66,4 @@ class Malta(Platform):
self.cchip.pio = bus.port
self.io.pio = bus.port
self.uart.pio = bus.port
- self.console.pio = bus.port
+ self.backdoor.pio = bus.port
diff --git a/src/dev/mips/MipsConsole.py b/src/dev/mips/MipsBackdoor.py
index 36575677a..f65250238 100644
--- a/src/dev/mips/MipsConsole.py
+++ b/src/dev/mips/MipsBackdoor.py
@@ -30,9 +30,9 @@ from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice
-class MipsConsole(BasicPioDevice):
- type = 'MipsConsole'
+class MipsBackdoor(BasicPioDevice):
+ type = 'MipsBackdoor'
cpu = Param.BaseCPU(Parent.cpu[0], "Processor")
disk = Param.SimpleDisk("Simple Disk")
- sim_console = Param.SimConsole(Parent.any, "The Simulator Console")
+ terminal = Param.Terminal(Parent.any, "The console terminal")
system = Param.MipsSystem(Parent.any, "system object")
diff --git a/src/dev/mips/SConscript b/src/dev/mips/SConscript
index 22e91ff09..e83e47ebd 100755
--- a/src/dev/mips/SConscript
+++ b/src/dev/mips/SConscript
@@ -32,13 +32,13 @@
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'mips':
- SimObject('MipsConsole.py')
+ SimObject('MipsBackdoor.py')
SimObject('Malta.py')
TraceFlag('Malta')
TraceFlag('MC146818')
- Source('console.cc')
+ Source('backdoor.cc')
Source('malta.cc')
Source('malta_cchip.cc')
Source('malta_io.cc')
diff --git a/src/dev/mips/access.h b/src/dev/mips/access.h
index dbf3661b3..416b80590 100755
--- a/src/dev/mips/access.h
+++ b/src/dev/mips/access.h
@@ -48,37 +48,37 @@ typedef unsigned long uint64_t;
// This structure hacked up from simos
struct MipsAccess
{
- uint32_t inputChar; // 00: Placeholder for input
- uint32_t last_offset; // 04: must be first field
- uint32_t version; // 08:
- uint32_t numCPUs; // 0C:
- uint32_t intrClockFrequency; // 10: Hz
+ uint32_t inputChar; // 00: Placeholder for input
+ uint32_t last_offset; // 04: must be first field
+ uint32_t version; // 08:
+ uint32_t numCPUs; // 0C:
+ uint32_t intrClockFrequency; // 10: Hz
// Loaded kernel
- uint32_t kernStart; // 14:
- uint32_t kernEnd; // 18:
- uint32_t entryPoint; // 1c:
+ uint32_t kernStart; // 14:
+ uint32_t kernEnd; // 18:
+ uint32_t entryPoint; // 1c:
// console simple output stuff
- uint32_t outputChar; // 20: Placeholder for output
+ uint32_t outputChar; // 20: Placeholder for output
// console disk stuff
- uint32_t diskUnit; // 24:
- uint32_t diskCount; // 28:
- uint32_t diskPAddr; // 2c:
- uint32_t diskBlock; // 30:
- uint32_t diskOperation; // 34:
+ uint32_t diskUnit; // 24:
+ uint32_t diskCount; // 28:
+ uint32_t diskPAddr; // 2c:
+ uint32_t diskBlock; // 30:
+ uint32_t diskOperation; // 34:
// MP boot
- uint32_t cpuStack[64]; // 70:
+ uint32_t cpuStack[64]; // 70:
/* XXX There appears to be a problem in accessing
* unit64_t in the console.c file. They are treated
* like uint32_int and result in the wrong address for
* everything below. This problem should be investigated.
*/
- uint64_t cpuClock; // 38: MHz
- uint64_t mem_size; // 40:
+ uint64_t cpuClock; // 38: MHz
+ uint64_t mem_size; // 40:
};
#endif // __MIPS_ACCESS_H__
diff --git a/src/dev/mips/console.cc b/src/dev/mips/backdoor.cc
index 185e1acbc..313f12567 100755
--- a/src/dev/mips/console.cc
+++ b/src/dev/mips/backdoor.cc
@@ -32,7 +32,7 @@
*/
/** @file
- * Mips Console Definition
+ * Mips Console Backdoor Definition
*/
#include <cstddef>
#include <string>
@@ -43,22 +43,22 @@
#include "base/trace.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "dev/mips/console.hh"
+#include "dev/mips/backdoor.hh"
#include "dev/platform.hh"
-#include "dev/simconsole.hh"
#include "dev/simple_disk.hh"
+#include "dev/terminal.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
-#include "params/MipsConsole.hh"
+#include "params/MipsBackdoor.hh"
#include "sim/sim_object.hh"
using namespace std;
using namespace MipsISA;
-MipsConsole::MipsConsole(const Params *p)
- : BasicPioDevice(p), disk(p->disk), console(p->sim_console),
+MipsBackdoor::MipsBackdoor(const Params *p)
+ : BasicPioDevice(p), disk(p->disk), terminal(p->terminal),
system(p->system), cpu(p->cpu)
{
@@ -81,7 +81,7 @@ MipsConsole::MipsConsole(const Params *p)
}
void
-MipsConsole::startup()
+MipsBackdoor::startup()
{
system->setMipsAccess(pioAddr);
mipsAccess->numCPUs = system->getNumCPUs();
@@ -94,7 +94,7 @@ MipsConsole::startup()
}
Tick
-MipsConsole::read(PacketPtr pkt)
+MipsBackdoor::read(PacketPtr pkt)
{
/** XXX Do we want to push the addr munging to a bus brige or something? So
@@ -125,7 +125,7 @@ MipsConsole::read(PacketPtr pkt)
pkt->set(mipsAccess->intrClockFrequency);
break;
case offsetof(MipsAccess, inputChar):
- pkt->set(console->console_in());
+ pkt->set(terminal->console_in());
break;
case offsetof(MipsAccess, cpuClock):
pkt->set(mipsAccess->cpuClock);
@@ -169,7 +169,7 @@ MipsConsole::read(PacketPtr pkt)
else
panic("Unknown 32bit access, %#x\n", daddr);
}
- //DPRINTF(MipsConsole, "read: offset=%#x val=%#x\n", daddr,
+ //DPRINTF(MipsBackdoor, "read: offset=%#x val=%#x\n", daddr,
// pkt->get<uint64_t>());
break;
default:
@@ -181,7 +181,7 @@ MipsConsole::read(PacketPtr pkt)
}
Tick
-MipsConsole::write(PacketPtr pkt)
+MipsBackdoor::write(PacketPtr pkt)
{
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
@@ -215,7 +215,7 @@ MipsConsole::write(PacketPtr pkt)
break;
case offsetof(MipsAccess, outputChar):
- console->out((char)(val & 0xff));
+ terminal->out((char)(val & 0xff));
break;
default:
@@ -235,7 +235,7 @@ MipsConsole::write(PacketPtr pkt)
}
void
-MipsConsole::Access::serialize(ostream &os)
+MipsBackdoor::Access::serialize(ostream &os)
{
SERIALIZE_SCALAR(last_offset);
SERIALIZE_SCALAR(version);
@@ -257,7 +257,7 @@ MipsConsole::Access::serialize(ostream &os)
}
void
-MipsConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
+MipsBackdoor::Access::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_SCALAR(last_offset);
UNSERIALIZE_SCALAR(version);
@@ -279,19 +279,19 @@ MipsConsole::Access::unserialize(Checkpoint *cp, const std::string &section)
}
void
-MipsConsole::serialize(ostream &os)
+MipsBackdoor::serialize(ostream &os)
{
mipsAccess->serialize(os);
}
void
-MipsConsole::unserialize(Checkpoint *cp, const std::string &section)
+MipsBackdoor::unserialize(Checkpoint *cp, const std::string &section)
{
mipsAccess->unserialize(cp, section);
}
-MipsConsole *
-MipsConsoleParams::create()
+MipsBackdoor *
+MipsBackdoorParams::create()
{
- return new MipsConsole(this);
+ return new MipsBackdoor(this);
}
diff --git a/src/dev/mips/console.hh b/src/dev/mips/backdoor.hh
index 34792090d..b8cc0ae46 100755
--- a/src/dev/mips/console.hh
+++ b/src/dev/mips/backdoor.hh
@@ -29,28 +29,28 @@
*/
/** @file
- * System Console Interface
+ * System Console Backdoor Interface
*/
-#ifndef __MIPS_CONSOLE_HH__
-#define __MIPS_CONSOLE_HH__
+#ifndef __DEV_MIPS_BACKDOOR_HH__
+#define __DEV_MIPS_BACKDOOR_HH__
#include "base/range.hh"
#include "dev/mips/access.h"
#include "dev/io_device.hh"
-#include "params/MipsConsole.hh"
+#include "params/MipsBackdoor.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
class BaseCPU;
-class SimConsole;
+class Terminal;
class MipsSystem;
class SimpleDisk;
/**
* Memory mapped interface to the system console. This device
* represents a shared data region between the OS Kernel and the
- * System Console.
+ * System Console Backdoor.
*
* The system console is a small standalone program that is initially
* run when the system boots. It contains the necessary code to
@@ -72,7 +72,7 @@ class SimpleDisk;
* primarily used doing boot before the kernel has loaded its device
* drivers.
*/
-class MipsConsole : public BasicPioDevice
+class MipsBackdoor : public BasicPioDevice
{
protected:
struct Access : public MipsAccess
@@ -89,8 +89,8 @@ class MipsConsole : public BasicPioDevice
/** the disk must be accessed from the console */
SimpleDisk *disk;
- /** the system console (the terminal) is accessable from the console */
- SimConsole *console;
+ /** the system terminal is accessable from the console */
+ Terminal *terminal;
/** a pointer to the system we are running in */
MipsSystem *system;
@@ -99,8 +99,8 @@ class MipsConsole : public BasicPioDevice
BaseCPU *cpu;
public:
- typedef MipsConsoleParams Params;
- MipsConsole(const Params *p);
+ typedef MipsBackdoorParams Params;
+ MipsBackdoor(const Params *p);
const Params *
params() const
@@ -123,4 +123,4 @@ class MipsConsole : public BasicPioDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
};
-#endif // __MIPS_CONSOLE_HH__
+#endif // __DEV_MIPS_BACKDOOR_HH__
diff --git a/src/dev/mips/malta.cc b/src/dev/mips/malta.cc
index 0b1fa15ba..21e79d999 100755
--- a/src/dev/mips/malta.cc
+++ b/src/dev/mips/malta.cc
@@ -38,11 +38,11 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/mips/malta_cchip.hh"
#include "dev/mips/malta_pchip.hh"
#include "dev/mips/malta_io.hh"
#include "dev/mips/malta.hh"
+#include "dev/terminal.hh"
#include "params/Malta.hh"
#include "sim/system.hh"
diff --git a/src/dev/mips/malta_cchip.cc b/src/dev/mips/malta_cchip.cc
index 5a4ea4585..265977665 100755
--- a/src/dev/mips/malta_cchip.cc
+++ b/src/dev/mips/malta_cchip.cc
@@ -103,7 +103,7 @@ MaltaCChip::read(PacketPtr pkt)
break;
case TSDEV_CC_MISC:
pkt->set((ipint << 8) & 0xF | (itint << 4) & 0xF |
- (pkt->req->getCpuNum() & 0x3));
+ (pkt->req->contextId() & 0x3));
break;
case TSDEV_CC_AAR0:
case TSDEV_CC_AAR1:
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
index bd48bdca5..fb3446299 100644
--- a/src/dev/ns_gige.cc
+++ b/src/dev/ns_gige.cc
@@ -36,6 +36,7 @@
#include <deque>
#include <string>
+#include "base/debug.hh"
#include "base/inet.hh"
#include "cpu/thread_context.hh"
#include "dev/etherlink.hh"
@@ -44,9 +45,7 @@
#include "mem/packet.hh"
#include "mem/packet_access.hh"
#include "params/NSGigE.hh"
-#include "sim/debug.hh"
#include "sim/host.hh"
-#include "sim/stats.hh"
#include "sim/system.hh"
const char *NsRxStateStrings[] =
@@ -131,341 +130,6 @@ NSGigE::NSGigE(Params *p)
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
*/
@@ -1186,6 +850,7 @@ NSGigE::devIntrPost(uint32_t interrupts)
Tick when = curTick;
if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
when += intrDelay;
+ postedInterrupts++;
cpuIntrPost(when);
}
}
@@ -1226,9 +891,6 @@ NSGigE::devIntrClear(uint32_t interrupts)
postedRxOrn++;
}
- if (regs.isr & regs.imr & ISR_IMPL)
- postedInterrupts++;
-
interrupts &= ~ISR_NOIMPL;
regs.isr &= ~interrupts;
@@ -1283,7 +945,8 @@ NSGigE::cpuIntrPost(Tick when)
if (intrEvent)
intrEvent->squash();
- intrEvent = new IntrEvent(this, intrTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrTick);
}
void
@@ -1780,7 +1443,7 @@ NSGigE::rxKick()
NsRxStateStrings[rxState]);
if (clock && !rxKickEvent.scheduled())
- rxKickEvent.schedule(rxKickTick);
+ schedule(rxKickEvent, rxKickTick);
}
void
@@ -1830,7 +1493,7 @@ NSGigE::transmit()
if (!txFifo.empty() && !txEvent.scheduled()) {
DPRINTF(Ethernet, "reschedule transmit\n");
- txEvent.schedule(curTick + retryTime);
+ schedule(txEvent, curTick + retryTime);
}
}
@@ -2036,19 +1699,34 @@ NSGigE::txKick()
IpPtr ip(txPacket);
if (extsts & EXTSTS_UDPPKT) {
UdpPtr udp(ip);
- udp->sum(0);
- udp->sum(cksum(udp));
- txUdpChecksums++;
+ if (udp) {
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ txUdpChecksums++;
+ } else {
+ debug_break();
+ warn_once("UDPPKT set, but not UDP!\n");
+ }
} else if (extsts & EXTSTS_TCPPKT) {
TcpPtr tcp(ip);
- tcp->sum(0);
- tcp->sum(cksum(tcp));
- txTcpChecksums++;
+ if (tcp) {
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ txTcpChecksums++;
+ } else {
+ debug_break();
+ warn_once("TCPPKT set, but not UDP!\n");
+ }
}
if (extsts & EXTSTS_IPPKT) {
- ip->sum(0);
- ip->sum(cksum(ip));
- txIpChecksums++;
+ if (ip) {
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ txIpChecksums++;
+ } else {
+ debug_break();
+ warn_once("IPPKT set, but not UDP!\n");
+ }
}
}
@@ -2208,7 +1886,7 @@ NSGigE::txKick()
NsTxStateStrings[txState]);
if (clock && !txKickEvent.scheduled())
- txKickEvent.schedule(txKickTick);
+ schedule(txKickEvent, txKickTick);
}
/**
@@ -2322,7 +2000,7 @@ NSGigE::transferDone()
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
- txEvent.reschedule(curTick + ticks(1), true);
+ reschedule(txEvent, curTick + ticks(1), true);
}
bool
@@ -2723,7 +2401,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
this->txDmaState = (DmaState) txDmaState;
UNSERIALIZE_SCALAR(txKickTick);
if (txKickTick)
- txKickEvent.schedule(txKickTick);
+ schedule(txKickEvent, txKickTick);
/*
* unserialize rx state machine
@@ -2741,7 +2419,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
this->rxDmaState = (DmaState) rxDmaState;
UNSERIALIZE_SCALAR(rxKickTick);
if (rxKickTick)
- rxKickEvent.schedule(rxKickTick);
+ schedule(rxKickEvent, rxKickTick);
/*
* Unserialize EEPROM state machine
@@ -2761,7 +2439,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
Tick transmitTick;
UNSERIALIZE_SCALAR(transmitTick);
if (transmitTick)
- txEvent.schedule(curTick + transmitTick);
+ schedule(txEvent, curTick + transmitTick);
/*
* unserialize receive address filter settings
@@ -2782,7 +2460,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
Tick intrEventTick;
UNSERIALIZE_SCALAR(intrEventTick);
if (intrEventTick) {
- intrEvent = new IntrEvent(this, intrEventTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrEventTick);
}
}
diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh
index dfdd81b66..87cf56962 100644
--- a/src/dev/ns_gige.hh
+++ b/src/dev/ns_gige.hh
@@ -38,7 +38,6 @@
#define __DEV_NS_GIGE_HH__
#include "base/inet.hh"
-#include "base/statistics.hh"
#include "dev/etherdevice.hh"
#include "dev/etherint.hh"
#include "dev/etherpkt.hh"
@@ -63,10 +62,10 @@ 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 command;
+ uint32_t config;
+ uint32_t mear;
+ uint32_t ptscr;
uint32_t isr;
uint32_t imr;
uint32_t ier;
@@ -372,60 +371,6 @@ class NSGigE : public EtherDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
-
- 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;
};
/*
diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc
index faf033705..74396be5d 100644
--- a/src/dev/pciconfigall.cc
+++ b/src/dev/pciconfigall.cc
@@ -47,7 +47,7 @@ using namespace std;
PciConfigAll::PciConfigAll(const Params *p)
: PioDevice(p)
{
- pioAddr = p->platform->calcConfigAddr(params()->bus,0,0);
+ pioAddr = p->platform->calcPciConfigAddr(params()->bus,0,0);
}
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index aa532414c..b311ed8cf 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -41,7 +41,7 @@
#include "base/inifile.hh"
#include "base/intmath.hh" // for isPowerOf2(
#include "base/misc.hh"
-#include "base/str.hh" // for to_number
+#include "base/str.hh" // for to_number
#include "base/trace.hh"
#include "dev/pciconfigall.hh"
#include "dev/pcidev.hh"
@@ -56,10 +56,10 @@ using namespace std;
PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
int funcid, Platform *p)
- : SimpleTimingPort(dev->name() + "-pciconf"), device(dev), platform(p),
- busId(busid), deviceId(devid), functionId(funcid)
+ : SimpleTimingPort(dev->name() + "-pciconf", dev), device(dev),
+ platform(p), busId(busid), deviceId(devid), functionId(funcid)
{
- configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
+ configAddr = platform->calcPciConfigAddr(busId, deviceId, functionId);
}
@@ -121,15 +121,26 @@ PciDev::PciDev(const Params *p)
BARSize[4] = p->BAR4Size;
BARSize[5] = p->BAR5Size;
+ legacyIO[0] = p->BAR0LegacyIO;
+ legacyIO[1] = p->BAR1LegacyIO;
+ legacyIO[2] = p->BAR2LegacyIO;
+ legacyIO[3] = p->BAR3LegacyIO;
+ legacyIO[4] = p->BAR4LegacyIO;
+ legacyIO[5] = p->BAR5LegacyIO;
+
for (int i = 0; i < 6; ++i) {
- uint32_t barsize = BARSize[i];
- if (barsize != 0 && !isPowerOf2(barsize)) {
- fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
+ if (legacyIO[i]) {
+ BARAddrs[i] = platform->calcPciIOAddr(letoh(config.baseAddr[i]));
+ config.baseAddr[i] = 0;
+ } else {
+ BARAddrs[i] = 0;
+ uint32_t barsize = BARSize[i];
+ if (barsize != 0 && !isPowerOf2(barsize)) {
+ fatal("BAR %d size %d is not a power of 2\n", i, BARSize[i]);
+ }
}
}
- memset(BARAddrs, 0, sizeof(BARAddrs));
-
plat->registerPciDevice(0, p->pci_dev, p->pci_func,
letoh(config.interruptLine));
}
@@ -216,8 +227,10 @@ PciDev::writeConfig(PacketPtr pkt)
switch (offset) {
case PCI0_INTERRUPT_LINE:
config.interruptLine = pkt->get<uint8_t>();
+ break;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
+ break;
case PCI_LATENCY_TIMER:
config.latencyTimer = pkt->get<uint8_t>();
break;
@@ -240,8 +253,10 @@ PciDev::writeConfig(PacketPtr pkt)
switch (offset) {
case PCI_COMMAND:
config.command = pkt->get<uint8_t>();
+ break;
case PCI_STATUS:
config.status = pkt->get<uint8_t>();
+ break;
case PCI_CACHE_LINE_SIZE:
config.cacheLineSize = pkt->get<uint8_t>();
break;
@@ -264,30 +279,32 @@ PciDev::writeConfig(PacketPtr pkt)
{
int barnum = BAR_NUMBER(offset);
- // convert BAR values to host endianness
- uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
- uint32_t he_new_bar = letoh(pkt->get<uint32_t>());
-
- uint32_t bar_mask =
- BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
-
- // Writing 0xffffffff to a BAR tells the card to set the
- // value of the bar to a bitmask indicating the size of
- // memory it needs
- if (he_new_bar == 0xffffffff) {
- he_new_bar = ~(BARSize[barnum] - 1);
- } else {
- // does it mean something special to write 0 to a BAR?
- he_new_bar &= ~bar_mask;
- if (he_new_bar) {
- Addr space_base = BAR_IO_SPACE(he_old_bar) ?
- TSUNAMI_PCI0_IO : TSUNAMI_PCI0_MEMORY;
- BARAddrs[barnum] = he_new_bar + space_base;
- pioPort->sendStatusChange(Port::RangeChange);
+ if (!legacyIO[barnum]) {
+ // convert BAR values to host endianness
+ uint32_t he_old_bar = letoh(config.baseAddr[barnum]);
+ uint32_t he_new_bar = letoh(pkt->get<uint32_t>());
+
+ uint32_t bar_mask =
+ BAR_IO_SPACE(he_old_bar) ? BAR_IO_MASK : BAR_MEM_MASK;
+
+ // Writing 0xffffffff to a BAR tells the card to set the
+ // value of the bar to a bitmask indicating the size of
+ // memory it needs
+ if (he_new_bar == 0xffffffff) {
+ he_new_bar = ~(BARSize[barnum] - 1);
+ } else {
+ // does it mean something special to write 0 to a BAR?
+ he_new_bar &= ~bar_mask;
+ if (he_new_bar) {
+ BARAddrs[barnum] = BAR_IO_SPACE(he_old_bar) ?
+ platform->calcPciIOAddr(he_new_bar) :
+ platform->calcPciMemAddr(he_new_bar);
+ pioPort->sendStatusChange(Port::RangeChange);
+ }
}
+ config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
+ (he_old_bar & bar_mask));
}
- config.baseAddr[barnum] = htole((he_new_bar & ~bar_mask) |
- (he_old_bar & bar_mask));
}
break;
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
index a584a957d..5da8b2dfc 100644
--- a/src/dev/pcidev.hh
+++ b/src/dev/pcidev.hh
@@ -99,6 +99,9 @@ class PciDev : public DmaDevice
/** The current address mapping of the BARs */
Addr BARAddrs[6];
+ /** Whether the BARs are really hardwired legacy IO locations. */
+ bool legacyIO[6];
+
/**
* Does the given address lie within the space mapped by the given
* base address register?
diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h
index df57acdb0..5639d8e29 100644
--- a/src/dev/pcireg.h
+++ b/src/dev/pcireg.h
@@ -69,18 +69,18 @@ union PCIConfig {
};
// Common PCI offsets
-#define PCI_VENDOR_ID 0x00 // Vendor ID ro
-#define PCI_DEVICE_ID 0x02 // Device ID ro
-#define PCI_COMMAND 0x04 // Command rw
-#define PCI_STATUS 0x06 // Status rw
-#define PCI_REVISION_ID 0x08 // Revision ID ro
-#define PCI_CLASS_CODE 0x09 // Class Code ro
-#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
-#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
-#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
-#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
-#define PCI_HEADER_TYPE 0x0E // Header Type ro
-#define PCI_BIST 0x0F // Built in self test rw
+#define PCI_VENDOR_ID 0x00 // Vendor ID ro
+#define PCI_DEVICE_ID 0x02 // Device ID ro
+#define PCI_COMMAND 0x04 // Command rw
+#define PCI_STATUS 0x06 // Status rw
+#define PCI_REVISION_ID 0x08 // Revision ID ro
+#define PCI_CLASS_CODE 0x09 // Class Code ro
+#define PCI_SUB_CLASS_CODE 0x0A // Sub Class Code ro
+#define PCI_BASE_CLASS_CODE 0x0B // Base Class Code ro
+#define PCI_CACHE_LINE_SIZE 0x0C // Cache Line Size ro+
+#define PCI_LATENCY_TIMER 0x0D // Latency Timer ro+
+#define PCI_HEADER_TYPE 0x0E // Header Type ro
+#define PCI_BIST 0x0F // Built in self test rw
// some pci command reg bitfields
#define PCI_CMD_BME 0x04 // Bus master function enable
@@ -88,62 +88,62 @@ union PCIConfig {
#define PCI_CMD_IOSE 0x01 // I/O space enable
// Type 0 PCI offsets
-#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
-#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
-#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
-#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
-#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
-#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
-#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
-#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
-#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
-#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
-#define PCI0_RESERVED0 0x34
-#define PCI0_RESERVED1 0x38
-#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
-#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
-#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
-#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
+#define PCI0_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI0_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI0_BASE_ADDR2 0x18 // Base Address 2 rw
+#define PCI0_BASE_ADDR3 0x1C // Base Address 3 rw
+#define PCI0_BASE_ADDR4 0x20 // Base Address 4 rw
+#define PCI0_BASE_ADDR5 0x24 // Base Address 5 rw
+#define PCI0_CIS 0x28 // CardBus CIS Pointer ro
+#define PCI0_SUB_VENDOR_ID 0x2C // Sub-Vendor ID ro
+#define PCI0_SUB_SYSTEM_ID 0x2E // Sub-System ID ro
+#define PCI0_ROM_BASE_ADDR 0x30 // Expansion ROM Base Address rw
+#define PCI0_RESERVED0 0x34
+#define PCI0_RESERVED1 0x38
+#define PCI0_INTERRUPT_LINE 0x3C // Interrupt Line rw
+#define PCI0_INTERRUPT_PIN 0x3D // Interrupt Pin ro
+#define PCI0_MINIMUM_GRANT 0x3E // Maximum Grant ro
+#define PCI0_MAXIMUM_LATENCY 0x3F // Maximum Latency ro
// Type 1 PCI offsets
-#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
-#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
-#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
-#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
-#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
-#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
-#define PCI1_IO_BASE 0x1C // I/O Base rw
-#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
-#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
-#define PCI1_MEM_BASE 0x20 // Memory Base rw
-#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
-#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
-#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
-#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
-#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
-#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
-#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
-#define PCI1_RESERVED 0x34 // Reserved ro
-#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
-#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
-#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
-#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
+#define PCI1_BASE_ADDR0 0x10 // Base Address 0 rw
+#define PCI1_BASE_ADDR1 0x14 // Base Address 1 rw
+#define PCI1_PRI_BUS_NUM 0x18 // Primary Bus Number rw
+#define PCI1_SEC_BUS_NUM 0x19 // Secondary Bus Number rw
+#define PCI1_SUB_BUS_NUM 0x1A // Subordinate Bus Number rw
+#define PCI1_SEC_LAT_TIMER 0x1B // Secondary Latency Timer ro+
+#define PCI1_IO_BASE 0x1C // I/O Base rw
+#define PCI1_IO_LIMIT 0x1D // I/O Limit rw
+#define PCI1_SECONDARY_STATUS 0x1E // Secondary Status rw
+#define PCI1_MEM_BASE 0x20 // Memory Base rw
+#define PCI1_MEM_LIMIT 0x22 // Memory Limit rw
+#define PCI1_PRF_MEM_BASE 0x24 // Prefetchable Memory Base rw
+#define PCI1_PRF_MEM_LIMIT 0x26 // Prefetchable Memory Limit rw
+#define PCI1_PRF_BASE_UPPER 0x28 // Prefetchable Base Upper 32 rw
+#define PCI1_PRF_LIMIT_UPPER 0x2C // Prefetchable Limit Upper 32 rw
+#define PCI1_IO_BASE_UPPER 0x30 // I/O Base Upper 16 bits rw
+#define PCI1_IO_LIMIT_UPPER 0x32 // I/O Limit Upper 16 bits rw
+#define PCI1_RESERVED 0x34 // Reserved ro
+#define PCI1_ROM_BASE_ADDR 0x38 // Expansion ROM Base Address rw
+#define PCI1_INTR_LINE 0x3C // Interrupt Line rw
+#define PCI1_INTR_PIN 0x3D // Interrupt Pin ro
+#define PCI1_BRIDGE_CTRL 0x3E // Bridge Control rw
// Device specific offsets
-#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
+#define PCI_DEVICE_SPECIFIC 0x40 // 192 bytes
#define PCI_CONFIG_SIZE 0xFF
// Some Vendor IDs
-#define PCI_VENDOR_DEC 0x1011
-#define PCI_VENDOR_NCR 0x101A
-#define PCI_VENDOR_QLOGIC 0x1077
-#define PCI_VENDOR_SIMOS 0x1291
+#define PCI_VENDOR_DEC 0x1011
+#define PCI_VENDOR_NCR 0x101A
+#define PCI_VENDOR_QLOGIC 0x1077
+#define PCI_VENDOR_SIMOS 0x1291
// Some Product IDs
-#define PCI_PRODUCT_DEC_PZA 0x0008
-#define PCI_PRODUCT_NCR_810 0x0001
-#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
-#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
-#define PCI_PRODUCT_SIMOS_ETHER 0x1292
+#define PCI_PRODUCT_DEC_PZA 0x0008
+#define PCI_PRODUCT_NCR_810 0x0001
+#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
+#define PCI_PRODUCT_SIMOS_SIMOS 0x1291
+#define PCI_PRODUCT_SIMOS_ETHER 0x1292
#endif // __PCIREG_H__
diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc
index 37f7ff680..97d6c04af 100644
--- a/src/dev/pktfifo.cc
+++ b/src/dev/pktfifo.cc
@@ -40,23 +40,24 @@ PacketFifo::copyout(void *dest, int offset, int len)
if (offset + len >= size())
return false;
- list<EthPacketPtr>::iterator p = fifo.begin();
- list<EthPacketPtr>::iterator end = fifo.end();
+ iterator i = fifo.begin();
+ iterator end = fifo.end();
while (len > 0) {
- while (offset >= (*p)->length) {
- offset -= (*p)->length;
- ++p;
+ EthPacketPtr &pkt = i->packet;
+ while (offset >= pkt->length) {
+ offset -= pkt->length;
+ ++i;
}
- if (p == end)
+ if (i == end)
panic("invalid fifo");
- int size = min((*p)->length - offset, len);
- memcpy(data, (*p)->data, size);
+ int size = min(pkt->length - offset, len);
+ memcpy(data, pkt->data, size);
offset = 0;
len -= size;
data += size;
- ++p;
+ ++i;
}
return true;
@@ -64,6 +65,26 @@ PacketFifo::copyout(void *dest, int offset, int len)
void
+PacketFifoEntry::serialize(const string &base, ostream &os)
+{
+ packet->serialize(base + ".packet", os);
+ paramOut(os, base + ".slack", slack);
+ paramOut(os, base + ".number", number);
+ paramOut(os, base + ".priv", priv);
+}
+
+void
+PacketFifoEntry::unserialize(const string &base, Checkpoint *cp,
+ const string &section)
+{
+ packet = new EthPacketData(16384);
+ packet->unserialize(base + ".packet", cp, section);
+ paramIn(cp, section, base + ".slack", slack);
+ paramIn(cp, section, base + ".number", number);
+ paramIn(cp, section, base + ".priv", priv);
+}
+
+void
PacketFifo::serialize(const string &base, ostream &os)
{
paramOut(os, base + ".size", _size);
@@ -72,11 +93,11 @@ PacketFifo::serialize(const string &base, ostream &os)
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;
+ iterator entry = fifo.begin();
+ iterator end = fifo.end();
+ while (entry != end) {
+ entry->serialize(csprintf("%s.entry%d", base, i), os);
+ ++entry;
++i;
}
}
@@ -94,8 +115,8 @@ PacketFifo::unserialize(const string &base, Checkpoint *cp,
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);
+ PacketFifoEntry entry;
+ entry.unserialize(csprintf("%s.entry%d", base, i), cp, section);
+ fifo.push_back(entry);
}
}
diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh
index 45157ba41..6ded248be 100644
--- a/src/dev/pktfifo.hh
+++ b/src/dev/pktfifo.hh
@@ -39,20 +39,59 @@
#include "sim/serialize.hh"
class Checkpoint;
+
+struct PacketFifoEntry
+{
+ EthPacketPtr packet;
+ uint64_t number;
+ int slack;
+ int priv;
+
+ PacketFifoEntry()
+ {
+ clear();
+ }
+
+ PacketFifoEntry(const PacketFifoEntry &s)
+ : packet(s.packet), number(s.number), slack(s.slack), priv(s.priv)
+ {
+ }
+
+ PacketFifoEntry(EthPacketPtr p, uint64_t n)
+ : packet(p), number(n), slack(0), priv(-1)
+ {
+ }
+
+ void clear()
+ {
+ packet = NULL;
+ number = 0;
+ slack = 0;
+ priv = -1;
+ }
+
+ void serialize(const std::string &base, std::ostream &os);
+ void unserialize(const std::string &base, Checkpoint *cp,
+ const std::string &section);
+};
+
class PacketFifo
{
public:
- typedef std::list<EthPacketPtr> fifo_list;
+
+ typedef std::list<PacketFifoEntry> fifo_list;
typedef fifo_list::iterator iterator;
protected:
- std::list<EthPacketPtr> fifo;
+ std::list<PacketFifoEntry> fifo;
+ uint64_t _counter;
int _maxsize;
int _size;
int _reserved;
public:
- explicit PacketFifo(int max) : _maxsize(max), _size(0), _reserved(0) {}
+ explicit PacketFifo(int max)
+ : _counter(0), _maxsize(max), _size(0), _reserved(0) {}
virtual ~PacketFifo() {}
int packets() const { return fifo.size(); }
@@ -73,18 +112,21 @@ class PacketFifo
iterator begin() { return fifo.begin(); }
iterator end() { return fifo.end(); }
- EthPacketPtr front() { return fifo.front(); }
+ EthPacketPtr front() { return fifo.begin()->packet; }
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);
+
+ PacketFifoEntry entry;
+ entry.packet = ptr;
+ entry.number = _counter++;
+ fifo.push_back(entry);
_reserved = 0;
return true;
}
@@ -94,18 +136,17 @@ class PacketFifo
if (empty())
return;
- EthPacketPtr &packet = fifo.front();
- _size -= packet->length;
- _size -= packet->slack;
- packet->slack = 0;
- packet = NULL;
+ iterator entry = fifo.begin();
+ _size -= entry->packet->length;
+ _size -= entry->slack;
+ entry->packet = NULL;
fifo.pop_front();
}
void clear()
{
for (iterator i = begin(); i != end(); ++i)
- (*i)->slack = 0;
+ i->clear();
fifo.clear();
_size = 0;
_reserved = 0;
@@ -113,51 +154,48 @@ class PacketFifo
void remove(iterator i)
{
- EthPacketPtr &packet = *i;
if (i != fifo.begin()) {
iterator prev = i;
--prev;
assert(prev != fifo.end());
- (*prev)->slack += packet->length;
+ prev->slack += i->packet->length;
+ prev->slack += i->slack;
} else {
- _size -= packet->length;
- _size -= packet->slack;
+ _size -= i->packet->length;
+ _size -= i->slack;
}
- packet->slack = 0;
- packet = NULL;
+ i->clear();
fifo.erase(i);
}
bool copyout(void *dest, int offset, int len);
- int countPacketsBefore(iterator end)
+ int countPacketsBefore(iterator i)
{
- iterator i = fifo.begin();
- int count = 0;
-
- while (i != end) {
- ++count;
- ++i;
- }
-
- return count;
+ if (i == fifo.end())
+ return 0;
+ return i->number - fifo.begin()->number;
}
int countPacketsAfter(iterator i)
{
iterator end = fifo.end();
- int count = 0;
+ if (i == end)
+ return 0;
+ return (--end)->number - i->number;
+ }
- while (i != end) {
- ++count;
- ++i;
- }
+ void check()
+ {
+ int total = 0;
+ for (iterator i = begin(); i != end(); ++i)
+ total += i->packet->length + i->slack;
- return count;
+ if (total != _size)
+ panic("total (%d) is not == to size (%d)\n", total, _size);
}
-
/**
* Serialization stuff
*/
diff --git a/src/dev/platform.hh b/src/dev/platform.hh
index 699b168ce..5f6f1df81 100644
--- a/src/dev/platform.hh
+++ b/src/dev/platform.hh
@@ -46,7 +46,7 @@
class PciConfigAll;
class IntrControl;
-class SimConsole;
+class Terminal;
class Uart;
class System;
@@ -69,7 +69,9 @@ class Platform : public SimObject
virtual void postPciInt(int line);
virtual void clearPciInt(int line);
virtual Addr pciToDma(Addr pciAddr) const;
- virtual Addr calcConfigAddr(int bus, int dev, int func) = 0;
+ virtual Addr calcPciConfigAddr(int bus, int dev, int func) = 0;
+ virtual Addr calcPciIOAddr(Addr addr) = 0;
+ virtual Addr calcPciMemAddr(Addr addr) = 0;
virtual void registerPciDevice(uint8_t bus, uint8_t dev, uint8_t func,
uint8_t intr);
diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h
index 37255777b..b1406c464 100644
--- a/src/dev/rtcreg.h
+++ b/src/dev/rtcreg.h
@@ -30,32 +30,32 @@
* Nathan Binkert
*/
-#define RTC_SEC 0x00
-#define RTC_SEC_ALRM 0x01
-#define RTC_MIN 0x02
-#define RTC_MIN_ALRM 0x03
-#define RTC_HR 0x04
-#define RTC_HR_ALRM 0x05
-#define RTC_DOW 0x06
-#define RTC_DOM 0x07
-#define RTC_MON 0x08
-#define RTC_YEAR 0x09
+static const int RTC_SEC = 0x00;
+static const int RTC_SEC_ALRM = 0x01;
+static const int RTC_MIN = 0x02;
+static const int RTC_MIN_ALRM = 0x03;
+static const int RTC_HR = 0x04;
+static const int RTC_HR_ALRM = 0x05;
+static const int RTC_DOW = 0x06;
+static const int RTC_DOM = 0x07;
+static const int RTC_MON = 0x08;
+static const int RTC_YEAR = 0x09;
-#define RTC_STAT_REGA 0x0A
-#define RTCA_1024HZ 0x06 /* 1024Hz periodic interrupt frequency */
-#define RTCA_32768HZ 0x20 /* 22-stage divider, 32.768KHz timebase */
-#define RTCA_UIP 0x80 /* 1 = date and time update in progress */
+static const int RTC_STAT_REGA = 0x0A;
+static const int RTCA_1024HZ = 0x06; /* 1024Hz periodic interrupt frequency */
+static const int RTCA_32768HZ = 0x20; /* 22-stage divider, 32.768KHz timebase */
+static const int RTCA_UIP = 0x80; /* 1 = date and time update in progress */
-#define RTC_STAT_REGB 0x0B
-#define RTCB_DST 0x01 /* USA Daylight Savings Time enable */
-#define RTCB_24HR 0x02 /* 0 = 12 hours, 1 = 24 hours */
-#define RTCB_BIN 0x04 /* 0 = BCD, 1 = Binary coded time */
-#define RTCB_SQWE 0x08 /* 1 = output sqare wave at SQW pin */
-#define RTCB_UPDT_IE 0x10 /* 1 = enable update-ended interrupt */
-#define RTCB_ALRM_IE 0x20 /* 1 = enable alarm interrupt */
-#define RTCB_PRDC_IE 0x40 /* 1 = enable periodic clock interrupt */
-#define RTCB_NO_UPDT 0x80 /* stop clock updates */
+static const int RTC_STAT_REGB = 0x0B;
+static const int RTCB_DST = 0x01; /* USA Daylight Savings Time enable */
+static const int RTCB_24HR = 0x02; /* 0 = 12 hours, 1 = 24 hours */
+static const int RTCB_BIN = 0x04; /* 0 = BCD, 1 = Binary coded time */
+static const int RTCB_SQWE = 0x08; /* 1 = output sqare wave at SQW pin */
+static const int RTCB_UPDT_IE = 0x10; /* 1 = enable update-ended interrupt */
+static const int RTCB_ALRM_IE = 0x20; /* 1 = enable alarm interrupt */
+static const int RTCB_PRDC_IE = 0x40; /* 1 = enable periodic clock interrupt */
+static const int RTCB_NO_UPDT = 0x80; /* stop clock updates */
-#define RTC_STAT_REGC 0x0C
-#define RTC_STAT_REGD 0x0D
+static const int RTC_STAT_REGC = 0x0C;
+static const int RTC_STAT_REGD = 0x0D;
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
index c63966528..37c6a8259 100644
--- a/src/dev/sinic.cc
+++ b/src/dev/sinic.cc
@@ -33,6 +33,7 @@
#include <string>
#include "arch/vtophys.hh"
+#include "base/debug.hh"
#include "base/inet.hh"
#include "cpu/thread_context.hh"
#include "cpu/intr_control.hh"
@@ -40,11 +41,11 @@
#include "dev/sinic.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
-#include "sim/debug.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"
#include "sim/stats.hh"
+using namespace std;
using namespace Net;
using namespace TheISA;
@@ -265,6 +266,35 @@ Device::regStats()
totPackets = txPackets + rxPackets;
txPacketRate = txPackets / simSeconds;
rxPacketRate = rxPackets / simSeconds;
+
+ _maxVnicDistance = 0;
+
+ maxVnicDistance
+ .name(name() + ".maxVnicDistance")
+ .desc("maximum vnic distance")
+ ;
+
+ totalVnicDistance
+ .name(name() + ".totalVnicDistance")
+ .desc("total vnic distance")
+ ;
+ numVnicDistance
+ .name(name() + ".numVnicDistance")
+ .desc("number of vnic distance measurements")
+ ;
+
+ avgVnicDistance
+ .name(name() + ".avgVnicDistance")
+ .desc("average vnic distance")
+ ;
+
+ avgVnicDistance = totalVnicDistance / numVnicDistance;
+}
+
+void
+Device::resetStats()
+{
+ _maxVnicDistance = 0;
}
EtherInt*
@@ -289,6 +319,10 @@ Device::prepareIO(int cpu, int index)
index, size);
}
+//add stats for head of line blocking
+//add stats for average fifo length
+//add stats for average number of vnics busy
+
void
Device::prepareRead(int cpu, int index)
{
@@ -301,7 +335,7 @@ Device::prepareRead(int cpu, int index)
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_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
rxdone = set_RxDone_NotHigh(rxdone, rxLow);
regs.RxData = vnic.RxData;
regs.RxDone = rxdone;
@@ -311,10 +345,23 @@ Device::prepareRead(int cpu, int index)
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);
+ txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
regs.TxData = vnic.TxData;
regs.TxDone = txdone;
regs.TxWait = txdone;
+
+ int head = 0xffff;
+
+ if (!rxFifo.empty()) {
+ int vnic = rxFifo.begin()->priv;
+ if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
+ head = vnic;
+ }
+
+ regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
+ regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
+ regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
+ regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
}
void
@@ -332,7 +379,7 @@ Device::read(PacketPtr pkt)
assert(config.command & PCI_CMD_MSE);
assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
- int cpu = pkt->req->getCpuNum();
+ int cpu = pkt->req->contextId();
Addr daddr = pkt->getAddr() - BARAddrs[0];
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
@@ -419,7 +466,7 @@ Device::write(PacketPtr pkt)
assert(config.command & PCI_CMD_MSE);
assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
- int cpu = pkt->req->getCpuNum();
+ int cpu = pkt->req->contextId();
Addr daddr = pkt->getAddr() - BARAddrs[0];
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
@@ -473,22 +520,25 @@ Device::write(PacketPtr pkt)
vnic.rxUnique = rxUnique++;
vnic.RxDone = Regs::RxDone_Busy;
vnic.RxData = pkt->get<uint64_t>();
+ rxBusyCount++;
if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
panic("vtophys not implemented in newmem");
-/* Addr vaddr = Regs::get_RxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+ 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);*/
+ vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
+#endif
} else {
DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
index, vnic.rxUnique);
}
- if (vnic.rxPacket == rxFifo.end()) {
+ if (vnic.rxIndex == rxFifo.end()) {
DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
rxList.push_back(index);
} else {
@@ -512,15 +562,17 @@ Device::write(PacketPtr pkt)
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);
+#ifdef SINIC_VTOPHYS
+ Addr vaddr = Regs::get_TxData_Addr(reg64);
Addr paddr = vtophys(req->xc, vaddr);
- DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+ DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
"vaddr=%#x, paddr=%#x\n",
index, vnic.txUnique, vaddr, paddr);
- vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+ vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
+#endif
} else {
- DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+ DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
index, vnic.txUnique);
}
@@ -643,7 +695,8 @@ Base::cpuIntrPost(Tick when)
if (intrEvent)
intrEvent->squash();
- intrEvent = new IntrEvent(this, intrTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrTick);
}
void
@@ -761,18 +814,31 @@ Device::reset()
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.ZeroCopySize = params()->zero_copy_size;
+ regs.ZeroCopyMark = params()->zero_copy_threshold;
regs.VirtualCount = params()->virtual_count;
+ regs.RxMaxIntr = params()->rx_max_intr;
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.RxFifoLow = params()->rx_fifo_low_mark;
+ regs.TxFifoLow = params()->tx_fifo_threshold;
+ regs.RxFifoHigh = params()->rx_fifo_threshold;
+ regs.TxFifoHigh = params()->tx_fifo_high_mark;
regs.HwAddr = params()->hardware_address;
+ if (regs.RxMaxCopy < regs.ZeroCopyMark)
+ panic("Must be able to copy at least as many bytes as the threshold");
+
+ if (regs.ZeroCopySize >= regs.ZeroCopyMark)
+ panic("The number of bytes to copy must be less than the threshold");
+
rxList.clear();
rxBusy.clear();
rxActive = -1;
txList.clear();
+ rxBusyCount = 0;
+ rxDirtyCount = 0;
+ rxMappedCount = 0;
rxState = rxIdle;
txState = txIdle;
@@ -788,7 +854,7 @@ Device::reset()
virtualRegs.clear();
virtualRegs.resize(size);
for (int i = 0; i < size; ++i)
- virtualRegs[i].rxPacket = rxFifo.end();
+ virtualRegs[i].rxIndex = rxFifo.end();
}
void
@@ -822,6 +888,7 @@ Device::rxKick()
}
next:
+ rxFifo.check();
if (rxState == rxIdle)
goto exit;
@@ -845,12 +912,28 @@ Device::rxKick()
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)) {
+ bool busy = Regs::get_RxDone_Busy(vn->RxDone);
+ if (vn->rxIndex != end) {
+ bool dirty = vn->rxPacketOffset > 0;
+ const char *status;
+
+ if (busy && dirty)
+ status = "busy,dirty";
+ else if (busy)
+ status = "busy";
+ else if (dirty)
+ status = "dirty";
+ else
+ status = "mapped";
+
DPRINTF(EthernetSM,
- "vnic %d (rxunique %d), has outstanding packet %d\n",
- i, vn->rxUnique,
- rxFifo.countPacketsBefore(vn->rxPacket));
+ "vnic %d %s (rxunique %d), packet %d, slack %d\n",
+ i, status, vn->rxUnique,
+ rxFifo.countPacketsBefore(vn->rxIndex),
+ vn->rxIndex->slack);
+ } else if (busy) {
+ DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
+ i, vn->rxUnique);
}
}
}
@@ -860,7 +943,7 @@ Device::rxKick()
rxBusy.pop_front();
vnic = &virtualRegs[rxActive];
- if (vnic->rxPacket == rxFifo.end())
+ if (vnic->rxIndex == rxFifo.end())
panic("continuing vnic without packet\n");
DPRINTF(EthernetSM,
@@ -869,6 +952,14 @@ Device::rxKick()
rxState = rxBeginCopy;
+ int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
+ totalVnicDistance += vnic_distance;
+ numVnicDistance += 1;
+ if (vnic_distance > _maxVnicDistance) {
+ maxVnicDistance = vnic_distance;
+ _maxVnicDistance = vnic_distance;
+ }
+
break;
}
@@ -891,14 +982,16 @@ Device::rxKick()
rxActive, vnic->rxUnique);
// Grab a new packet from the fifo.
- vnic->rxPacket = rxFifoPtr++;
+ vnic->rxIndex = rxFifoPtr++;
+ vnic->rxIndex->priv = rxActive;
vnic->rxPacketOffset = 0;
- vnic->rxPacketBytes = (*vnic->rxPacket)->length;
+ vnic->rxPacketBytes = vnic->rxIndex->packet->length;
assert(vnic->rxPacketBytes);
+ rxMappedCount++;
vnic->rxDoneData = 0;
/* scope for variables */ {
- IpPtr ip(*vnic->rxPacket);
+ IpPtr ip(vnic->rxIndex->packet);
if (ip) {
DPRINTF(Ethernet, "ID is %d\n", ip->id());
vnic->rxDoneData |= Regs::RxDone_IpPacket;
@@ -939,16 +1032,26 @@ Device::rxKick()
rxDmaAddr = params()->platform->pciToDma(
Regs::get_RxData_Addr(vnic->RxData));
- rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
+ rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
vnic->rxPacketBytes);
- rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
+
+ /*
+ * if we're doing zero/delay copy and we're below the fifo
+ * threshold, see if we should try to do the zero/defer copy
+ */
+ if ((Regs::get_Config_ZeroCopy(regs.Config) ||
+ Regs::get_Config_DelayCopy(regs.Config)) &&
+ !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
+ if (rxDmaLen > regs.ZeroCopyMark)
+ rxDmaLen = regs.ZeroCopySize;
+ }
+ rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
rxState = rxCopy;
if (rxDmaAddr == 1LL) {
rxState = rxCopyDone;
break;
}
-
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
break;
@@ -959,17 +1062,25 @@ Device::rxKick()
case rxCopyDone:
vnic->RxDone = vnic->rxDoneData;
vnic->RxDone |= Regs::RxDone_Complete;
+ rxBusyCount--;
if (vnic->rxPacketBytes == rxDmaLen) {
+ if (vnic->rxPacketOffset)
+ rxDirtyCount--;
+
// 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();
+ rxFifo.remove(vnic->rxIndex);
+ vnic->rxIndex = rxFifo.end();
+ rxMappedCount--;
} else {
+ if (!vnic->rxPacketOffset)
+ rxDirtyCount++;
+
vnic->rxPacketBytes -= rxDmaLen;
vnic->rxPacketOffset += rxDmaLen;
vnic->RxDone |= Regs::RxDone_More;
@@ -989,10 +1100,10 @@ Device::rxKick()
rxEmpty = true;
}
- if (rxFifo.size() < params()->rx_fifo_low_mark)
+ if (rxFifo.size() < regs.RxFifoLow)
rxLow = true;
- if (rxFifo.size() > params()->rx_fifo_threshold)
+ if (rxFifo.size() > regs.RxFifoHigh)
rxLow = false;
devIntrPost(Regs::Intr_RxDMA);
@@ -1044,7 +1155,7 @@ Device::transmit()
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
txFifo.avail());
- goto reschedule;
+ return;
}
txFifo.pop();
@@ -1072,15 +1183,9 @@ Device::transmit()
txFifo.avail());
interrupts = Regs::Intr_TxPacket;
- if (txFifo.size() < regs.TxFifoMark)
+ if (txFifo.size() < regs.TxFifoLow)
interrupts |= Regs::Intr_TxLow;
devIntrPost(interrupts);
-
- reschedule:
- if (!txFifo.empty() && !txEvent.scheduled()) {
- DPRINTF(Ethernet, "reschedule transmit\n");
- txEvent.schedule(curTick + retryTime);
- }
}
void
@@ -1211,7 +1316,7 @@ Device::transferDone()
DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
- txEvent.reschedule(curTick + ticks(1), true);
+ reschedule(txEvent, curTick + ticks(1), true);
}
bool
@@ -1278,7 +1383,7 @@ Device::recvPacket(EthPacketPtr packet)
return true;
}
- if (rxFifo.size() >= regs.RxFifoMark)
+ if (rxFifo.size() >= regs.RxFifoHigh)
devIntrPost(Regs::Intr_RxHigh);
if (!rxFifo.push(packet)) {
@@ -1351,7 +1456,8 @@ Base::unserialize(Checkpoint *cp, const std::string &section)
Tick intrEventTick;
UNSERIALIZE_SCALAR(intrEventTick);
if (intrEventTick) {
- intrEvent = new IntrEvent(this, intrEventTick, true);
+ intrEvent = new IntrEvent(this, true);
+ schedule(intrEvent, intrEventTick);
}
}
@@ -1372,19 +1478,13 @@ Device::serialize(std::ostream &os)
TxStateStrings[txState]);
/*
- * Serialize the device registers
+ * Serialize the device registers that could be modified by the OS.
*/
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
@@ -1400,12 +1500,12 @@ Device::serialize(std::ostream &os)
paramOut(os, reg + ".TxData", vnic->TxData);
paramOut(os, reg + ".TxDone", vnic->TxDone);
- bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+ bool rxPacketExists = vnic->rxIndex != rxFifo.end();
paramOut(os, reg + ".rxPacketExists", rxPacketExists);
if (rxPacketExists) {
int rxPacket = 0;
PacketFifo::iterator i = rxFifo.begin();
- while (i != vnic->rxPacket) {
+ while (i != vnic->rxIndex) {
assert(i != rxFifo.end());
++i;
++rxPacket;
@@ -1418,10 +1518,15 @@ Device::serialize(std::ostream &os)
paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
}
- int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+ int rxFifoPtr = -1;
+ if (this->rxFifoPtr != rxFifo.end())
+ rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
SERIALIZE_SCALAR(rxFifoPtr);
SERIALIZE_SCALAR(rxActive);
+ SERIALIZE_SCALAR(rxBusyCount);
+ SERIALIZE_SCALAR(rxDirtyCount);
+ SERIALIZE_SCALAR(rxMappedCount);
VirtualList::iterator i, end;
for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
@@ -1478,21 +1583,18 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
Base::unserialize(cp, section);
/*
- * Unserialize the device registers
+ * Unserialize the device registers that may have been written by the OS.
*/
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);
+ UNSERIALIZE_SCALAR(rxBusyCount);
+ UNSERIALIZE_SCALAR(rxDirtyCount);
+ UNSERIALIZE_SCALAR(rxMappedCount);
int rxListSize;
UNSERIALIZE_SCALAR(rxListSize);
@@ -1533,9 +1635,13 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
int rxFifoPtr;
UNSERIALIZE_SCALAR(rxFifoPtr);
- this->rxFifoPtr = rxFifo.begin();
- for (int i = 0; i < rxFifoPtr; ++i)
- ++this->rxFifoPtr;
+ if (rxFifoPtr >= 0) {
+ this->rxFifoPtr = rxFifo.begin();
+ for (int i = 0; i < rxFifoPtr; ++i)
+ ++this->rxFifoPtr;
+ } else {
+ this->rxFifoPtr = rxFifo.end();
+ }
/*
* Unserialize tx state machine
@@ -1582,15 +1688,15 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
if (rxPacketExists) {
int rxPacket;
paramIn(cp, section, reg + ".rxPacket", rxPacket);
- vnic->rxPacket = rxFifo.begin();
+ vnic->rxIndex = rxFifo.begin();
while (rxPacket--)
- ++vnic->rxPacket;
+ ++vnic->rxIndex;
paramIn(cp, section, reg + ".rxPacketOffset",
vnic->rxPacketOffset);
paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
} else {
- vnic->rxPacket = rxFifo.end();
+ vnic->rxIndex = rxFifo.end();
}
paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
}
@@ -1601,7 +1707,7 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
Tick transmitTick;
UNSERIALIZE_SCALAR(transmitTick);
if (transmitTick)
- txEvent.schedule(curTick + transmitTick);
+ schedule(txEvent, curTick + transmitTick);
pioPort->sendStatusChange(Port::RangeChange);
diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh
index e85d93fe4..cd8412ef4 100644
--- a/src/dev/sinic.hh
+++ b/src/dev/sinic.hh
@@ -115,19 +115,24 @@ class Device : public Base
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
+ uint32_t ZeroCopySize; // 0x18
+ uint32_t ZeroCopyMark; // 0x1c
+ uint32_t VirtualCount; // 0x20
+ uint32_t RxMaxIntr; // 0x24
+ uint32_t RxFifoSize; // 0x28
+ uint32_t TxFifoSize; // 0x2c
+ uint32_t RxFifoLow; // 0x30
+ uint32_t TxFifoLow; // 0x34
+ uint32_t RxFifoHigh; // 0x38
+ uint32_t TxFifoHigh; // 0x3c
+ uint64_t RxData; // 0x40
+ uint64_t RxDone; // 0x48
+ uint64_t RxWait; // 0x50
+ uint64_t TxData; // 0x58
+ uint64_t TxDone; // 0x60
+ uint64_t TxWait; // 0x68
+ uint64_t HwAddr; // 0x70
+ uint64_t RxStatus; // 0x78
} regs;
struct VirtualReg {
@@ -136,7 +141,7 @@ class Device : public Base
uint64_t TxData;
uint64_t TxDone;
- PacketFifo::iterator rxPacket;
+ PacketFifo::iterator rxIndex;
int rxPacketOffset;
int rxPacketBytes;
uint64_t rxDoneData;
@@ -159,6 +164,10 @@ class Device : public Base
int rxActive;
VirtualList txList;
+ int rxBusyCount;
+ int rxMappedCount;
+ int rxDirtyCount;
+
uint8_t &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
@@ -274,34 +283,42 @@ class Device : public Base
* Statistics
*/
private:
- Stats::Scalar<> rxBytes;
+ Stats::Scalar rxBytes;
Stats::Formula rxBandwidth;
- Stats::Scalar<> rxPackets;
+ 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::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::Scalar txPackets;
Stats::Formula txPacketRate;
- Stats::Scalar<> txIpPackets;
- Stats::Scalar<> txTcpPackets;
- Stats::Scalar<> txUdpPackets;
- Stats::Scalar<> txIpChecksums;
- Stats::Scalar<> txTcpChecksums;
- Stats::Scalar<> txUdpChecksums;
+ Stats::Scalar txIpPackets;
+ Stats::Scalar txTcpPackets;
+ Stats::Scalar txUdpPackets;
+ Stats::Scalar txIpChecksums;
+ Stats::Scalar txTcpChecksums;
+ Stats::Scalar txUdpChecksums;
+
+ Stats::Scalar totalVnicDistance;
+ Stats::Scalar numVnicDistance;
+ Stats::Scalar maxVnicDistance;
+ Stats::Formula avgVnicDistance;
+
+ int _maxVnicDistance;
public:
virtual void regStats();
+ virtual void resetStats();
/**
* Serialization stuff
diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh
index de4188145..7ac7abad0 100644
--- a/src/dev/sinicreg.hh
+++ b/src/dev/sinicreg.hh
@@ -48,7 +48,7 @@
static const uint64_t NAME##_width = WIDTH; \
static const uint64_t NAME##_offset = OFFSET; \
static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \
- static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
+ static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
static inline uint64_t get_##NAME(uint64_t reg) \
{ return (reg & NAME) >> OFFSET; } \
static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \
@@ -67,20 +67,25 @@ __SINIC_REG32(IntrStatus, 0x08); // 32: interrupt status
__SINIC_REG32(IntrMask, 0x0c); // 32: interrupt mask
__SINIC_REG32(RxMaxCopy, 0x10); // 32: max bytes per rx copy
__SINIC_REG32(TxMaxCopy, 0x14); // 32: max bytes per tx copy
-__SINIC_REG32(RxMaxIntr, 0x18); // 32: max receives per interrupt
-__SINIC_REG32(VirtualCount, 0x1c); // 32: number of virutal NICs
-__SINIC_REG32(RxFifoSize, 0x20); // 32: rx fifo capacity in bytes
-__SINIC_REG32(TxFifoSize, 0x24); // 32: tx fifo capacity in bytes
-__SINIC_REG32(RxFifoMark, 0x28); // 32: rx fifo high watermark
-__SINIC_REG32(TxFifoMark, 0x2c); // 32: tx fifo low watermark
-__SINIC_REG32(RxData, 0x30); // 64: receive data
-__SINIC_REG32(RxDone, 0x38); // 64: receive done
-__SINIC_REG32(RxWait, 0x40); // 64: receive done (busy wait)
-__SINIC_REG32(TxData, 0x48); // 64: transmit data
-__SINIC_REG32(TxDone, 0x50); // 64: transmit done
-__SINIC_REG32(TxWait, 0x58); // 64: transmit done (busy wait)
-__SINIC_REG32(HwAddr, 0x60); // 64: mac address
-__SINIC_REG32(Size, 0x68); // register addres space size
+__SINIC_REG32(ZeroCopySize, 0x18); // 32: bytes to copy if below threshold
+__SINIC_REG32(ZeroCopyMark, 0x1c); // 32: only zero-copy above this threshold
+__SINIC_REG32(VirtualCount, 0x20); // 32: number of virutal NICs
+__SINIC_REG32(RxMaxIntr, 0x24); // 32: max receives per interrupt
+__SINIC_REG32(RxFifoSize, 0x28); // 32: rx fifo capacity in bytes
+__SINIC_REG32(TxFifoSize, 0x2c); // 32: tx fifo capacity in bytes
+__SINIC_REG32(RxFifoLow, 0x30); // 32: rx fifo low watermark
+__SINIC_REG32(TxFifoLow, 0x34); // 32: tx fifo low watermark
+__SINIC_REG32(RxFifoHigh, 0x38); // 32: rx fifo high watermark
+__SINIC_REG32(TxFifoHigh, 0x3c); // 32: tx fifo high watermark
+__SINIC_REG32(RxData, 0x40); // 64: receive data
+__SINIC_REG32(RxDone, 0x48); // 64: receive done
+__SINIC_REG32(RxWait, 0x50); // 64: receive done (busy wait)
+__SINIC_REG32(TxData, 0x58); // 64: transmit data
+__SINIC_REG32(TxDone, 0x60); // 64: transmit done
+__SINIC_REG32(TxWait, 0x68); // 64: transmit done (busy wait)
+__SINIC_REG32(HwAddr, 0x70); // 64: mac address
+__SINIC_REG32(RxStatus, 0x78);
+__SINIC_REG32(Size, 0x80); // register addres space size
// Config register bits
__SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy
@@ -116,9 +121,10 @@ __SINIC_REG32(Intr_NoDelay, 0x01cc); // interrupts that aren't coalesced
__SINIC_REG32(Intr_Res, ~0x01ff); // reserved interrupt bits
// RX Data Description
-__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual
-__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k
-__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
+__SINIC_VAL64(RxData_NoDelay, 61, 1); // Don't Delay this copy
+__SINIC_VAL64(RxData_Vaddr, 60, 1); // Addr is virtual
+__SINIC_VAL64(RxData_Len, 40, 20); // 0 - 256k
+__SINIC_VAL64(RxData_Addr, 0, 40); // Address 1TB
// TX Data Description
__SINIC_VAL64(TxData_More, 63, 1); // Packet not complete (will dma more)
@@ -159,6 +165,11 @@ __SINIC_VAL64(TxDone_Res6, 21, 1); // reserved
__SINIC_VAL64(TxDone_Res7, 20, 1); // reserved
__SINIC_VAL64(TxDone_CopyLen, 0, 20); // up to 256k
+__SINIC_VAL64(RxStatus_Dirty, 48, 16);
+__SINIC_VAL64(RxStatus_Mapped, 32, 16);
+__SINIC_VAL64(RxStatus_Busy, 16, 16);
+__SINIC_VAL64(RxStatus_Head, 0, 16);
+
struct Info
{
uint8_t size;
@@ -174,31 +185,37 @@ regInfo(Addr daddr)
{
static Regs::Info invalid = { 0, false, false, "invalid" };
static Regs::Info info [] = {
- { 4, true, true, "Config" },
- { 4, false, true, "Command" },
- { 4, true, true, "IntrStatus" },
- { 4, true, true, "IntrMask" },
- { 4, true, false, "RxMaxCopy" },
- { 4, true, false, "TxMaxCopy" },
- { 4, true, false, "RxMaxIntr" },
- { 4, true, false, "VirtualCount" },
- { 4, true, false, "RxFifoSize" },
- { 4, true, false, "TxFifoSize" },
- { 4, true, false, "RxFifoMark" },
- { 4, true, false, "TxFifoMark" },
- { 8, true, true, "RxData" },
+ { 4, true, true, "Config" },
+ { 4, false, true, "Command" },
+ { 4, true, true, "IntrStatus" },
+ { 4, true, true, "IntrMask" },
+ { 4, true, false, "RxMaxCopy" },
+ { 4, true, false, "TxMaxCopy" },
+ { 4, true, false, "ZeroCopySize" },
+ { 4, true, false, "ZeroCopyMark" },
+ { 4, true, false, "VirtualCount" },
+ { 4, true, false, "RxMaxIntr" },
+ { 4, true, false, "RxFifoSize" },
+ { 4, true, false, "TxFifoSize" },
+ { 4, true, false, "RxFifoLow" },
+ { 4, true, false, "TxFifoLow" },
+ { 4, true, false, "RxFifoHigh" },
+ { 4, true, false, "TxFifoHigh" },
+ { 8, true, true, "RxData" },
+ invalid,
+ { 8, true, false, "RxDone" },
invalid,
- { 8, true, false, "RxDone" },
+ { 8, true, false, "RxWait" },
invalid,
- { 8, true, false, "RxWait" },
+ { 8, true, true, "TxData" },
invalid,
- { 8, true, true, "TxData" },
+ { 8, true, false, "TxDone" },
invalid,
- { 8, true, false, "TxDone" },
+ { 8, true, false, "TxWait" },
invalid,
- { 8, true, false, "TxWait" },
+ { 8, true, false, "HwAddr" },
invalid,
- { 8, true, false, "HwAddr" },
+ { 8, true, false, "RxStatus" },
invalid,
};
diff --git a/src/dev/sparc/T1000.py b/src/dev/sparc/T1000.py
index a033e27e2..cbf390737 100644
--- a/src/dev/sparc/T1000.py
+++ b/src/dev/sparc/T1000.py
@@ -29,9 +29,9 @@
from m5.params import *
from m5.proxy import *
from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr
-from Uart import Uart8250
from Platform import Platform
-from SimConsole import SimConsole
+from Terminal import Terminal
+from Uart import Uart8250
class MmDisk(BasicPioDevice):
@@ -98,11 +98,11 @@ class T1000(Platform):
fake_ssi = IsaFake(pio_addr=0xff00000000, pio_size=0x10000000)
#warn_access="Accessing SSI -- Unimplemented!")
- hconsole = SimConsole()
+ hterm = Terminal()
hvuart = Uart8250(pio_addr=0xfff0c2c000)
htod = DumbTOD()
- pconsole = SimConsole()
+ pterm = Terminal()
puart0 = Uart8250(pio_addr=0x1f10000000)
iob = Iob()
@@ -116,8 +116,8 @@ class T1000(Platform):
# earlier, since the bus object itself is typically defined at the
# System level.
def attachIO(self, bus):
- self.hvuart.sim_console = self.hconsole
- self.puart0.sim_console = self.pconsole
+ self.hvuart.terminal = self.hterm
+ self.puart0.terminal = self.pterm
self.fake_clk.pio = bus.port
self.fake_membnks.pio = bus.port
self.fake_l2_1.pio = bus.port
diff --git a/src/dev/sparc/iob.cc b/src/dev/sparc/iob.cc
index 6608fc64a..4543dd07b 100644
--- a/src/dev/sparc/iob.cc
+++ b/src/dev/sparc/iob.cc
@@ -120,7 +120,7 @@ void
Iob::readJBus(PacketPtr pkt)
{
Addr accessAddr = pkt->getAddr() - iobJBusAddr;
- int cpuid = pkt->req->getCpuNum();
+ int cpuid = pkt->req->contextId();
int index;
uint64_t data;
@@ -235,7 +235,7 @@ void
Iob::writeJBus(PacketPtr pkt)
{
Addr accessAddr = pkt->getAddr() - iobJBusAddr;
- int cpuid = pkt->req->getCpuNum();
+ int cpuid = pkt->req->contextId();
int index;
uint64_t data;
@@ -276,7 +276,7 @@ void
Iob::generateIpi(Type type, int cpu_id, int vector)
{
SparcISA::SparcFault<SparcISA::PowerOnReset> *por = new SparcISA::PowerOnReset();
- if (cpu_id >= sys->getNumCPUs())
+ if (cpu_id >= sys->numContexts())
return;
switch (type) {
diff --git a/src/dev/sparc/t1000.cc b/src/dev/sparc/t1000.cc
index 49e44af55..88fb358ef 100644
--- a/src/dev/sparc/t1000.cc
+++ b/src/dev/sparc/t1000.cc
@@ -37,8 +37,8 @@
#include <vector>
#include "cpu/intr_control.hh"
-#include "dev/simconsole.hh"
#include "dev/sparc/t1000.hh"
+#include "dev/terminal.hh"
#include "sim/system.hh"
using namespace std;
@@ -94,7 +94,21 @@ T1000::pciToDma(Addr pciAddr) const
Addr
-T1000::calcConfigAddr(int bus, int dev, int func)
+T1000::calcPciConfigAddr(int bus, int dev, int func)
+{
+ panic("Need implementation\n");
+ M5_DUMMY_RETURN
+}
+
+Addr
+T1000::calcPciIOAddr(Addr addr)
+{
+ panic("Need implementation\n");
+ M5_DUMMY_RETURN
+}
+
+Addr
+T1000::calcPciMemAddr(Addr addr)
{
panic("Need implementation\n");
M5_DUMMY_RETURN
diff --git a/src/dev/sparc/t1000.hh b/src/dev/sparc/t1000.hh
index 76de0a550..01ff3d319 100644
--- a/src/dev/sparc/t1000.hh
+++ b/src/dev/sparc/t1000.hh
@@ -91,7 +91,17 @@ class T1000 : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int func);
+ virtual Addr calcPciConfigAddr(int bus, int dev, int func);
+
+ /**
+ * Calculate the address for an IO location on the PCI bus.
+ */
+ virtual Addr calcPciIOAddr(Addr addr);
+
+ /**
+ * Calculate the address for a memory location on the PCI bus.
+ */
+ virtual Addr calcPciMemAddr(Addr addr);
};
#endif // __DEV_T1000_HH__
diff --git a/src/dev/simconsole.cc b/src/dev/terminal.cc
index e8dc1b210..fba0c6130 100644
--- a/src/dev/simconsole.cc
+++ b/src/dev/terminal.cc
@@ -30,27 +30,28 @@
*/
/* @file
- * Implements the user interface to a serial console
+ * Implements the user interface to a serial terminal
*/
#include <sys/ioctl.h>
#include <sys/termios.h>
-#include <sys/types.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
+#include <cctype>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
+#include "base/atomicio.hh"
#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/terminal.hh"
#include "dev/uart.hh"
using namespace std;
@@ -59,50 +60,46 @@ using namespace std;
/*
* Poll event for the listen socket
*/
-SimConsole::ListenEvent::ListenEvent(SimConsole *c, int fd, int e)
- : PollEvent(fd, e), cons(c)
+Terminal::ListenEvent::ListenEvent(Terminal *t, int fd, int e)
+ : PollEvent(fd, e), term(t)
{
}
void
-SimConsole::ListenEvent::process(int revent)
+Terminal::ListenEvent::process(int revent)
{
- cons->accept();
+ term->accept();
}
/*
* Poll event for the data socket
*/
-SimConsole::DataEvent::DataEvent(SimConsole *c, int fd, int e)
- : PollEvent(fd, e), cons(c)
+Terminal::DataEvent::DataEvent(Terminal *t, int fd, int e)
+ : PollEvent(fd, e), term(t)
{
}
void
-SimConsole::DataEvent::process(int revent)
+Terminal::DataEvent::process(int revent)
{
if (revent & POLLIN)
- cons->data();
+ term->data();
else if (revent & POLLNVAL)
- cons->detach();
+ term->detach();
}
/*
- * SimConsole code
+ * Terminal code
*/
-SimConsole::SimConsole(const Params *p)
+Terminal::Terminal(const Params *p)
: SimObject(p), listenEvent(NULL), dataEvent(NULL), number(p->number),
data_fd(-1), txbuf(16384), rxbuf(16384), outfile(NULL)
#if TRACING_ON == 1
, linebuf(16384)
#endif
{
- if (!p->output.empty()) {
- if (p->append_name)
- outfile = simout.find(p->output + "." + p->name);
- else
- outfile = simout.find(p->output);
-
+ if (p->output) {
+ outfile = simout.find(p->name);
outfile->setf(ios::unitbuf);
}
@@ -110,7 +107,7 @@ SimConsole::SimConsole(const Params *p)
listen(p->port);
}
-SimConsole::~SimConsole()
+Terminal::~Terminal()
{
if (data_fd != -1)
::close(data_fd);
@@ -123,15 +120,20 @@ SimConsole::~SimConsole()
}
///////////////////////////////////////////////////////////////////////
-// socket creation and console attach
+// socket creation and terminal attach
//
void
-SimConsole::listen(int port)
+Terminal::listen(int port)
{
+ if (ListenSocket::allDisabled()) {
+ warn_once("Sockets disabled, not accepting terminal connections");
+ return;
+ }
+
while (!listener.listen(port, true)) {
- DPRINTF(Console,
- ": can't bind address console port %d inuse PID %d\n",
+ DPRINTF(Terminal,
+ ": can't bind address terminal port %d inuse PID %d\n",
port, getpid());
port++;
}
@@ -147,15 +149,15 @@ SimConsole::listen(int port)
}
void
-SimConsole::accept()
+Terminal::accept()
{
if (!listener.islistening())
panic("%s: cannot accept a connection if not listening!", name());
int fd = listener.accept(true);
if (data_fd != -1) {
- char message[] = "console already attached!\n";
- ::write(fd, message, sizeof(message));
+ char message[] = "terminal already attached!\n";
+ atomic_write(fd, message, sizeof(message));
::close(fd);
return;
}
@@ -165,7 +167,7 @@ SimConsole::accept()
pollQueue.schedule(dataEvent);
stringstream stream;
- ccprintf(stream, "==== m5 slave console: Console %d ====", number);
+ ccprintf(stream, "==== m5 slave terminal: Terminal %d ====", number);
// we need an actual carriage return followed by a newline for the
// terminal
@@ -173,13 +175,13 @@ SimConsole::accept()
write((const uint8_t *)stream.str().c_str(), stream.str().size());
- DPRINTFN("attach console %d\n", number);
+ DPRINTFN("attach terminal %d\n", number);
txbuf.readall(data_fd);
}
void
-SimConsole::detach()
+Terminal::detach()
{
if (data_fd != -1) {
::close(data_fd);
@@ -190,11 +192,11 @@ SimConsole::detach()
delete dataEvent;
dataEvent = NULL;
- DPRINTFN("detach console %d\n", number);
+ DPRINTFN("detach terminal %d\n", number);
}
void
-SimConsole::data()
+Terminal::data()
{
uint8_t buf[1024];
int len;
@@ -208,10 +210,10 @@ SimConsole::data()
}
size_t
-SimConsole::read(uint8_t *buf, size_t len)
+Terminal::read(uint8_t *buf, size_t len)
{
if (data_fd < 0)
- panic("Console not properly attached.\n");
+ panic("Terminal not properly attached.\n");
size_t ret;
do {
@@ -230,23 +232,16 @@ SimConsole::read(uint8_t *buf, size_t len)
return ret;
}
-// Console output.
+// Terminal output.
size_t
-SimConsole::write(const uint8_t *buf, size_t len)
+Terminal::write(const uint8_t *buf, size_t len)
{
if (data_fd < 0)
- panic("Console not properly attached.\n");
+ panic("Terminal not properly attached.\n");
- size_t ret;
- for (;;) {
- ret = ::write(data_fd, buf, len);
-
- if (ret >= 0)
- break;
-
- if (errno != EINTR)
- detach();
- }
+ ssize_t ret = atomic_write(data_fd, buf, len);
+ if (ret < len)
+ detach();
return ret;
}
@@ -257,7 +252,7 @@ SimConsole::write(const uint8_t *buf, size_t len)
#define RECEIVE_ERROR (ULL(3) << 62)
uint8_t
-SimConsole::in()
+Terminal::in()
{
bool empty;
uint8_t c;
@@ -268,14 +263,14 @@ SimConsole::in()
empty = rxbuf.empty();
- DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n",
+ DPRINTF(TerminalVerbose, "in: \'%c\' %#02x more: %d\n",
isprint(c) ? c : ' ', c, !empty);
return c;
}
uint64_t
-SimConsole::console_in()
+Terminal::console_in()
{
uint64_t value;
@@ -287,26 +282,25 @@ SimConsole::console_in()
value = RECEIVE_NONE;
}
- DPRINTF(ConsoleVerbose, "console_in: return: %#x\n", value);
+ DPRINTF(TerminalVerbose, "console_in: return: %#x\n", value);
return value;
}
void
-SimConsole::out(char c)
+Terminal::out(char c)
{
#if TRACING_ON == 1
- if (DTRACE(Console)) {
+ if (DTRACE(Terminal)) {
static char last = '\0';
- if (c != '\n' && c != '\r' ||
- last != '\n' && last != '\r') {
+ 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);
+ DPRINTF(Terminal, "%s\n", buffer);
delete [] buffer;
} else {
linebuf.write(c);
@@ -325,13 +319,13 @@ SimConsole::out(char c)
if (outfile)
outfile->write(&c, 1);
- DPRINTF(ConsoleVerbose, "out: \'%c\' %#02x\n",
+ DPRINTF(TerminalVerbose, "out: \'%c\' %#02x\n",
isprint(c) ? c : ' ', (int)c);
}
-SimConsole *
-SimConsoleParams::create()
+Terminal *
+TerminalParams::create()
{
- return new SimConsole(this);
+ return new Terminal(this);
}
diff --git a/src/dev/simconsole.hh b/src/dev/terminal.hh
index c8d453960..d2499b6b2 100644
--- a/src/dev/simconsole.hh
+++ b/src/dev/terminal.hh
@@ -30,11 +30,11 @@
*/
/* @file
- * User Console Interface
+ * User Terminal Interface
*/
-#ifndef __CONSOLE_HH__
-#define __CONSOLE_HH__
+#ifndef __DEV_TERMINAL_HH__
+#define __DEV_TERMINAL_HH__
#include <iostream>
@@ -43,12 +43,12 @@
#include "base/pollevent.hh"
#include "base/socket.hh"
#include "sim/sim_object.hh"
-#include "params/SimConsole.hh"
+#include "params/Terminal.hh"
-class ConsoleListener;
+class TerminalListener;
class Uart;
-class SimConsole : public SimObject
+class Terminal : public SimObject
{
public:
Uart *uart;
@@ -57,10 +57,10 @@ class SimConsole : public SimObject
class ListenEvent : public PollEvent
{
protected:
- SimConsole *cons;
+ Terminal *term;
public:
- ListenEvent(SimConsole *c, int fd, int e);
+ ListenEvent(Terminal *t, int fd, int e);
void process(int revent);
};
@@ -70,10 +70,10 @@ class SimConsole : public SimObject
class DataEvent : public PollEvent
{
protected:
- SimConsole *cons;
+ Terminal *term;
public:
- DataEvent(SimConsole *c, int fd, int e);
+ DataEvent(Terminal *t, int fd, int e);
void process(int revent);
};
@@ -85,9 +85,9 @@ class SimConsole : public SimObject
int data_fd;
public:
- typedef SimConsoleParams Params;
- SimConsole(const Params *p);
- ~SimConsole();
+ typedef TerminalParams Params;
+ Terminal(const Params *p);
+ ~Terminal();
protected:
ListenSocket listener;
@@ -119,10 +119,10 @@ class SimConsole : public SimObject
/////////////////
// OS interface
- // Get a character from the console.
+ // Get a character from the terminal.
uint8_t in();
- // get a character from the console in the console specific format
+ // get a character from the terminal in the console specific format
// corresponds to GETC:
// retval<63:61>
// 000: success: character received
@@ -136,11 +136,11 @@ class SimConsole : public SimObject
// Interrupts are cleared when the buffer is empty.
uint64_t console_in();
- // Send a character to the console
+ // Send a character to the terminal
void out(char c);
- //Ask the console if data is available
+ // Ask the terminal if data is available
bool dataAvailable() { return !rxbuf.empty(); }
};
-#endif // __CONSOLE_HH__
+#endif // __DEV_TERMINAL_HH__
diff --git a/src/dev/uart.cc b/src/dev/uart.cc
index c9a2ae964..ab0ebde2c 100644
--- a/src/dev/uart.cc
+++ b/src/dev/uart.cc
@@ -32,17 +32,17 @@
* Implements a base class for UARTs
*/
-#include "dev/simconsole.hh"
-#include "dev/uart.hh"
#include "dev/platform.hh"
+#include "dev/terminal.hh"
+#include "dev/uart.hh"
using namespace std;
Uart::Uart(const Params *p)
- : BasicPioDevice(p), platform(p->platform), cons(p->sim_console)
+ : BasicPioDevice(p), platform(p->platform), term(p->terminal)
{
status = 0;
// set back pointers
- cons->uart = this;
+ term->uart = this;
}
diff --git a/src/dev/uart.hh b/src/dev/uart.hh
index f5d5e2855..ba10c204c 100644
--- a/src/dev/uart.hh
+++ b/src/dev/uart.hh
@@ -39,7 +39,7 @@
#include "dev/io_device.hh"
#include "params/Uart.hh"
-class SimConsole;
+class Terminal;
class Platform;
const int RX_INT = 0x1;
@@ -51,7 +51,7 @@ class Uart : public BasicPioDevice
protected:
int status;
Platform *platform;
- SimConsole *cons;
+ Terminal *term;
public:
typedef UartParams Params;
diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc
index b4dc93645..93f71f49b 100644
--- a/src/dev/uart8250.cc
+++ b/src/dev/uart8250.cc
@@ -38,9 +38,9 @@
#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 "dev/terminal.hh"
+#include "dev/uart8250.hh"
#include "mem/packet.hh"
#include "mem/packet_access.hh"
@@ -48,7 +48,7 @@ using namespace std;
using namespace TheISA;
Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit)
- : Event(&mainEventQueue), uart(u)
+ : uart(u)
{
DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
intrBit = bit;
@@ -93,9 +93,9 @@ Uart8250::IntrEvent::scheduleIntr()
DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
curTick + interval);
if (!scheduled())
- schedule(curTick + interval);
+ uart->schedule(this, curTick + interval);
else
- reschedule(curTick + interval);
+ uart->reschedule(this, curTick + interval);
}
@@ -120,8 +120,8 @@ Uart8250::read(PacketPtr pkt)
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // read byte
- if (cons->dataAvailable())
- pkt->set(cons->in());
+ if (term->dataAvailable())
+ pkt->set(term->in());
else {
pkt->set((uint8_t)0);
// A limited amount of these are ok.
@@ -130,7 +130,7 @@ Uart8250::read(PacketPtr pkt)
status &= ~RX_INT;
platform->clearConsoleInt();
- if (cons->dataAvailable() && (IER & UART_IER_RDI))
+ if (term->dataAvailable() && (IER & UART_IER_RDI))
rxIntrEvent.scheduleIntr();
} else { // dll divisor latch
;
@@ -165,7 +165,7 @@ Uart8250::read(PacketPtr pkt)
uint8_t lsr;
lsr = 0;
// check if there are any bytes to be read
- if (cons->dataAvailable())
+ if (term->dataAvailable())
lsr = UART_LSR_DR;
lsr |= UART_LSR_TEMT | UART_LSR_THRE;
pkt->set(lsr);
@@ -201,7 +201,7 @@ Uart8250::write(PacketPtr pkt)
switch (daddr) {
case 0x0:
if (!(LCR & 0x80)) { // write byte
- cons->out(pkt->get<uint8_t>());
+ term->out(pkt->get<uint8_t>());
platform->clearConsoleInt();
status &= ~TX_INT;
if (UART_IER_THRI & IER)
@@ -231,19 +231,19 @@ Uart8250::write(PacketPtr pkt)
{
DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
if (txIntrEvent.scheduled())
- txIntrEvent.deschedule();
+ deschedule(txIntrEvent);
if (status & TX_INT)
platform->clearConsoleInt();
status &= ~TX_INT;
}
- if ((UART_IER_RDI & IER) && cons->dataAvailable()) {
+ if ((UART_IER_RDI & IER) && term->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();
+ deschedule(rxIntrEvent);
if (status & RX_INT)
platform->clearConsoleInt();
status &= ~RX_INT;
@@ -329,9 +329,9 @@ Uart8250::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(rxintrwhen);
UNSERIALIZE_SCALAR(txintrwhen);
if (rxintrwhen != 0)
- rxIntrEvent.schedule(rxintrwhen);
+ schedule(rxIntrEvent, rxintrwhen);
if (txintrwhen != 0)
- txIntrEvent.schedule(txintrwhen);
+ schedule(txIntrEvent, txintrwhen);
}
Uart8250 *
diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh
index 2c69667e1..79c31d5cf 100644
--- a/src/dev/uart8250.hh
+++ b/src/dev/uart8250.hh
@@ -65,7 +65,7 @@ const uint8_t UART_LSR_DR = 0x01;
const uint8_t UART_MCR_LOOP = 0x10;
-class SimConsole;
+class Terminal;
class Platform;
class Uart8250 : public Uart
diff --git a/src/dev/x86/Cmos.py b/src/dev/x86/Cmos.py
new file mode 100644
index 000000000..0a92145e2
--- /dev/null
+++ b/src/dev/x86/Cmos.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class Cmos(BasicPioDevice):
+ type = 'Cmos'
+ cxx_class='X86ISA::Cmos'
+ time = Param.Time('01/01/2009',
+ "System time to use ('Now' for actual time)")
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal RTC alarm interrupts to')
diff --git a/src/dev/x86/I8042.py b/src/dev/x86/I8042.py
new file mode 100644
index 000000000..31192adcd
--- /dev/null
+++ b/src/dev/x86/I8042.py
@@ -0,0 +1,45 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class I8042(BasicPioDevice):
+ type = 'I8042'
+ cxx_class = 'X86ISA::I8042'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ # This isn't actually used for anything here.
+ pio_addr = 0x0
+ data_port = Param.Addr('Data port address')
+ command_port = Param.Addr('Command/status port address')
+ mouse_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal the mouse has data')
+ keyboard_int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal the keyboard has data')
diff --git a/src/dev/x86/I82094AA.py b/src/dev/x86/I82094AA.py
new file mode 100644
index 000000000..9d57beed1
--- /dev/null
+++ b/src/dev/x86/I82094AA.py
@@ -0,0 +1,43 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSinkPin
+
+class I82094AA(BasicPioDevice):
+ type = 'I82094AA'
+ cxx_class = 'X86ISA::I82094AA'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ pio_addr = Param.Addr("Device address")
+ int_port = Port("Port for sending and receiving interrupt messages")
+ external_int_pic = Param.I8259(NULL, "External PIC, if any")
+
+ def pin(self, line):
+ return X86IntSinkPin(device=self, number=line)
diff --git a/src/dev/x86/I8237.py b/src/dev/x86/I8237.py
new file mode 100644
index 000000000..20788a164
--- /dev/null
+++ b/src/dev/x86/I8237.py
@@ -0,0 +1,36 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+
+class I8237(BasicPioDevice):
+ type = 'I8237'
+ cxx_class = 'X86ISA::I8237'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
diff --git a/src/dev/x86/I8254.py b/src/dev/x86/I8254.py
new file mode 100644
index 000000000..f468717cc
--- /dev/null
+++ b/src/dev/x86/I8254.py
@@ -0,0 +1,39 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin
+
+class I8254(BasicPioDevice):
+ type = 'I8254'
+ cxx_class = 'X86ISA::I8254'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ int_pin = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'Pin to signal timer interrupts to')
diff --git a/src/dev/x86/I8259.py b/src/dev/x86/I8259.py
new file mode 100644
index 000000000..0a516d30a
--- /dev/null
+++ b/src/dev/x86/I8259.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+from X86IntPin import X86IntSourcePin, X86IntSinkPin
+
+class X86I8259CascadeMode(Enum):
+ map = {'I8259Master' : 0,
+ 'I8259Slave' : 1,
+ 'I8259Single' : 2
+ }
+
+class I8259(BasicPioDevice):
+ type = 'I8259'
+ cxx_class='X86ISA::I8259'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ output = Param.X86IntSourcePin(X86IntSourcePin(),
+ 'The pin this I8259 drives')
+ mode = Param.X86I8259CascadeMode('How this I8259 is cascaded')
+ slave = Param.I8259(NULL, 'Slave I8259, if any')
+
+ def pin(self, line):
+ return X86IntSinkPin(device=self, number=line)
diff --git a/src/dev/x86/Opteron.py b/src/dev/x86/Opteron.py
deleted file mode 100644
index cb015e2e7..000000000
--- a/src/dev/x86/Opteron.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from m5.params import *
-from m5.proxy import *
-from Device import BasicPioDevice, PioDevice, IsaFake, BadAddr
-from Uart import Uart8250
-from Platform import Platform
-from Pci import PciConfigAll
-from SimConsole import SimConsole
-
-class Opteron(Platform):
- type = 'Opteron'
- system = Param.System(Parent.any, "system")
-
- pciconfig = PciConfigAll()
-
- def attachIO(self, bus):
- self.pciconfig.pio = bus.default
- bus.responder_set = True
- bus.responder = self.pciconfig
diff --git a/src/dev/x86/Pc.py b/src/dev/x86/Pc.py
new file mode 100644
index 000000000..6f315cbcb
--- /dev/null
+++ b/src/dev/x86/Pc.py
@@ -0,0 +1,83 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+
+from Device import IsaFake
+from Pci import PciConfigAll
+from Platform import Platform
+from SouthBridge import SouthBridge
+from Terminal import Terminal
+from Uart import Uart8250
+
+def x86IOAddress(port):
+ IO_address_space_base = 0x8000000000000000
+ return IO_address_space_base + port;
+
+class Pc(Platform):
+ type = 'Pc'
+ system = Param.System(Parent.any, "system")
+
+ pciconfig = PciConfigAll()
+
+ south_bridge = SouthBridge()
+
+ # "Non-existant" port used for timing purposes by the linux kernel
+ i_dont_exist = IsaFake(pio_addr=x86IOAddress(0x80), pio_size=1)
+
+ # Ports behind the pci config and data regsiters. These don't do anything,
+ # but the linux kernel fiddles with them anway.
+ behind_pci = IsaFake(pio_addr=x86IOAddress(0xcf8), pio_size=8)
+
+ # Serial port and terminal
+ terminal = Terminal()
+ com_1 = Uart8250()
+ com_1.pio_addr = x86IOAddress(0x3f8)
+ com_1.terminal = terminal
+
+ # Devices to catch access to non-existant serial ports.
+ fake_com_2 = IsaFake(pio_addr=x86IOAddress(0x2f8), pio_size=8)
+ fake_com_3 = IsaFake(pio_addr=x86IOAddress(0x3e8), pio_size=8)
+ fake_com_4 = IsaFake(pio_addr=x86IOAddress(0x2e8), pio_size=8)
+
+ # A device to catch accesses to the non-existant floppy controller.
+ fake_floppy = IsaFake(pio_addr=x86IOAddress(0x3f2), pio_size=2)
+
+ def attachIO(self, bus):
+ self.south_bridge.attachIO(bus)
+ self.i_dont_exist.pio = bus.port
+ self.behind_pci.pio = bus.port
+ self.com_1.pio = bus.port
+ self.fake_com_2.pio = bus.port
+ self.fake_com_3.pio = bus.port
+ self.fake_com_4.pio = bus.port
+ self.fake_floppy.pio = bus.port
+ self.pciconfig.pio = bus.default
+ bus.responder_set = True
+ bus.responder = self.pciconfig
diff --git a/src/dev/x86/PcSpeaker.py b/src/dev/x86/PcSpeaker.py
new file mode 100644
index 000000000..7ca62ec1e
--- /dev/null
+++ b/src/dev/x86/PcSpeaker.py
@@ -0,0 +1,37 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Device import BasicPioDevice
+
+class PcSpeaker(BasicPioDevice):
+ type = 'PcSpeaker'
+ cxx_class = 'X86ISA::Speaker'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ i8254 = Param.I8254('Timer that drives the speaker')
diff --git a/src/dev/x86/SConscript b/src/dev/x86/SConscript
index c500531b1..e7543dfdf 100644
--- a/src/dev/x86/SConscript
+++ b/src/dev/x86/SConscript
@@ -26,12 +26,44 @@
# (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
-# Gabe Black
+# Authors: Gabe Black
Import('*')
if env['FULL_SYSTEM'] and env['TARGET_ISA'] == 'x86':
- SimObject('Opteron.py')
+ SimObject('Pc.py')
+ Source('pc.cc')
- Source('opteron.cc')
+ SimObject('SouthBridge.py')
+ Source('south_bridge.cc')
+
+ SimObject('Cmos.py')
+ Source('cmos.cc')
+ TraceFlag('CMOS', 'Accesses to CMOS devices')
+
+ SimObject('I8259.py')
+ Source('i8259.cc')
+ TraceFlag('I8259', 'Accesses to the I8259 PIC devices')
+
+ SimObject('I8254.py')
+ Source('i8254.cc')
+ TraceFlag('I8254', 'Interrupts from the I8254 timer');
+
+ SimObject('I8237.py')
+ Source('i8237.cc')
+ TraceFlag('I8237', 'The I8237 dma controller');
+
+ SimObject('I8042.py')
+ Source('i8042.cc')
+ TraceFlag('I8042', 'The I8042 keyboard controller');
+
+ SimObject('PcSpeaker.py')
+ Source('speaker.cc')
+ TraceFlag('PcSpeaker')
+
+ SimObject('I82094AA.py')
+ Source('i82094aa.cc')
+ TraceFlag('I82094AA')
+
+ SimObject('X86IntPin.py')
+ Source('intdev.cc')
diff --git a/src/dev/x86/SouthBridge.py b/src/dev/x86/SouthBridge.py
new file mode 100644
index 000000000..d89ed9dc6
--- /dev/null
+++ b/src/dev/x86/SouthBridge.py
@@ -0,0 +1,122 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.proxy import *
+from Cmos import Cmos
+from I8042 import I8042
+from I82094AA import I82094AA
+from I8237 import I8237
+from I8254 import I8254
+from I8259 import I8259
+from Ide import IdeController
+from PcSpeaker import PcSpeaker
+from X86IntPin import X86IntLine
+from m5.SimObject import SimObject
+
+def x86IOAddress(port):
+ IO_address_space_base = 0x8000000000000000
+ return IO_address_space_base + port;
+
+class SouthBridge(SimObject):
+ type = 'SouthBridge'
+ pio_latency = Param.Latency('1ns', "Programmed IO latency in simticks")
+ platform = Param.Platform(Parent.any, "Platform this device is part of")
+
+ _pic1 = I8259(pio_addr=x86IOAddress(0x20), mode='I8259Master')
+ _pic2 = I8259(pio_addr=x86IOAddress(0xA0), mode='I8259Slave')
+ _cmos = Cmos(pio_addr=x86IOAddress(0x70))
+ _dma1 = I8237(pio_addr=x86IOAddress(0x0))
+ _keyboard = I8042(data_port=x86IOAddress(0x60), \
+ command_port=x86IOAddress(0x64))
+ _pit = I8254(pio_addr=x86IOAddress(0x40))
+ _speaker = PcSpeaker(pio_addr=x86IOAddress(0x61))
+ _io_apic = I82094AA(pio_addr=0xFEC00000)
+ # This is to make sure the interrupt lines are instantiated. Don't use
+ # it for anything directly.
+ int_lines = VectorParam.X86IntLine([], "Interrupt lines")
+
+ pic1 = Param.I8259(_pic1, "Master PIC")
+ pic2 = Param.I8259(_pic2, "Slave PIC")
+ cmos = Param.Cmos(_cmos, "CMOS memory and real time clock device")
+ dma1 = Param.I8237(_dma1, "The first dma controller")
+ keyboard = Param.I8042(_keyboard, "The keyboard controller")
+ pit = Param.I8254(_pit, "Programmable interval timer")
+ speaker = Param.PcSpeaker(_speaker, "PC speaker")
+ io_apic = Param.I82094AA(_io_apic, "I/O APIC")
+
+ def connectPins(self, source, sink):
+ self.int_lines.append(X86IntLine(source=source, sink=sink))
+
+ # IDE controller
+ ide = IdeController(disks=[], pci_func=0, pci_dev=4, pci_bus=0)
+ ide.BAR0 = 0x1f0
+ ide.BAR0LegacyIO = True
+ ide.BAR1 = 0x3f4
+ ide.BAR1Size = '3B'
+ ide.BAR1LegacyIO = True
+ ide.BAR2 = 0x170
+ ide.BAR2LegacyIO = True
+ ide.BAR3 = 0x374
+ ide.BAR3Size = '3B'
+ ide.BAR3LegacyIO = True
+ ide.BAR4 = 1
+ ide.Command = 1
+ ide.InterruptLine = 14
+ ide.InterruptPin = 1
+
+ def attachIO(self, bus):
+ # Route interupt signals
+ self.connectPins(self.pic1.output, self.io_apic.pin(0))
+ self.connectPins(self.pic2.output, self.pic1.pin(2))
+ self.connectPins(self.cmos.int_pin, self.pic2.pin(0))
+ self.connectPins(self.pit.int_pin, self.pic1.pin(0))
+ self.connectPins(self.pit.int_pin, self.io_apic.pin(2))
+# self.connectPins(self.keyboard.keyboard_int_pin,
+# self.pic1.pin(1))
+ self.connectPins(self.keyboard.keyboard_int_pin,
+ self.io_apic.pin(1))
+# self.connectPins(self.keyboard.mouse_int_pin,
+# self.pic2.pin(4))
+ self.connectPins(self.keyboard.mouse_int_pin,
+ self.io_apic.pin(12))
+ # Tell the devices about each other
+ self.pic1.slave = self.pic2
+ self.speaker.i8254 = self.pit
+ self.io_apic.external_int_pic = self.pic1
+ # Connect to the bus
+ self.cmos.pio = bus.port
+ self.dma1.pio = bus.port
+ self.ide.pio = bus.port
+ self.keyboard.pio = bus.port
+ self.pic1.pio = bus.port
+ self.pic2.pio = bus.port
+ self.pit.pio = bus.port
+ self.speaker.pio = bus.port
+ self.io_apic.pio = bus.port
+ self.io_apic.int_port = bus.port
diff --git a/src/dev/x86/X86IntPin.py b/src/dev/x86/X86IntPin.py
new file mode 100644
index 000000000..35e274624
--- /dev/null
+++ b/src/dev/x86/X86IntPin.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2008 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.params import *
+from m5.SimObject import SimObject
+
+# A generic pin to drive an interrupt signal generated by a device.
+class X86IntSourcePin(SimObject):
+ type = 'X86IntSourcePin'
+ cxx_class = 'X86ISA::IntSourcePin'
+
+# A generic pin to receive an interrupt signal generated by another device.
+class X86IntSinkPin(SimObject):
+ type = 'X86IntSinkPin'
+ cxx_class = 'X86ISA::IntSinkPin'
+
+ device = Param.SimObject("Device this pin belongs to")
+ number = Param.Int("The pin number on the device")
+
+# An interrupt line which is driven by a source pin and drives a sink pin.
+class X86IntLine(SimObject):
+ type = 'X86IntLine'
+ cxx_class = 'X86ISA::IntLine'
+
+ source = Param.X86IntSourcePin("Pin driving this line")
+ sink = Param.X86IntSinkPin("Pin driven by this line")
diff --git a/src/dev/x86/cmos.cc b/src/dev/x86/cmos.cc
new file mode 100644
index 000000000..e08c56e8c
--- /dev/null
+++ b/src/dev/x86/cmos.cc
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "dev/x86/cmos.hh"
+#include "dev/x86/intdev.hh"
+#include "mem/packet_access.hh"
+
+void
+X86ISA::Cmos::X86RTC::handleEvent()
+{
+ assert(intPin);
+ intPin->raise();
+ //XXX This is a hack.
+ intPin->lower();
+}
+
+Tick
+X86ISA::Cmos::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ pkt->set(address);
+ break;
+ case 0x1:
+ pkt->set(readRegister(address));
+ break;
+ default:
+ panic("Read from undefined CMOS port.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::Cmos::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ address = pkt->get<uint8_t>();
+ break;
+ case 0x1:
+ writeRegister(address, pkt->get<uint8_t>());
+ break;
+ default:
+ panic("Write to undefined CMOS port.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+uint8_t
+X86ISA::Cmos::readRegister(uint8_t reg)
+{
+ assert(reg < numRegs);
+ uint8_t val;
+ if (reg <= 0xD) {
+ val = rtc.readData(reg);
+ DPRINTF(CMOS,
+ "Reading CMOS RTC reg %x as %x.\n", reg, val);
+ } else {
+ val = regs[reg];
+ DPRINTF(CMOS,
+ "Reading non-volitile CMOS address %x as %x.\n", reg, val);
+ }
+ return val;
+}
+
+void
+X86ISA::Cmos::writeRegister(uint8_t reg, uint8_t val)
+{
+ assert(reg < numRegs);
+ if (reg <= 0xD) {
+ DPRINTF(CMOS, "Writing CMOS RTC reg %x with %x.\n",
+ reg, val);
+ rtc.writeData(reg, val);
+ } else {
+ DPRINTF(CMOS, "Writing non-volitile CMOS address %x with %x.\n",
+ reg, val);
+ regs[reg] = val;
+ }
+}
+
+X86ISA::Cmos *
+CmosParams::create()
+{
+ return new X86ISA::Cmos(this);
+}
diff --git a/src/dev/x86/cmos.hh b/src/dev/x86/cmos.hh
new file mode 100644
index 000000000..76276dbc1
--- /dev/null
+++ b/src/dev/x86/cmos.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_CMOS_HH__
+#define __DEV_X86_CMOS_HH__
+
+#include "dev/io_device.hh"
+#include "dev/mc146818.hh"
+#include "params/Cmos.hh"
+
+namespace X86ISA
+{
+
+class IntSourcePin;
+
+class Cmos : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+
+ uint8_t address;
+
+ static const int numRegs = 128;
+
+ uint8_t regs[numRegs];
+
+ uint8_t readRegister(uint8_t reg);
+ void writeRegister(uint8_t reg, uint8_t val);
+
+ class X86RTC : public MC146818
+ {
+ protected:
+ IntSourcePin * intPin;
+ public:
+ X86RTC(EventManager *em, const std::string &n, const struct tm time,
+ bool bcd, Tick frequency, IntSourcePin * _intPin) :
+ MC146818(em, n, time, bcd, frequency), intPin(_intPin)
+ {
+ }
+ protected:
+ void handleEvent();
+ } rtc;
+
+ public:
+ typedef CmosParams Params;
+
+ Cmos(const Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ rtc(this, "rtc", p->time, true, ULL(5000000000), p->int_pin)
+ {
+ pioSize = 2;
+ memset(regs, 0, numRegs * sizeof(uint8_t));
+ address = 0;
+ }
+
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_CMOS_HH__
diff --git a/src/dev/x86/i8042.cc b/src/dev/x86/i8042.cc
new file mode 100644
index 000000000..afcbfdfb4
--- /dev/null
+++ b/src/dev/x86/i8042.cc
@@ -0,0 +1,446 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "base/bitunion.hh"
+#include "dev/x86/i8042.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+// The 8042 has a whopping 32 bytes of internal RAM.
+const uint8_t RamSize = 32;
+const uint8_t NumOutputBits = 14;
+const uint8_t X86ISA::PS2Keyboard::ID[] = {0xab, 0x83};
+const uint8_t X86ISA::PS2Mouse::ID[] = {0x00};
+const uint8_t CommandAck = 0xfa;
+const uint8_t CommandNack = 0xfe;
+const uint8_t BatSuccessful = 0xaa;
+
+void
+X86ISA::I8042::addressRanges(AddrRangeList &range_list)
+{
+ range_list.clear();
+ range_list.push_back(RangeSize(dataPort, 1));
+ range_list.push_back(RangeSize(commandPort, 1));
+}
+
+void
+X86ISA::I8042::writeData(uint8_t newData, bool mouse)
+{
+ DPRINTF(I8042, "Set data %#02x.\n", newData);
+ dataReg = newData;
+ statusReg.outputFull = 1;
+ statusReg.mouseOutputFull = (mouse ? 1 : 0);
+ if (!mouse && commandByte.keyboardFullInt) {
+ DPRINTF(I8042, "Sending keyboard interrupt.\n");
+ keyboardIntPin->raise();
+ //This is a hack
+ keyboardIntPin->lower();
+ } else if (mouse && commandByte.mouseFullInt) {
+ DPRINTF(I8042, "Sending mouse interrupt.\n");
+ mouseIntPin->raise();
+ //This is a hack
+ mouseIntPin->lower();
+ }
+}
+
+void
+X86ISA::PS2Device::ack()
+{
+ bufferData(&CommandAck, sizeof(CommandAck));
+}
+
+void
+X86ISA::PS2Device::nack()
+{
+ bufferData(&CommandNack, sizeof(CommandNack));
+}
+
+void
+X86ISA::PS2Device::bufferData(const uint8_t *data, int size)
+{
+ assert(data || size == 0);
+ while (size) {
+ outBuffer.push(*(data++));
+ size--;
+ }
+}
+
+uint8_t
+X86ISA::I8042::readDataOut()
+{
+ uint8_t data = dataReg;
+ statusReg.outputFull = 0;
+ statusReg.mouseOutputFull = 0;
+ if (keyboard.hasData()) {
+ writeData(keyboard.getData(), false);
+ } else if (mouse.hasData()) {
+ writeData(mouse.getData(), true);
+ }
+ return data;
+}
+
+bool
+X86ISA::PS2Keyboard::processData(uint8_t data)
+{
+ if (lastCommand != NoCommand) {
+ switch (lastCommand) {
+ case LEDWrite:
+ DPRINTF(I8042, "Setting LEDs: "
+ "caps lock %s, num lock %s, scroll lock %s\n",
+ bits(data, 2) ? "on" : "off",
+ bits(data, 1) ? "on" : "off",
+ bits(data, 0) ? "on" : "off");
+ ack();
+ lastCommand = NoCommand;
+ break;
+ case TypematicInfo:
+ DPRINTF(I8042, "Setting typematic info to %#02x.\n", data);
+ ack();
+ lastCommand = NoCommand;
+ break;
+ }
+ return hasData();
+ }
+ switch (data) {
+ case LEDWrite:
+ DPRINTF(I8042, "Got LED write command.\n");
+ ack();
+ lastCommand = LEDWrite;
+ break;
+ case DiagnosticEcho:
+ panic("Keyboard diagnostic echo unimplemented.\n");
+ case AlternateScanCodes:
+ panic("Accessing alternate scan codes unimplemented.\n");
+ case ReadID:
+ DPRINTF(I8042, "Got keyboard read ID command.\n");
+ ack();
+ bufferData((uint8_t *)&ID, sizeof(ID));
+ break;
+ case TypematicInfo:
+ DPRINTF(I8042, "Setting typematic info.\n");
+ ack();
+ lastCommand = TypematicInfo;
+ break;
+ case Enable:
+ DPRINTF(I8042, "Enabling the keyboard.\n");
+ ack();
+ break;
+ case Disable:
+ DPRINTF(I8042, "Disabling the keyboard.\n");
+ ack();
+ break;
+ case DefaultsAndDisable:
+ DPRINTF(I8042, "Disabling and resetting the keyboard.\n");
+ ack();
+ break;
+ case AllKeysToTypematic:
+ panic("Setting all keys to typemantic unimplemented.\n");
+ case AllKeysToMakeRelease:
+ panic("Setting all keys to make/release unimplemented.\n");
+ case AllKeysToMake:
+ panic("Setting all keys to make unimplemented.\n");
+ case AllKeysToTypematicMakeRelease:
+ panic("Setting all keys to "
+ "typematic/make/release unimplemented.\n");
+ case KeyToTypematic:
+ panic("Setting a key to typematic unimplemented.\n");
+ case KeyToMakeRelease:
+ panic("Setting a key to make/release unimplemented.\n");
+ case KeyToMakeOnly:
+ panic("Setting key to make only unimplemented.\n");
+ case Resend:
+ panic("Keyboard resend unimplemented.\n");
+ case Reset:
+ panic("Keyboard reset unimplemented.\n");
+ default:
+ panic("Unknown keyboard command %#02x.\n", data);
+ }
+ return hasData();
+}
+
+bool
+X86ISA::PS2Mouse::processData(uint8_t data)
+{
+ if (lastCommand != NoCommand) {
+ switch(lastCommand) {
+ case SetResolution:
+ DPRINTF(I8042, "Mouse resolution set to %d.\n", data);
+ resolution = data;
+ ack();
+ lastCommand = NoCommand;
+ break;
+ case SampleRate:
+ DPRINTF(I8042, "Mouse sample rate %d samples "
+ "per second.\n", data);
+ sampleRate = data;
+ ack();
+ lastCommand = NoCommand;
+ break;
+ default:
+ panic("Not expecting data for a mouse command.\n");
+ }
+ return hasData();
+ }
+ switch (data) {
+ case Scale1to1:
+ DPRINTF(I8042, "Setting mouse scale to 1:1.\n");
+ status.twoToOne = 0;
+ ack();
+ break;
+ case Scale2to1:
+ DPRINTF(I8042, "Setting mouse scale to 2:1.\n");
+ status.twoToOne = 1;
+ ack();
+ break;
+ case SetResolution:
+ DPRINTF(I8042, "Setting mouse resolution.\n");
+ lastCommand = SetResolution;
+ ack();
+ break;
+ case GetStatus:
+ DPRINTF(I8042, "Getting mouse status.\n");
+ ack();
+ bufferData((uint8_t *)&(status), 1);
+ bufferData(&resolution, sizeof(resolution));
+ bufferData(&sampleRate, sizeof(sampleRate));
+ break;
+ case ReadData:
+ panic("Reading mouse data unimplemented.\n");
+ case ResetWrapMode:
+ panic("Resetting mouse wrap mode unimplemented.\n");
+ case WrapMode:
+ panic("Setting mouse wrap mode unimplemented.\n");
+ case RemoteMode:
+ panic("Setting mouse remote mode unimplemented.\n");
+ case ReadID:
+ DPRINTF(I8042, "Mouse ID requested.\n");
+ ack();
+ bufferData(ID, sizeof(ID));
+ break;
+ case SampleRate:
+ DPRINTF(I8042, "Setting mouse sample rate.\n");
+ lastCommand = SampleRate;
+ ack();
+ break;
+ case DisableReporting:
+ DPRINTF(I8042, "Disabling data reporting.\n");
+ status.enabled = 0;
+ ack();
+ break;
+ case EnableReporting:
+ DPRINTF(I8042, "Enabling data reporting.\n");
+ status.enabled = 1;
+ ack();
+ break;
+ case DefaultsAndDisable:
+ DPRINTF(I8042, "Disabling and resetting mouse.\n");
+ sampleRate = 100;
+ resolution = 4;
+ status.twoToOne = 0;
+ status.enabled = 0;
+ ack();
+ break;
+ case Resend:
+ panic("Mouse resend unimplemented.\n");
+ case Reset:
+ DPRINTF(I8042, "Resetting the mouse.\n");
+ sampleRate = 100;
+ resolution = 4;
+ status.twoToOne = 0;
+ status.enabled = 0;
+ ack();
+ bufferData(&BatSuccessful, sizeof(BatSuccessful));
+ bufferData(ID, sizeof(ID));
+ break;
+ default:
+ warn("Unknown mouse command %#02x.\n", data);
+ nack();
+ break;
+ }
+ return hasData();
+}
+
+
+Tick
+X86ISA::I8042::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr addr = pkt->getAddr();
+ if (addr == dataPort) {
+ uint8_t data = readDataOut();
+ //DPRINTF(I8042, "Read from data port got %#02x.\n", data);
+ pkt->set<uint8_t>(data);
+ } else if (addr == commandPort) {
+ //DPRINTF(I8042, "Read status as %#02x.\n", (uint8_t)statusReg);
+ pkt->set<uint8_t>((uint8_t)statusReg);
+ } else {
+ panic("Read from unrecognized port %#x.\n", addr);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8042::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr addr = pkt->getAddr();
+ uint8_t data = pkt->get<uint8_t>();
+ if (addr == dataPort) {
+ statusReg.commandLast = 0;
+ switch (lastCommand) {
+ case NoCommand:
+ if (keyboard.processData(data)) {
+ writeData(keyboard.getData(), false);
+ }
+ break;
+ case WriteToMouse:
+ if (mouse.processData(data)) {
+ writeData(mouse.getData(), true);
+ }
+ break;
+ case WriteCommandByte:
+ commandByte = data;
+ DPRINTF(I8042, "Got data %#02x for \"Write "
+ "command byte\" command.\n", data);
+ statusReg.passedSelfTest = (uint8_t)commandByte.passedSelfTest;
+ break;
+ case WriteMouseOutputBuff:
+ DPRINTF(I8042, "Got data %#02x for \"Write "
+ "mouse output buffer\" command.\n", data);
+ writeData(data, true);
+ break;
+ default:
+ panic("Data written for unrecognized "
+ "command %#02x\n", lastCommand);
+ }
+ lastCommand = NoCommand;
+ } else if (addr == commandPort) {
+ DPRINTF(I8042, "Got command %#02x.\n", data);
+ statusReg.commandLast = 1;
+ // These purposefully leave off the first byte of the controller RAM
+ // so it can be handled specially.
+ if (data > ReadControllerRamBase &&
+ data < ReadControllerRamBase + RamSize) {
+ panic("Attempted to use i8042 read controller RAM command to "
+ "get byte %d.\n", data - ReadControllerRamBase);
+ } else if (data > WriteControllerRamBase &&
+ data < WriteControllerRamBase + RamSize) {
+ panic("Attempted to use i8042 read controller RAM command to "
+ "get byte %d.\n", data - ReadControllerRamBase);
+ } else if (data >= PulseOutputBitBase &&
+ data < PulseOutputBitBase + NumOutputBits) {
+ panic("Attempted to use i8042 pulse output bit command to "
+ "to pulse bit %d.\n", data - PulseOutputBitBase);
+ }
+ switch (data) {
+ case GetCommandByte:
+ DPRINTF(I8042, "Getting command byte.\n");
+ writeData(commandByte);
+ break;
+ case WriteCommandByte:
+ DPRINTF(I8042, "Setting command byte.\n");
+ lastCommand = WriteCommandByte;
+ break;
+ case CheckForPassword:
+ panic("i8042 \"Check for password\" command not implemented.\n");
+ case LoadPassword:
+ panic("i8042 \"Load password\" command not implemented.\n");
+ case CheckPassword:
+ panic("i8042 \"Check password\" command not implemented.\n");
+ case DisableMouse:
+ DPRINTF(I8042, "Disabling mouse at controller.\n");
+ commandByte.disableMouse = 1;
+ break;
+ case EnableMouse:
+ DPRINTF(I8042, "Enabling mouse at controller.\n");
+ commandByte.disableMouse = 0;
+ break;
+ case TestMouse:
+ panic("i8042 \"Test mouse\" command not implemented.\n");
+ case SelfTest:
+ panic("i8042 \"Self test\" command not implemented.\n");
+ case InterfaceTest:
+ panic("i8042 \"Interface test\" command not implemented.\n");
+ case DiagnosticDump:
+ panic("i8042 \"Diagnostic dump\" command not implemented.\n");
+ case DisableKeyboard:
+ DPRINTF(I8042, "Disabling keyboard at controller.\n");
+ commandByte.disableKeyboard = 1;
+ break;
+ case EnableKeyboard:
+ DPRINTF(I8042, "Enabling keyboard at controller.\n");
+ commandByte.disableKeyboard = 0;
+ break;
+ case ReadInputPort:
+ panic("i8042 \"Read input port\" command not implemented.\n");
+ case ContinuousPollLow:
+ panic("i8042 \"Continuous poll low\" command not implemented.\n");
+ case ContinuousPollHigh:
+ panic("i8042 \"Continuous poll high\" command not implemented.\n");
+ case ReadOutputPort:
+ panic("i8042 \"Read output port\" command not implemented.\n");
+ case WriteOutputPort:
+ panic("i8042 \"Write output port\" command not implemented.\n");
+ case WriteKeyboardOutputBuff:
+ panic("i8042 \"Write keyboard output buffer\" "
+ "command not implemented.\n");
+ case WriteMouseOutputBuff:
+ DPRINTF(I8042, "Got command to write to mouse output buffer.\n");
+ lastCommand = WriteMouseOutputBuff;
+ break;
+ case WriteToMouse:
+ DPRINTF(I8042, "Expecting mouse command.\n");
+ lastCommand = WriteToMouse;
+ break;
+ case DisableA20:
+ panic("i8042 \"Disable A20\" command not implemented.\n");
+ case EnableA20:
+ panic("i8042 \"Enable A20\" command not implemented.\n");
+ case ReadTestInputs:
+ panic("i8042 \"Read test inputs\" command not implemented.\n");
+ case SystemReset:
+ panic("i8042 \"System reset\" command not implemented.\n");
+ default:
+ panic("Write to unknown i8042 "
+ "(keyboard controller) command port.\n");
+ }
+ } else {
+ panic("Write to unrecognized port %#x.\n", addr);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::I8042 *
+I8042Params::create()
+{
+ return new X86ISA::I8042(this);
+}
diff --git a/src/dev/x86/i8042.hh b/src/dev/x86/i8042.hh
new file mode 100644
index 000000000..8a941f9a5
--- /dev/null
+++ b/src/dev/x86/i8042.hh
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_I8042_HH__
+#define __DEV_X86_I8042_HH__
+
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I8042.hh"
+
+#include <queue>
+
+namespace X86ISA
+{
+
+class IntPin;
+
+class PS2Device
+{
+ protected:
+ std::queue<uint8_t> outBuffer;
+
+ static const uint16_t NoCommand = (uint16_t)(-1);
+
+ uint16_t lastCommand;
+ void bufferData(const uint8_t *data, int size);
+ void ack();
+ void nack();
+
+ public:
+ virtual ~PS2Device()
+ {};
+
+ PS2Device() : lastCommand(NoCommand)
+ {}
+
+ bool hasData()
+ {
+ return !outBuffer.empty();
+ }
+
+ uint8_t getData()
+ {
+ uint8_t data = outBuffer.front();
+ outBuffer.pop();
+ return data;
+ }
+
+ virtual bool processData(uint8_t data) = 0;
+};
+
+class PS2Mouse : public PS2Device
+{
+ protected:
+ static const uint8_t ID[];
+
+ enum Command
+ {
+ Scale1to1 = 0xE6,
+ Scale2to1 = 0xE7,
+ SetResolution = 0xE8,
+ GetStatus = 0xE9,
+ ReadData = 0xEB,
+ ResetWrapMode = 0xEC,
+ WrapMode = 0xEE,
+ RemoteMode = 0xF0,
+ ReadID = 0xF2,
+ SampleRate = 0xF3,
+ EnableReporting = 0xF4,
+ DisableReporting = 0xF5,
+ DefaultsAndDisable = 0xF6,
+ Resend = 0xFE,
+ Reset = 0xFF
+ };
+
+ BitUnion8(Status)
+ Bitfield<6> remote;
+ Bitfield<5> enabled;
+ Bitfield<4> twoToOne;
+ Bitfield<2> leftButton;
+ Bitfield<0> rightButton;
+ EndBitUnion(Status)
+
+ Status status;
+ uint8_t resolution;
+ uint8_t sampleRate;
+ public:
+ PS2Mouse() : PS2Device(), status(0), resolution(4), sampleRate(100)
+ {}
+
+ bool processData(uint8_t data);
+};
+
+class PS2Keyboard : public PS2Device
+{
+ protected:
+ static const uint8_t ID[];
+
+ enum Command
+ {
+ LEDWrite = 0xED,
+ DiagnosticEcho = 0xEE,
+ AlternateScanCodes = 0xF0,
+ ReadID = 0xF2,
+ TypematicInfo = 0xF3,
+ Enable = 0xF4,
+ Disable = 0xF5,
+ DefaultsAndDisable = 0xF6,
+ AllKeysToTypematic = 0xF7,
+ AllKeysToMakeRelease = 0xF8,
+ AllKeysToMake = 0xF9,
+ AllKeysToTypematicMakeRelease = 0xFA,
+ KeyToTypematic = 0xFB,
+ KeyToMakeRelease = 0xFC,
+ KeyToMakeOnly = 0xFD,
+ Resend = 0xFE,
+ Reset = 0xFF
+ };
+
+ public:
+ bool processData(uint8_t data);
+};
+
+class I8042 : public BasicPioDevice
+{
+ protected:
+ enum Command
+ {
+ GetCommandByte = 0x20,
+ ReadControllerRamBase = 0x20,
+ WriteCommandByte = 0x60,
+ WriteControllerRamBase = 0x60,
+ CheckForPassword = 0xA4,
+ LoadPassword = 0xA5,
+ CheckPassword = 0xA6,
+ DisableMouse = 0xA7,
+ EnableMouse = 0xA8,
+ TestMouse = 0xA9,
+ SelfTest = 0xAA,
+ InterfaceTest = 0xAB,
+ DiagnosticDump = 0xAC,
+ DisableKeyboard = 0xAD,
+ EnableKeyboard = 0xAE,
+ ReadInputPort = 0xC0,
+ ContinuousPollLow = 0xC1,
+ ContinuousPollHigh = 0xC2,
+ ReadOutputPort = 0xD0,
+ WriteOutputPort = 0xD1,
+ WriteKeyboardOutputBuff = 0xD2,
+ WriteMouseOutputBuff = 0xD3,
+ WriteToMouse = 0xD4,
+ DisableA20 = 0xDD,
+ EnableA20 = 0xDF,
+ ReadTestInputs = 0xE0,
+ PulseOutputBitBase = 0xF0,
+ SystemReset = 0xFE
+ };
+
+ BitUnion8(StatusReg)
+ Bitfield<7> parityError;
+ Bitfield<6> timeout;
+ Bitfield<5> mouseOutputFull;
+ Bitfield<4> keyboardUnlocked;
+ Bitfield<3> commandLast;
+ Bitfield<2> passedSelfTest;
+ Bitfield<1> inputFull;
+ Bitfield<0> outputFull;
+ EndBitUnion(StatusReg)
+
+ BitUnion8(CommandByte)
+ Bitfield<6> convertScanCodes;
+ Bitfield<5> disableMouse;
+ Bitfield<4> disableKeyboard;
+ Bitfield<2> passedSelfTest;
+ Bitfield<1> mouseFullInt;
+ Bitfield<0> keyboardFullInt;
+ EndBitUnion(CommandByte)
+
+ Tick latency;
+ Addr dataPort;
+ Addr commandPort;
+
+ StatusReg statusReg;
+ CommandByte commandByte;
+
+ uint8_t dataReg;
+
+ static const uint16_t NoCommand = (uint16_t)(-1);
+ uint16_t lastCommand;
+
+ IntSourcePin *mouseIntPin;
+ IntSourcePin *keyboardIntPin;
+
+ PS2Mouse mouse;
+ PS2Keyboard keyboard;
+
+ void writeData(uint8_t newData, bool mouse = false);
+ uint8_t readDataOut();
+
+ public:
+ typedef I8042Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8042(Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ dataPort(p->data_port), commandPort(p->command_port),
+ statusReg(0), commandByte(0), dataReg(0), lastCommand(NoCommand),
+ mouseIntPin(p->mouse_int_pin), keyboardIntPin(p->keyboard_int_pin)
+ {
+ statusReg.passedSelfTest = 1;
+ statusReg.commandLast = 1;
+ statusReg.keyboardUnlocked = 1;
+
+ commandByte.convertScanCodes = 1;
+ commandByte.passedSelfTest = 1;
+ commandByte.keyboardFullInt = 1;
+ }
+
+ void addressRanges(AddrRangeList &range_list);
+
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8042_HH__
diff --git a/src/dev/x86/i82094aa.cc b/src/dev/x86/i82094aa.cc
new file mode 100644
index 000000000..d160fcb24
--- /dev/null
+++ b/src/dev/x86/i82094aa.cc
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "arch/x86/intmessage.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8259.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "sim/system.hh"
+
+X86ISA::I82094AA::I82094AA(Params *p) : PioDevice(p), IntDev(this),
+ latency(p->pio_latency), pioAddr(p->pio_addr),
+ extIntPic(p->external_int_pic)
+{
+ // This assumes there's only one I/O APIC in the system
+ id = sys->numContexts();
+ assert(id <= 0xf);
+ arbId = id;
+ regSel = 0;
+ RedirTableEntry entry = 0;
+ entry.mask = 1;
+ for (int i = 0; i < TableSize; i++) {
+ redirTable[i] = entry;
+ pinStates[i] = false;
+ }
+}
+
+Tick
+X86ISA::I82094AA::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 4);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch(offset) {
+ case 0:
+ pkt->set<uint32_t>(regSel);
+ break;
+ case 16:
+ pkt->set<uint32_t>(readReg(regSel));
+ break;
+ default:
+ panic("Illegal read from I/O APIC.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I82094AA::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 4);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch(offset) {
+ case 0:
+ regSel = pkt->get<uint32_t>();
+ break;
+ case 16:
+ writeReg(regSel, pkt->get<uint32_t>());
+ break;
+ default:
+ panic("Illegal write to I/O APIC.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+void
+X86ISA::I82094AA::writeReg(uint8_t offset, uint32_t value)
+{
+ if (offset == 0x0) {
+ id = bits(value, 27, 24);
+ } else if (offset == 0x1) {
+ // The IOAPICVER register is read only.
+ } else if (offset == 0x2) {
+ arbId = bits(value, 27, 24);
+ } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
+ int index = (offset - 0x10) / 2;
+ if (offset % 2) {
+ redirTable[index].topDW = value;
+ redirTable[index].topReserved = 0;
+ } else {
+ redirTable[index].bottomDW = value;
+ redirTable[index].bottomReserved = 0;
+ }
+ } else {
+ warn("Access to undefined I/O APIC register %#x.\n", offset);
+ }
+ DPRINTF(I82094AA,
+ "Wrote %#x to I/O APIC register %#x .\n", value, offset);
+}
+
+uint32_t
+X86ISA::I82094AA::readReg(uint8_t offset)
+{
+ uint32_t result = 0;
+ if (offset == 0x0) {
+ result = id << 24;
+ } else if (offset == 0x1) {
+ result = ((TableSize - 1) << 16) | APICVersion;
+ } else if (offset == 0x2) {
+ result = arbId << 24;
+ } else if (offset >= 0x10 && offset <= (0x10 + TableSize * 2)) {
+ int index = (offset - 0x10) / 2;
+ if (offset % 2) {
+ result = redirTable[index].topDW;
+ } else {
+ result = redirTable[index].bottomDW;
+ }
+ } else {
+ warn("Access to undefined I/O APIC register %#x.\n", offset);
+ }
+ DPRINTF(I82094AA,
+ "Read %#x from I/O APIC register %#x.\n", result, offset);
+ return result;
+}
+
+void
+X86ISA::I82094AA::signalInterrupt(int line)
+{
+ DPRINTF(I82094AA, "Received interrupt %d.\n", line);
+ assert(line < TableSize);
+ RedirTableEntry entry = redirTable[line];
+ if (entry.mask) {
+ DPRINTF(I82094AA, "Entry was masked.\n");
+ return;
+ } else {
+ TriggerIntMessage message;
+ message.destination = entry.dest;
+ if (entry.deliveryMode == DeliveryMode::ExtInt) {
+ assert(extIntPic);
+ message.vector = extIntPic->getVector();
+ } else {
+ message.vector = entry.vector;
+ }
+ message.deliveryMode = entry.deliveryMode;
+ message.destMode = entry.destMode;
+ message.level = entry.polarity;
+ message.trigger = entry.trigger;
+
+ if (DeliveryMode::isReserved(entry.deliveryMode)) {
+ fatal("Tried to use reserved delivery mode "
+ "for IO APIC entry %d.\n", line);
+ } else if (DTRACE(I82094AA)) {
+ DPRINTF(I82094AA, "Delivery mode is: %s.\n",
+ DeliveryMode::names[entry.deliveryMode]);
+ DPRINTF(I82094AA, "Vector is %#x.\n", message.vector);
+ }
+
+ if (entry.destMode == 0) {
+ DPRINTF(I82094AA,
+ "Sending interrupt to APIC ID %d.\n", entry.dest);
+ PacketPtr pkt = buildIntRequest(entry.dest, message);
+ if (sys->getMemoryMode() == Enums::timing)
+ intPort->sendMessageTiming(pkt, latency);
+ else if (sys->getMemoryMode() == Enums::atomic)
+ intPort->sendMessageAtomic(pkt);
+ else
+ panic("Unrecognized memory mode.\n");
+ } else {
+ DPRINTF(I82094AA, "Sending interrupts to APIC IDs:"
+ "%s%s%s%s%s%s%s%s\n",
+ bits((int)entry.dest, 0) ? " 0": "",
+ bits((int)entry.dest, 1) ? " 1": "",
+ bits((int)entry.dest, 2) ? " 2": "",
+ bits((int)entry.dest, 3) ? " 3": "",
+ bits((int)entry.dest, 4) ? " 4": "",
+ bits((int)entry.dest, 5) ? " 5": "",
+ bits((int)entry.dest, 6) ? " 6": "",
+ bits((int)entry.dest, 7) ? " 7": ""
+ );
+ uint8_t dests = entry.dest;
+ uint8_t id = 0;
+ while(dests) {
+ if (dests & 0x1) {
+ PacketPtr pkt = buildIntRequest(id, message);
+ if (sys->getMemoryMode() == Enums::timing)
+ intPort->sendMessageTiming(pkt, latency);
+ else if (sys->getMemoryMode() == Enums::atomic)
+ intPort->sendMessageAtomic(pkt);
+ else
+ panic("Unrecognized memory mode.\n");
+ }
+ dests >>= 1;
+ id++;
+ }
+ }
+ }
+}
+
+void
+X86ISA::I82094AA::raiseInterruptPin(int number)
+{
+ assert(number < TableSize);
+ if (!pinStates[number])
+ signalInterrupt(number);
+ pinStates[number] = true;
+}
+
+void
+X86ISA::I82094AA::lowerInterruptPin(int number)
+{
+ assert(number < TableSize);
+ pinStates[number] = false;
+}
+
+X86ISA::I82094AA *
+I82094AAParams::create()
+{
+ return new X86ISA::I82094AA(this);
+}
diff --git a/src/dev/x86/i82094aa.hh b/src/dev/x86/i82094aa.hh
new file mode 100644
index 000000000..b11e2bcb1
--- /dev/null
+++ b/src/dev/x86/i82094aa.hh
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_I82094AA_HH__
+#define __DEV_X86_I82094AA_HH__
+
+#include "base/bitunion.hh"
+#include "base/range_map.hh"
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I82094AA.hh"
+
+namespace X86ISA
+{
+
+class I8259;
+
+class I82094AA : public PioDevice, public IntDev
+{
+ public:
+ BitUnion64(RedirTableEntry)
+ Bitfield<63, 32> topDW;
+ Bitfield<55, 32> topReserved;
+ Bitfield<31, 0> bottomDW;
+ Bitfield<31, 17> bottomReserved;
+ Bitfield<63, 56> dest;
+ Bitfield<16> mask;
+ Bitfield<15> trigger;
+ Bitfield<14> remoteIRR;
+ Bitfield<13> polarity;
+ Bitfield<12> deliveryStatus;
+ Bitfield<11> destMode;
+ Bitfield<10, 8> deliveryMode;
+ Bitfield<7, 0> vector;
+ EndBitUnion(RedirTableEntry)
+
+ protected:
+ Tick latency;
+ Addr pioAddr;
+
+ I8259 * extIntPic;
+
+ uint8_t regSel;
+ uint8_t id;
+ uint8_t arbId;
+
+ static const uint8_t TableSize = 24;
+ // This implementation is based on version 0x11, but 0x14 avoids having
+ // to deal with the arbitration and APIC bus guck.
+ static const uint8_t APICVersion = 0x14;
+
+ RedirTableEntry redirTable[TableSize];
+ bool pinStates[TableSize];
+
+ public:
+ typedef I82094AAParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I82094AA(Params *p);
+
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+
+ void addressRanges(AddrRangeList &range_list)
+ {
+ range_list.clear();
+ range_list.push_back(RangeEx(pioAddr, pioAddr + 4));
+ range_list.push_back(RangeEx(pioAddr + 16, pioAddr + 20));
+ }
+
+ void getIntAddrRange(AddrRangeList &range_list)
+ {
+ range_list.clear();
+ range_list.push_back(RangeEx(x86InterruptAddress(1, 0),
+ x86InterruptAddress(1, 0) + PhysAddrAPICRangeSize));
+ }
+
+ void writeReg(uint8_t offset, uint32_t value);
+ uint32_t readReg(uint8_t offset);
+
+ Port *getPort(const std::string &if_name, int idx = -1)
+ {
+ if (if_name == "int_port")
+ return intPort;
+ return PioDevice::getPort(if_name, idx);
+ }
+
+ void signalInterrupt(int line);
+ void raiseInterruptPin(int number);
+ void lowerInterruptPin(int number);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__
diff --git a/src/dev/x86/i8237.cc b/src/dev/x86/i8237.cc
new file mode 100644
index 000000000..f6ea9d75f
--- /dev/null
+++ b/src/dev/x86/i8237.cc
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "dev/x86/i8237.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+Tick
+X86ISA::I8237::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch (offset) {
+ case 0x0:
+ panic("Read from i8237 channel 0 current address unimplemented.\n");
+ case 0x1:
+ panic("Read from i8237 channel 0 remaining "
+ "word count unimplemented.\n");
+ case 0x2:
+ panic("Read from i8237 channel 1 current address unimplemented.\n");
+ case 0x3:
+ panic("Read from i8237 channel 1 remaining "
+ "word count unimplemented.\n");
+ case 0x4:
+ panic("Read from i8237 channel 2 current address unimplemented.\n");
+ case 0x5:
+ panic("Read from i8237 channel 2 remaining "
+ "word count unimplemented.\n");
+ case 0x6:
+ panic("Read from i8237 channel 3 current address unimplemented.\n");
+ case 0x7:
+ panic("Read from i8237 channel 3 remaining "
+ "word count unimplemented.\n");
+ case 0x8:
+ panic("Read from i8237 status register unimplemented.\n");
+ default:
+ panic("Read from undefined i8237 register %d.\n", offset);
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8237::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ switch (offset) {
+ case 0x0:
+ panic("Write to i8237 channel 0 starting address unimplemented.\n");
+ case 0x1:
+ panic("Write to i8237 channel 0 starting "
+ "word count unimplemented.\n");
+ case 0x2:
+ panic("Write to i8237 channel 1 starting address unimplemented.\n");
+ case 0x3:
+ panic("Write to i8237 channel 1 starting "
+ "word count unimplemented.\n");
+ case 0x4:
+ panic("Write to i8237 channel 2 starting address unimplemented.\n");
+ case 0x5:
+ panic("Write to i8237 channel 2 starting "
+ "word count unimplemented.\n");
+ case 0x6:
+ panic("Write to i8237 channel 3 starting address unimplemented.\n");
+ case 0x7:
+ panic("Write to i8237 channel 3 starting "
+ "word count unimplemented.\n");
+ case 0x8:
+ panic("Write to i8237 command register unimplemented.\n");
+ case 0x9:
+ panic("Write to i8237 request register unimplemented.\n");
+ case 0xa:
+ {
+ uint8_t command = pkt->get<uint8_t>();
+ uint8_t select = bits(command, 1, 0);
+ uint8_t bitVal = bits(command, 2);
+ if (!bitVal)
+ panic("Turning on i8237 channels unimplemented.\n");
+ replaceBits(maskReg, select, bitVal);
+ }
+ break;
+ case 0xb:
+ panic("Write to i8237 mode register unimplemented.\n");
+ case 0xc:
+ panic("Write to i8237 clear LSB/MSB flip-flop "
+ "register unimplemented.\n");
+ case 0xd:
+ panic("Write to i8237 master clear/reset register unimplemented.\n");
+ case 0xe:
+ panic("Write to i8237 clear mask register unimplemented.\n");
+ case 0xf:
+ panic("Write to i8237 write all mask register bits unimplemented.\n");
+ default:
+ panic("Write to undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::I8237 *
+I8237Params::create()
+{
+ return new X86ISA::I8237(this);
+}
diff --git a/src/cpu/o3/sparc/params.hh b/src/dev/x86/i8237.hh
index 09f523818..2d73b8ab5 100644
--- a/src/cpu/o3/sparc/params.hh
+++ b/src/dev/x86/i8237.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2006 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,34 +28,39 @@
* Authors: Gabe Black
*/
-#ifndef __CPU_O3_SPARC_PARAMS_HH__
-#define __CPU_O3_SPARC_PARAMS_HH__
+#ifndef __DEV_X86_I8237_HH__
+#define __DEV_X86_I8237_HH__
-#include "cpu/o3/cpu.hh"
-#include "cpu/o3/params.hh"
+#include "dev/io_device.hh"
+#include "params/I8237.hh"
-//Forward declarations
-namespace SparcISA
+namespace X86ISA
{
- class DTB;
- class ITB;
-}
-class MemObject;
-class Process;
-class System;
-
-/**
- * This file defines the parameters that will be used for the AlphaO3CPU.
- * This must be defined externally so that the Impl can have a params class
- * defined that it can pass to all of the individual stages.
- */
-class SparcSimpleParams : public O3Params
+class I8237 : public BasicPioDevice
{
+ protected:
+ Tick latency;
+ uint8_t maskReg;
+
public:
+ typedef I8237Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
- SparcISA::ITB *itb;
- SparcISA::DTB *dtb;
+ I8237(Params *p) : BasicPioDevice(p), latency(p->pio_latency), maskReg(0)
+ {
+ pioSize = 16;
+ }
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
};
-#endif // __CPU_O3_SPARC_PARAMS_HH__
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8237_HH__
diff --git a/src/base/stats/statdb.cc b/src/dev/x86/i8254.cc
index f9136807a..5eb28844a 100644
--- a/src/base/stats/statdb.cc
+++ b/src/dev/x86/i8254.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,59 +25,59 @@
* (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
+ * Authors: Gabe Black
*/
-#include "base/misc.hh"
-#include "base/trace.hh"
-#include "base/statistics.hh"
-#include "base/stats/statdb.hh"
+#include "dev/x86/i8254.hh"
+#include "dev/x86/intdev.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
-using namespace std;
-
-namespace Stats {
-namespace Database {
-
-StatData *
-find(void *stat)
+void
+X86ISA::I8254::counterInterrupt(unsigned int num)
{
- stat_map_t::const_iterator i = map().find(stat);
-
- if (i == map().end())
- return NULL;
-
- return (*i).second;
+ DPRINTF(I8254, "Interrupt from counter %d.\n", num);
+ if (num == 0) {
+ intPin->raise();
+ //XXX This is a hack.
+ intPin->lower();
+ }
}
-void
-regStat(void *stat, StatData *data)
+Tick
+X86ISA::I8254::read(PacketPtr pkt)
{
- if (map().find(stat) != map().end())
- panic("shouldn't register stat twice!");
-
- stats().push_back(data);
-
-#ifndef NDEBUG
- pair<stat_map_t::iterator, bool> result =
-#endif
- map().insert(make_pair(stat, data));
- assert(result.second && "this should never fail");
- assert(map().find(stat) != map().end());
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ if (offset < 3) {
+ pkt->set(pit.readCounter(offset));
+ } else if (offset == 3) {
+ pkt->set(uint8_t(-1));
+ } else {
+ panic("Read from undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
}
-void
-regPrint(void *stat)
+Tick
+X86ISA::I8254::write(PacketPtr pkt)
{
- StatData *data = find(stat);
- assert(data);
- data->flags |= print;
+ assert(pkt->getSize() == 1);
+ Addr offset = pkt->getAddr() - pioAddr;
+ if (offset < 3) {
+ pit.writeCounter(offset, pkt->get<uint8_t>());
+ } else if (offset == 3) {
+ pit.writeControl(pkt->get<uint8_t>());
+ } else {
+ panic("Write to undefined i8254 register.\n");
+ }
+ pkt->makeAtomicResponse();
+ return latency;
}
-TheDatabase &db()
+X86ISA::I8254 *
+I8254Params::create()
{
- static TheDatabase db;
- return db;
+ return new X86ISA::I8254(this);
}
-
-/* namespace Database */ }
-/* namespace Stats */ }
diff --git a/src/dev/x86/i8254.hh b/src/dev/x86/i8254.hh
new file mode 100644
index 000000000..7de20dfd4
--- /dev/null
+++ b/src/dev/x86/i8254.hh
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_I8254_HH__
+#define __DEV_X86_I8254_HH__
+
+#include "dev/intel_8254_timer.hh"
+#include "dev/io_device.hh"
+#include "params/I8254.hh"
+
+namespace X86ISA
+{
+
+class IntSourcePin;
+
+class I8254 : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+ class X86Intel8254Timer : public Intel8254Timer
+ {
+ protected:
+ I8254 * parent;
+
+ void
+ counterInterrupt(unsigned int num)
+ {
+ parent->counterInterrupt(num);
+ }
+
+ public:
+ X86Intel8254Timer(const std::string &name, I8254 * _parent) :
+ Intel8254Timer(_parent, name), parent(_parent)
+ {}
+ };
+
+
+ X86Intel8254Timer pit;
+
+ IntSourcePin *intPin;
+
+ void counterInterrupt(unsigned int num);
+
+ public:
+ typedef I8254Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8254(Params *p) : BasicPioDevice(p), latency(p->pio_latency),
+ pit(p->name, this), intPin(p->int_pin)
+ {
+ pioSize = 4;
+ }
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+
+ bool
+ outputHigh(unsigned int num)
+ {
+ return pit.outputHigh(num);
+ }
+
+ uint8_t
+ readCounter(unsigned int num)
+ {
+ return pit.readCounter(num);
+ }
+
+ void
+ writeCounter(unsigned int num, const uint8_t data)
+ {
+ pit.writeCounter(num, data);
+ }
+
+ void
+ writeControl(uint8_t val)
+ {
+ pit.writeControl(val);
+ }
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_SOUTH_BRIDGE_I8254_HH__
diff --git a/src/dev/x86/i8259.cc b/src/dev/x86/i8259.cc
new file mode 100644
index 000000000..b868295eb
--- /dev/null
+++ b/src/dev/x86/i8259.cc
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ *
+ * Authors: Gabe Black
+ */
+
+#include "base/bitfield.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8259.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+X86ISA::I8259::I8259(Params * p) : BasicPioDevice(p), IntDev(this),
+ latency(p->pio_latency), output(p->output),
+ mode(p->mode), slave(p->slave),
+ IRR(0), ISR(0), IMR(0),
+ readIRR(true), initControlWord(0), autoEOI(false)
+{
+ for (int i = 0; i < NumLines; i++)
+ pinStates[i] = false;
+ pioSize = 2;
+}
+
+Tick
+X86ISA::I8259::read(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ switch(pkt->getAddr() - pioAddr)
+ {
+ case 0x0:
+ if (readIRR) {
+ DPRINTF(I8259, "Reading IRR as %#x.\n", IRR);
+ pkt->set(IRR);
+ } else {
+ DPRINTF(I8259, "Reading ISR as %#x.\n", ISR);
+ pkt->set(ISR);
+ }
+ break;
+ case 0x1:
+ DPRINTF(I8259, "Reading IMR as %#x.\n", IMR);
+ pkt->set(IMR);
+ break;
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::I8259::write(PacketPtr pkt)
+{
+ assert(pkt->getSize() == 1);
+ uint8_t val = pkt->get<uint8_t>();
+ switch (pkt->getAddr() - pioAddr) {
+ case 0x0:
+ if (bits(val, 4)) {
+ DPRINTF(I8259, "Received initialization command word 1.\n");
+ IMR = 0;
+ edgeTriggered = bits(val, 3);
+ DPRINTF(I8259, "%s triggered mode.\n",
+ edgeTriggered ? "Edge" : "Level");
+ cascadeMode = !bits(val, 1);
+ DPRINTF(I8259, "%s mode.\n",
+ cascadeMode ? "Cascade" : "Single");
+ expectICW4 = bits(val, 0);
+ if (!expectICW4) {
+ autoEOI = false;
+ }
+ initControlWord = 1;
+ DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2);
+ } else if (bits(val, 4, 3) == 0) {
+ DPRINTF(I8259, "Received operation command word 2.\n");
+ switch (bits(val, 7, 5)) {
+ case 0x0:
+ DPRINTF(I8259,
+ "Subcommand: Rotate in auto-EOI mode (clear).\n");
+ break;
+ case 0x1:
+ {
+ int line = findMsbSet(ISR);
+ DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n",
+ line);
+ handleEOI(line);
+ }
+ break;
+ case 0x2:
+ DPRINTF(I8259, "Subcommand: No operation.\n");
+ break;
+ case 0x3:
+ {
+ int line = bits(val, 2, 0);
+ DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n",
+ line);
+ handleEOI(line);
+ }
+ break;
+ case 0x4:
+ DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n");
+ break;
+ case 0x5:
+ DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n");
+ break;
+ case 0x6:
+ DPRINTF(I8259, "Subcommand: Set priority command.\n");
+ DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
+ bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
+ break;
+ case 0x7:
+ DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n");
+ DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
+ bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
+ break;
+ }
+ } else if (bits(val, 4, 3) == 1) {
+ DPRINTF(I8259, "Received operation command word 3.\n");
+ if (bits(val, 7)) {
+ DPRINTF(I8259, "%s special mask mode.\n",
+ bits(val, 6) ? "Set" : "Clear");
+ }
+ if (bits(val, 1)) {
+ readIRR = bits(val, 0);
+ DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR");
+ }
+ }
+ break;
+ case 0x1:
+ switch (initControlWord) {
+ case 0x0:
+ DPRINTF(I8259, "Received operation command word 1.\n");
+ DPRINTF(I8259, "Wrote IMR value %#x.\n", val);
+ IMR = val;
+ break;
+ case 0x1:
+ DPRINTF(I8259, "Received initialization command word 2.\n");
+ vectorOffset = val & ~mask(3);
+ DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n",
+ vectorOffset, vectorOffset | mask(3));
+ if (cascadeMode) {
+ initControlWord++;
+ } else {
+ cascadeBits = 0;
+ initControlWord = 0;
+ }
+ break;
+ case 0x2:
+ DPRINTF(I8259, "Received initialization command word 3.\n");
+ if (mode == Enums::I8259Master) {
+ DPRINTF(I8259, "Slaves attached to IRQs:%s%s%s%s%s%s%s%s\n",
+ bits(val, 0) ? " 0" : "",
+ bits(val, 1) ? " 1" : "",
+ bits(val, 2) ? " 2" : "",
+ bits(val, 3) ? " 3" : "",
+ bits(val, 4) ? " 4" : "",
+ bits(val, 5) ? " 5" : "",
+ bits(val, 6) ? " 6" : "",
+ bits(val, 7) ? " 7" : "");
+ cascadeBits = val;
+ } else {
+ DPRINTF(I8259, "Slave ID is %d.\n", val & mask(3));
+ cascadeBits = val & mask(3);
+ }
+ if (expectICW4)
+ initControlWord++;
+ else
+ initControlWord = 0;
+ break;
+ case 0x3:
+ DPRINTF(I8259, "Received initialization command word 4.\n");
+ if (bits(val, 4)) {
+ DPRINTF(I8259, "Special fully nested mode.\n");
+ } else {
+ DPRINTF(I8259, "Not special fully nested mode.\n");
+ }
+ if (bits(val, 3) == 0) {
+ DPRINTF(I8259, "Nonbuffered.\n");
+ } else if (bits(val, 2) == 0) {
+ DPRINTF(I8259, "Buffered.\n");
+ } else {
+ DPRINTF(I8259, "Unrecognized buffer mode.\n");
+ }
+ autoEOI = bits(val, 1);
+ DPRINTF(I8259, "%s End Of Interrupt.\n",
+ autoEOI ? "Automatic" : "Normal");
+
+ DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85");
+ initControlWord = 0;
+ break;
+ }
+ break;
+ }
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+void
+X86ISA::I8259::handleEOI(int line)
+{
+ ISR &= ~(1 << line);
+ // There may be an interrupt that was waiting which can
+ // now be sent.
+ if (IRR)
+ requestInterrupt(findMsbSet(IRR));
+}
+
+void
+X86ISA::I8259::requestInterrupt(int line)
+{
+ if (bits(ISR, 7, line) == 0) {
+ if (output) {
+ DPRINTF(I8259, "Propogating interrupt.\n");
+ output->raise();
+ //XXX This is a hack.
+ output->lower();
+ } else {
+ warn("Received interrupt but didn't have "
+ "anyone to tell about it.\n");
+ }
+ }
+}
+
+void
+X86ISA::I8259::signalInterrupt(int line)
+{
+ DPRINTF(I8259, "Interrupt requested for line %d.\n", line);
+ if (line >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ line, NumLines - 1);
+ if (bits(IMR, line)) {
+ DPRINTF(I8259, "Interrupt %d was masked.\n", line);
+ } else {
+ IRR |= 1 << line;
+ requestInterrupt(line);
+ }
+}
+
+void
+X86ISA::I8259::raiseInterruptPin(int number)
+{
+ DPRINTF(I8259, "Interrupt signal raised for pin %d.\n", number);
+ if (number >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ number, NumLines - 1);
+ if (!pinStates[number])
+ signalInterrupt(number);
+ pinStates[number] = true;
+}
+
+void
+X86ISA::I8259::lowerInterruptPin(int number)
+{
+ DPRINTF(I8259, "Interrupt signal lowered for pin %d.\n", number);
+ if (number >= NumLines)
+ fatal("Line number %d doesn't exist. The max is %d.\n",
+ number, NumLines - 1);
+ pinStates[number] = false;
+}
+
+int
+X86ISA::I8259::getVector()
+{
+ /*
+ * This code only handles one slave. Since that's how the PC platform
+ * always uses the 8259 PIC, there shouldn't be any need for more. If
+ * there -is- a need for more for some reason, "slave" can become a
+ * vector of slaves.
+ */
+ int line = findMsbSet(IRR);
+ IRR &= ~(1 << line);
+ DPRINTF(I8259, "Interrupt %d was accepted.\n", line);
+ if (autoEOI) {
+ handleEOI(line);
+ } else {
+ ISR |= 1 << line;
+ }
+ if (slave && bits(cascadeBits, line)) {
+ DPRINTF(I8259, "Interrupt was from slave who will "
+ "provide the vector.\n");
+ return slave->getVector();
+ }
+ return line | vectorOffset;
+}
+
+X86ISA::I8259 *
+I8259Params::create()
+{
+ return new X86ISA::I8259(this);
+}
diff --git a/src/dev/x86/i8259.hh b/src/dev/x86/i8259.hh
new file mode 100644
index 000000000..dfb56646a
--- /dev/null
+++ b/src/dev/x86/i8259.hh
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ *
+ * Authors: Gabe Black
+ */
+
+#ifndef __DEV_X86_I8259_HH__
+#define __DEV_X86_I8259_HH__
+
+#include "dev/io_device.hh"
+#include "dev/x86/intdev.hh"
+#include "params/I8259.hh"
+#include "enums/X86I8259CascadeMode.hh"
+
+namespace X86ISA
+{
+
+class I82094AA;
+
+class I8259 : public BasicPioDevice, public IntDev
+{
+ protected:
+ static const int NumLines = 8;
+ bool pinStates[NumLines];
+
+ Tick latency;
+ IntSourcePin *output;
+ Enums::X86I8259CascadeMode mode;
+ I8259 * slave;
+
+ // Interrupt Request Register
+ uint8_t IRR;
+ // In Service Register
+ uint8_t ISR;
+ // Interrupt Mask Register
+ uint8_t IMR;
+
+ // The higher order bits of the vector to return
+ uint8_t vectorOffset;
+
+ bool cascadeMode;
+ // A bit vector of lines with slaves attached, or the slave id, depending
+ // on if this is a master or slave PIC.
+ uint8_t cascadeBits;
+
+ bool edgeTriggered;
+ bool readIRR;
+
+ // State machine information for reading in initialization control words.
+ bool expectICW4;
+ int initControlWord;
+
+ // Whether or not the PIC is in auto EOI mode.
+ bool autoEOI;
+
+ void requestInterrupt(int line);
+ void handleEOI(int line);
+
+ public:
+ typedef I8259Params Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ I8259(Params * p);
+
+ Tick read(PacketPtr pkt);
+ Tick write(PacketPtr pkt);
+
+ void signalInterrupt(int line);
+ void raiseInterruptPin(int number);
+ void lowerInterruptPin(int number);
+ int getVector();
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_I8259_HH__
diff --git a/src/dev/x86/intdev.cc b/src/dev/x86/intdev.cc
new file mode 100644
index 000000000..e386687a9
--- /dev/null
+++ b/src/dev/x86/intdev.cc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "dev/x86/intdev.hh"
+
+X86ISA::IntSourcePin *
+X86IntSourcePinParams::create()
+{
+ return new X86ISA::IntSourcePin(this);
+}
+
+X86ISA::IntSinkPin *
+X86IntSinkPinParams::create()
+{
+ return new X86ISA::IntSinkPin(this);
+}
+
+X86ISA::IntLine *
+X86IntLineParams::create()
+{
+ return new X86ISA::IntLine(this);
+}
diff --git a/src/dev/x86/intdev.hh b/src/dev/x86/intdev.hh
new file mode 100644
index 000000000..ca8e7eea5
--- /dev/null
+++ b/src/dev/x86/intdev.hh
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_INTDEV_HH__
+#define __DEV_X86_INTDEV_HH__
+
+#include <assert.h>
+#include <string>
+
+#include "arch/x86/x86_traits.hh"
+#include "mem/mem_object.hh"
+#include "mem/mport.hh"
+#include "sim/sim_object.hh"
+#include "params/X86IntSourcePin.hh"
+#include "params/X86IntSinkPin.hh"
+#include "params/X86IntLine.hh"
+
+namespace X86ISA {
+
+class IntDev
+{
+ protected:
+ class IntPort : public MessagePort
+ {
+ IntDev * device;
+ Tick latency;
+ Addr intAddr;
+ public:
+ IntPort(const std::string &_name, MemObject * _parent,
+ IntDev *dev, Tick _latency) :
+ MessagePort(_name, _parent), device(dev), latency(_latency)
+ {
+ }
+
+ void getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+ {
+ snoop = false;
+ device->getIntAddrRange(resp);
+ }
+
+ Tick recvMessage(PacketPtr pkt)
+ {
+ return device->recvMessage(pkt);
+ }
+
+ void recvStatusChange(Status status)
+ {
+ if (status == RangeChange) {
+ sendStatusChange(Port::RangeChange);
+ }
+ }
+
+ };
+
+ IntPort * intPort;
+
+ public:
+ IntDev(MemObject * parent, Tick latency = 0)
+ {
+ if (parent != NULL) {
+ intPort = new IntPort(parent->name() + ".int_port",
+ parent, this, latency);
+ } else {
+ intPort = NULL;
+ }
+ }
+
+ virtual ~IntDev()
+ {}
+
+ virtual void
+ signalInterrupt(int line)
+ {
+ panic("signalInterrupt not implemented.\n");
+ }
+
+ virtual void
+ raiseInterruptPin(int number)
+ {
+ panic("raiseInterruptPin not implemented.\n");
+ }
+
+ virtual void
+ lowerInterruptPin(int number)
+ {
+ panic("lowerInterruptPin not implemented.\n");
+ }
+
+ virtual Tick
+ recvMessage(PacketPtr pkt)
+ {
+ panic("recvMessage not implemented.\n");
+ return 0;
+ }
+
+ virtual void
+ getIntAddrRange(AddrRangeList &range_list)
+ {
+ panic("intAddrRange not implemented.\n");
+ }
+};
+
+class IntSinkPin : public SimObject
+{
+ public:
+ IntDev * device;
+ int number;
+
+ typedef X86IntSinkPinParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ IntSinkPin(Params *p) : SimObject(p),
+ device(dynamic_cast<IntDev *>(p->device)), number(p->number)
+ {
+ assert(device);
+ }
+};
+
+class IntSourcePin : public SimObject
+{
+ protected:
+ std::vector<IntSinkPin *> sinks;
+
+ public:
+ typedef X86IntSourcePinParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ void
+ addSink(IntSinkPin *sink)
+ {
+ sinks.push_back(sink);
+ }
+
+ void
+ raise()
+ {
+ for (int i = 0; i < sinks.size(); i++) {
+ const IntSinkPin &pin = *sinks[i];
+ pin.device->raiseInterruptPin(pin.number);
+ }
+ }
+
+ void
+ lower()
+ {
+ for (int i = 0; i < sinks.size(); i++) {
+ const IntSinkPin &pin = *sinks[i];
+ pin.device->lowerInterruptPin(pin.number);
+ }
+ }
+
+ IntSourcePin(Params *p) : SimObject(p)
+ {}
+};
+
+class IntLine : public SimObject
+{
+ protected:
+ IntSourcePin *source;
+ IntSinkPin *sink;
+
+ public:
+ typedef X86IntLineParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ IntLine(Params *p) : SimObject(p), source(p->source), sink(p->sink)
+ {
+ source->addSink(sink);
+ }
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_INTDEV_HH__
diff --git a/src/dev/x86/pc.cc b/src/dev/x86/pc.cc
new file mode 100644
index 000000000..d1ab4af7f
--- /dev/null
+++ b/src/dev/x86/pc.cc
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+/** @file
+ * Implementation of PC platform.
+ */
+
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "arch/x86/intmessage.hh"
+#include "arch/x86/x86_traits.hh"
+#include "cpu/intr_control.hh"
+#include "dev/terminal.hh"
+#include "dev/x86/i82094aa.hh"
+#include "dev/x86/i8254.hh"
+#include "dev/x86/i8259.hh"
+#include "dev/x86/pc.hh"
+#include "dev/x86/south_bridge.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+Pc::Pc(const Params *p)
+ : Platform(p), system(p->system)
+{
+ southBridge = NULL;
+ // set the back pointer from the system to myself
+ system->platform = this;
+}
+
+void
+Pc::init()
+{
+ assert(southBridge);
+
+ /*
+ * Initialize the timer.
+ */
+ I8254 & timer = *southBridge->pit;
+ //Timer 0, mode 2, no bcd, 16 bit count
+ timer.writeControl(0x34);
+ //Timer 0, latch command
+ timer.writeControl(0x00);
+ //Write a 16 bit count of 0
+ timer.writeCounter(0, 0);
+ timer.writeCounter(0, 0);
+
+ /*
+ * Initialize the I/O APIC.
+ */
+ I82094AA & ioApic = *southBridge->ioApic;
+ I82094AA::RedirTableEntry entry = 0;
+ entry.deliveryMode = DeliveryMode::ExtInt;
+ entry.vector = 0x20;
+ ioApic.writeReg(0x10, entry.bottomDW);
+ ioApic.writeReg(0x11, entry.topDW);
+ entry.deliveryMode = DeliveryMode::Fixed;
+ entry.vector = 0x24;
+ ioApic.writeReg(0x18, entry.bottomDW);
+ ioApic.writeReg(0x19, entry.topDW);
+ entry.mask = 1;
+ entry.vector = 0x21;
+ ioApic.writeReg(0x12, entry.bottomDW);
+ ioApic.writeReg(0x13, entry.topDW);
+ entry.vector = 0x20;
+ ioApic.writeReg(0x14, entry.bottomDW);
+ ioApic.writeReg(0x15, entry.topDW);
+ entry.vector = 0x28;
+ ioApic.writeReg(0x20, entry.bottomDW);
+ ioApic.writeReg(0x21, entry.topDW);
+ entry.vector = 0x2C;
+ ioApic.writeReg(0x28, entry.bottomDW);
+ ioApic.writeReg(0x29, entry.topDW);
+ entry.vector = 0x2E;
+ ioApic.writeReg(0x2C, entry.bottomDW);
+ ioApic.writeReg(0x2D, entry.topDW);
+ entry.vector = 0x30;
+ ioApic.writeReg(0x30, entry.bottomDW);
+ ioApic.writeReg(0x31, entry.topDW);
+}
+
+Tick
+Pc::intrFrequency()
+{
+ panic("Need implementation for intrFrequency\n");
+ M5_DUMMY_RETURN
+}
+
+void
+Pc::postConsoleInt()
+{
+ southBridge->ioApic->signalInterrupt(4);
+ southBridge->pic1->signalInterrupt(4);
+}
+
+void
+Pc::clearConsoleInt()
+{
+ warn_once("Don't know what interrupt to clear for console.\n");
+ //panic("Need implementation\n");
+}
+
+void
+Pc::postPciInt(int line)
+{
+ southBridge->ioApic->signalInterrupt(line);
+}
+
+void
+Pc::clearPciInt(int line)
+{
+ warn_once("Tried to clear PCI interrupt %d\n", line);
+}
+
+Addr
+Pc::pciToDma(Addr pciAddr) const
+{
+ return pciAddr;
+}
+
+Addr
+Pc::calcPciConfigAddr(int bus, int dev, int func)
+{
+ assert(func < 8);
+ assert(dev < 32);
+ assert(bus == 0);
+ return (PhysAddrPrefixPciConfig | (func << 8) | (dev << 11));
+}
+
+Addr
+Pc::calcPciIOAddr(Addr addr)
+{
+ return PhysAddrPrefixIO + addr;
+}
+
+Addr
+Pc::calcPciMemAddr(Addr addr)
+{
+ return addr;
+}
+
+Pc *
+PcParams::create()
+{
+ return new Pc(this);
+}
diff --git a/src/dev/x86/opteron.hh b/src/dev/x86/pc.hh
index 3026bce73..427cc4165 100644
--- a/src/dev/x86/opteron.hh
+++ b/src/dev/x86/pc.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,29 +30,36 @@
/**
* @file
- * Declaration of top level class for the Opteron platform chips. This class
+ * Declaration of top level class for PC platform components. This class
* just retains pointers to all its children so the children can communicate.
*/
-#ifndef __DEV_Opteron_HH__
-#define __DEV_Opteron_HH__
+#ifndef __DEV_PC_HH__
+#define __DEV_PC_HH__
#include "dev/platform.hh"
-#include "params/Opteron.hh"
+#include "params/Pc.hh"
class IdeController;
class System;
+class SouthBridge;
-class Opteron : public Platform
+class Pc : public Platform
{
public:
/** Pointer to the system */
System *system;
+ SouthBridge *southBridge;
public:
- typedef OpteronParams Params;
+ typedef PcParams Params;
- Opteron(const Params *p);
+ /**
+ * Do platform initialization stuff
+ */
+ void init();
+
+ Pc(const Params *p);
/**
* Return the interrupting frequency to AlphaAccess
@@ -86,7 +93,17 @@ class Opteron : public Platform
/**
* Calculate the configuration address given a bus/dev/func.
*/
- virtual Addr calcConfigAddr(int bus, int dev, int func);
+ virtual Addr calcPciConfigAddr(int bus, int dev, int func);
+
+ /**
+ * Calculate the address for an IO location on the PCI bus.
+ */
+ virtual Addr calcPciIOAddr(Addr addr);
+
+ /**
+ * Calculate the address for a memory location on the PCI bus.
+ */
+ virtual Addr calcPciMemAddr(Addr addr);
};
-#endif // __DEV_OPTERON_HH__
+#endif // __DEV_PC_HH__
diff --git a/src/dev/x86/south_bridge.cc b/src/dev/x86/south_bridge.cc
new file mode 100644
index 000000000..c456f478d
--- /dev/null
+++ b/src/dev/x86/south_bridge.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include <assert.h>
+
+#include "dev/x86/pc.hh"
+#include "dev/x86/south_bridge.hh"
+
+using namespace X86ISA;
+
+SouthBridge::SouthBridge(const Params *p) : SimObject(p),
+ platform(p->platform), pit(p->pit), pic1(p->pic1), pic2(p->pic2),
+ cmos(p->cmos), speaker(p->speaker), ioApic(p->io_apic)
+{
+ // Let the platform know where we are
+ Pc * pc = dynamic_cast<Pc *>(platform);
+ assert(pc);
+ pc->southBridge = this;
+}
+
+SouthBridge *
+SouthBridgeParams::create()
+{
+ return new SouthBridge(this);
+}
diff --git a/src/dev/x86/south_bridge.hh b/src/dev/x86/south_bridge.hh
new file mode 100644
index 000000000..61d6d387a
--- /dev/null
+++ b/src/dev/x86/south_bridge.hh
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#ifndef __DEV_X86_SOUTH_BRIDGE_HH__
+#define __DEV_X86_SOUTH_BRIDGE_HH__
+
+#include "sim/sim_object.hh"
+#include "params/SouthBridge.hh"
+
+namespace X86ISA
+{
+ class I8254;
+ class I8259;
+ class Cmos;
+ class Speaker;
+ class I82094AA;
+}
+
+class SouthBridge : public SimObject
+{
+ protected:
+ Platform * platform;
+
+ public:
+ X86ISA::I8254 * pit;
+ X86ISA::I8259 * pic1;
+ X86ISA::I8259 * pic2;
+ X86ISA::Cmos * cmos;
+ X86ISA::Speaker * speaker;
+ X86ISA::I82094AA * ioApic;
+
+ public:
+ typedef SouthBridgeParams Params;
+ SouthBridge(const Params *p);
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+};
+
+#endif //__DEV_X86_SOUTH_BRIDGE_HH__
diff --git a/src/dev/x86/speaker.cc b/src/dev/x86/speaker.cc
new file mode 100644
index 000000000..c6eb9db9e
--- /dev/null
+++ b/src/dev/x86/speaker.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "base/bitunion.hh"
+#include "base/trace.hh"
+#include "dev/x86/i8254.hh"
+#include "dev/x86/speaker.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+
+Tick
+X86ISA::Speaker::read(PacketPtr pkt)
+{
+ assert(pkt->getAddr() == pioAddr);
+ assert(pkt->getSize() == 1);
+ controlVal.timer = timer->outputHigh(2) ? 1 : 0;
+ DPRINTF(PcSpeaker,
+ "Reading from speaker device: gate %s, speaker %s, output %s.\n",
+ controlVal.gate ? "on" : "off",
+ controlVal.speaker ? "on" : "off",
+ controlVal.timer ? "on" : "off");
+ pkt->set((uint8_t)controlVal);
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+Tick
+X86ISA::Speaker::write(PacketPtr pkt)
+{
+ assert(pkt->getAddr() == pioAddr);
+ assert(pkt->getSize() == 1);
+ SpeakerControl val = pkt->get<uint8_t>();
+ controlVal.gate = val.gate;
+ //Change the gate value in the timer.
+ if (!val.gate)
+ warn("The gate bit of the pc speaker isn't implemented and "
+ "is always on.\n");
+ //This would control whether the timer output is hooked up to a physical
+ //speaker. Since M5 can't make noise, it's value doesn't actually do
+ //anything.
+ controlVal.speaker = val.speaker;
+ DPRINTF(PcSpeaker, "Writing to speaker device: gate %s, speaker %s.\n",
+ controlVal.gate ? "on" : "off", controlVal.speaker ? "on" : "off");
+ pkt->makeAtomicResponse();
+ return latency;
+}
+
+X86ISA::Speaker *
+PcSpeakerParams::create()
+{
+ return new X86ISA::Speaker(this);
+}
diff --git a/src/arch/arm/syscallreturn.hh b/src/dev/x86/speaker.hh
index ad46c2232..6778dcb28 100644
--- a/src/arch/arm/syscallreturn.hh
+++ b/src/dev/x86/speaker.hh
@@ -1,6 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * Copyright (c) 2007-2008 The Florida State University
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,31 +26,54 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Gabe Black
- * Korey Sewell
- * Stephen Hines
*/
-#ifndef __ARCH_ARM_SYSCALLRETURN_HH__
-#define __ARCH_ARM_SYSCALLRETURN_HH__
+#ifndef __DEV_X86_SPEAKER_HH__
+#define __DEV_X86_SPEAKER_HH__
-#include "sim/syscallreturn.hh"
-#include "cpu/thread_context.hh"
+#include "base/bitunion.hh"
+#include "params/PcSpeaker.hh"
-namespace ArmISA
+namespace X86ISA
{
- static inline void setSyscallReturn(SyscallReturn return_value,
- ThreadContext *tc)
+
+class I8254;
+
+class Speaker : public BasicPioDevice
+{
+ protected:
+ Tick latency;
+
+ BitUnion8(SpeakerControl)
+ Bitfield<0> gate;
+ Bitfield<1> speaker;
+ Bitfield<5> timer;
+ EndBitUnion(SpeakerControl)
+
+ SpeakerControl controlVal;
+
+ I8254 * timer;
+
+ public:
+ typedef PcSpeakerParams Params;
+
+ const Params *
+ params() const
+ {
+ return dynamic_cast<const Params *>(_params);
+ }
+
+ Speaker(Params *p) : BasicPioDevice(p),
+ latency(p->pio_latency), controlVal(0), timer(p->i8254)
{
- if (return_value.successful()) {
- // no error
- //regs->setIntReg(SyscallSuccessReg, 0);
- tc->setIntReg(ReturnValueReg, return_value.value());
- } else {
- // got an error, return details
- //regs->setIntReg(SyscallSuccessReg, (IntReg) -1);
- tc->setIntReg(ReturnValueReg, return_value.value());
- }
+ pioSize = 1;
}
-}
-#endif
+ Tick read(PacketPtr pkt);
+
+ Tick write(PacketPtr pkt);
+};
+
+}; // namespace X86ISA
+
+#endif //__DEV_X86_SPEAKER_HH__
diff --git a/src/kern/SConscript b/src/kern/SConscript
index 509e6b3f7..fc682aee0 100644
--- a/src/kern/SConscript
+++ b/src/kern/SConscript
@@ -40,11 +40,13 @@ if env['FULL_SYSTEM']:
Source('linux/events.cc')
Source('linux/linux_syscalls.cc')
Source('linux/printk.cc')
-
+
if env['TARGET_ISA'] == 'alpha':
Source('tru64/dump_mbuf.cc')
Source('tru64/printf.cc')
Source('tru64/tru64_events.cc')
Source('tru64/tru64_syscalls.cc')
TraceFlag('BADADDR')
-
+else:
+ Source('linux/linux.cc')
+ Source('operatingsystem.cc')
diff --git a/src/kern/kernel_stats.hh b/src/kern/kernel_stats.hh
index 66248c9c8..85a47ec00 100644
--- a/src/kern/kernel_stats.hh
+++ b/src/kern/kernel_stats.hh
@@ -51,17 +51,17 @@ class Statistics : public Serializable
std::string myname;
protected:
- Stats::Scalar<> _arm;
- Stats::Scalar<> _quiesce;
- Stats::Scalar<> _hwrei;
+ Stats::Scalar _arm;
+ Stats::Scalar _quiesce;
+ Stats::Scalar _hwrei;
- Stats::Vector<> _iplCount;
- Stats::Vector<> _iplGood;
- Stats::Vector<> _iplTicks;
+ Stats::Vector _iplCount;
+ Stats::Vector _iplGood;
+ Stats::Vector _iplTicks;
Stats::Formula _iplUsed;
- Stats::Vector<> _syscall;
-// Stats::Vector<> _faults;
+ Stats::Vector _syscall;
+// Stats::Vector _faults;
private:
int iplLast;
diff --git a/src/arch/alpha/syscallreturn.hh b/src/kern/linux/linux.cc
index 47b4ac8c7..b14e3c709 100644
--- a/src/arch/alpha/syscallreturn.hh
+++ b/src/kern/linux/linux.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2009 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,34 +25,41 @@
* (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
- * Gabe Black
+ * Authors: Ali Saidi
*/
-#ifndef __ARCH_ALPHA_SYSCALLRETURN_HH__
-#define __ARCH_ALPHA_SYSCALLRETURN_HH__
+#include <string>
#include "cpu/thread_context.hh"
-#include "sim/syscallreturn.hh"
+#include "kern/linux/linux.hh"
+#include "sim/process.hh"
+#include "sim/system.hh"
-namespace AlphaISA
+int
+Linux::openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc)
{
- static inline void setSyscallReturn(SyscallReturn return_value,
- ThreadContext * tc)
- {
- // 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
- tc->setIntReg(SyscallSuccessReg, 0);
- tc->setIntReg(ReturnValueReg, return_value.value());
- } else {
- // got an error, return details
- tc->setIntReg(SyscallSuccessReg, (IntReg)-1);
- tc->setIntReg(ReturnValueReg, -return_value.value());
- }
+ DPRINTF(SyscallVerbose, "Opening special file: %s\n", path.c_str());
+ if (path.compare(0, 13, "/proc/meminfo") == 0) {
+ std::string data = Linux::procMeminfo(process, tc);
+ FILE *f = tmpfile();
+ int fd = fileno(f);
+ int ret M5_VAR_USED = fwrite(data.c_str(), 1, data.size(), f);
+ assert(ret == data.size());
+ rewind(f);
+ return fd;
}
+
+ warn("Attempting to open special file: %s. Ignorning. Simulation may"
+ " take un-expected code path or be non-deterministic until proper"
+ " handling is implemented.\n", path.c_str());
+ return -1;
+}
+
+std::string
+Linux::procMeminfo(LiveProcess *process, ThreadContext *tc)
+{
+ return csprintf("MemTotal:%12d kB\nMemFree: %12d kB\n",
+ process->system->memSize() >> 10,
+ process->system->freeMemSize() >> 10);
}
-#endif
diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh
index 6e0b37d91..ad35fa726 100644
--- a/src/kern/linux/linux.hh
+++ b/src/kern/linux/linux.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2004-2009 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,9 +39,13 @@ class Linux {};
#else //!FULL_SYSTEM
#include <inttypes.h>
+#include <string>
#include "kern/operatingsystem.hh"
+class ThreadContext;
+class LiveProcess;
+
///
/// This class encapsulates the types, structures, constants,
/// functions, and syscall-number mappings specific to the Alpha Linux
@@ -65,46 +69,46 @@ class Linux : public OperatingSystem
/// gets #defined to something else on some systems. This type
/// can be specialized by architecture specific "Linux" classes
typedef struct {
- 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
+ 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
} tgt_stat;
// same for stat64
typedef struct {
- 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 st_atimeX;
- uint64_t st_atime_nsec;
- uint64_t st_mtimeX;
- uint64_t st_mtime_nsec;
- uint64_t st_ctimeX;
- uint64_t st_ctime_nsec;
- int64_t ___unused[3];
+ 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 st_atimeX;
+ uint64_t st_atime_nsec;
+ uint64_t st_mtimeX;
+ uint64_t st_mtime_nsec;
+ uint64_t st_ctimeX;
+ uint64_t st_ctime_nsec;
+ int64_t ___unused[3];
} tgt_stat64;
/// Length of strings in struct utsname (plus 1 for null char).
@@ -112,23 +116,23 @@ class Linux : public OperatingSystem
/// 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.
+ 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
+ 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
+ int64_t tv_sec; //!< seconds
+ int64_t tv_usec; //!< microseconds
};
// For writev/readv
@@ -140,24 +144,27 @@ class Linux : public OperatingSystem
/// 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 "
+ 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 "
};
+ static int openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc);
+ static std::string procMeminfo(LiveProcess *process, ThreadContext *tc);
+
}; // class Linux
diff --git a/src/kern/operatingsystem.cc b/src/kern/operatingsystem.cc
new file mode 100644
index 000000000..8951b8193
--- /dev/null
+++ b/src/kern/operatingsystem.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2009 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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 "kern/operatingsystem.hh"
+#include "base/misc.hh"
+
+int
+OperatingSystem::openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc)
+{
+ warn("Attempting to open special file: %s. Ignorning. Simulation may"
+ " take un-expected code path or be non-deterministic until proper"
+ " handling is implemented.\n", path.c_str());
+ return -1;
+}
+
+
diff --git a/src/kern/operatingsystem.hh b/src/kern/operatingsystem.hh
index 99358ae03..712b97c35 100644
--- a/src/kern/operatingsystem.hh
+++ b/src/kern/operatingsystem.hh
@@ -40,12 +40,16 @@
class OperatingSystem {};
#else //!FULL_SYSTEM
+#include <string>
+
+class LiveProcess;
+class ThreadContext;
/// 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.
+ int tgtFlag; //!< Target system flag value.
+ int hostFlag; //!< Corresponding host system flag value.
};
@@ -71,23 +75,23 @@ class OperatingSystem {
/// Interface struct for uname().
typedef struct {
- 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.
+ 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.
} utsname;
/// Limit struct for getrlimit/setrlimit.
typedef struct {
- uint64_t rlim_cur; //!< soft limit
- uint64_t rlim_max; //!< hard limit
+ uint64_t rlim_cur; //!< soft limit
+ uint64_t rlim_max; //!< hard limit
} rlimit;
/// For gettimeofday().
typedef struct {
- int64_t tv_sec; //!< seconds
- int64_t tv_usec; //!< microseconds
+ int64_t tv_sec; //!< seconds
+ int64_t tv_usec; //!< microseconds
} timeval;
// For writev/readv
@@ -99,24 +103,26 @@ class OperatingSystem {
/// For getrusage().
typedef struct {
- timeval ru_utime; //!< user time used
- 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 "
+ timeval ru_utime; //!< user time used
+ 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 "
} rusage;
+ static int openSpecialFile(std::string path, LiveProcess *process, ThreadContext *tc);
+
}; // class OperatingSystem
diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh
index ed574fdbf..a55ce2c80 100644
--- a/src/kern/solaris/solaris.hh
+++ b/src/kern/solaris/solaris.hh
@@ -76,39 +76,39 @@ class Solaris : public OperatingSystem
/// Stat buffer. Note that we can't call it 'stat' since that
/// gets #defined to something else on some systems.
typedef struct {
- 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
+ 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
int64_t st_atimeX, st_mtimeX, st_ctimeX;
- int32_t st_blksize; //!< optimal I/O block size
- int64_t st_blocks; //!< number of blocks allocated
+ int32_t st_blksize; //!< optimal I/O block size
+ int64_t st_blocks; //!< number of blocks allocated
char st_fstype[16];
} tgt_stat;
// same for stat64
typedef struct {
- 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
+ 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
int64_t st_atimeX, st_mtimeX, st_ctimeX;
- int32_t st_blksize; //!< optimal I/O block size
- int64_t st_blocks; //!< number of blocks allocated
+ int32_t st_blksize; //!< optimal I/O block size
+ int64_t st_blocks; //!< number of blocks allocated
char st_fstype[16];
} tgt_stat64;
@@ -117,11 +117,11 @@ class Solaris : public OperatingSystem
/// Interface struct for uname().
typedef 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.
+ 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.
} utsname;
}; // class Solaris
diff --git a/src/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh
index cb5a84a7e..78b5ead7a 100644
--- a/src/kern/tru64/mbuf.hh
+++ b/src/kern/tru64/mbuf.hh
@@ -37,63 +37,63 @@
namespace tru64 {
struct m_hdr {
- Addr mh_next; // 0x00
- Addr mh_nextpkt; // 0x08
- Addr mh_data; // 0x10
- int32_t mh_len; // 0x18
- int32_t mh_type; // 0x1C
- int32_t mh_flags; // 0x20
- int32_t mh_pad0; // 0x24
- Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40
+ Addr mh_next; // 0x00
+ Addr mh_nextpkt; // 0x08
+ Addr mh_data; // 0x10
+ int32_t mh_len; // 0x18
+ int32_t mh_type; // 0x1C
+ int32_t mh_flags; // 0x20
+ int32_t mh_pad0; // 0x24
+ Addr mh_foo[4]; // 0x28, 0x30, 0x38, 0x40
};
-struct pkthdr {
- int32_t len;
- int32_t protocolSum;
- Addr rcvif;
+struct pkthdr {
+ int32_t len;
+ int32_t protocolSum;
+ Addr rcvif;
};
struct m_ext {
- Addr ext_buf; // 0x00
- Addr ext_free; // 0x08
- uint32_t ext_size; // 0x10
- uint32_t ext_pad0; // 0x14
- Addr ext_arg; // 0x18
- struct ext_refq {
- Addr forw, back; // 0x20, 0x28
+ Addr ext_buf; // 0x00
+ Addr ext_free; // 0x08
+ uint32_t ext_size; // 0x10
+ uint32_t ext_pad0; // 0x14
+ Addr ext_arg; // 0x18
+ struct ext_refq {
+ Addr forw, back; // 0x20, 0x28
} ext_ref;
- Addr uiomove_f; // 0x30
- int32_t protocolSum; // 0x38
- int32_t bytesSummed; // 0x3C
- Addr checksum; // 0x40
+ Addr uiomove_f; // 0x30
+ int32_t protocolSum; // 0x38
+ int32_t bytesSummed; // 0x3C
+ Addr checksum; // 0x40
};
struct mbuf {
- struct m_hdr m_hdr;
+ struct m_hdr m_hdr;
union {
struct {
- struct pkthdr MH_pkthdr;
+ struct pkthdr MH_pkthdr;
union {
- struct m_ext MH_ext;
- char MH_databuf[1];
+ struct m_ext MH_ext;
+ char MH_databuf[1];
} MH_dat;
} MH;
- char M_databuf[1];
+ char M_databuf[1];
} M_dat;
};
#define m_attr m_hdr.mh_attr
-#define m_next m_hdr.mh_next
-#define m_len m_hdr.mh_len
-#define m_data m_hdr.mh_data
-#define m_type m_hdr.mh_type
-#define m_flags m_hdr.mh_flags
-#define m_nextpkt m_hdr.mh_nextpkt
-#define m_act m_nextpkt
-#define m_pkthdr M_dat.MH.MH_pkthdr
-#define m_ext M_dat.MH.MH_dat.MH_ext
-#define m_pktdat M_dat.MH.MH_dat.MH_databuf
-#define m_dat M_dat.M_databuf
+#define m_next m_hdr.mh_next
+#define m_len m_hdr.mh_len
+#define m_data m_hdr.mh_data
+#define m_type m_hdr.mh_type
+#define m_flags m_hdr.mh_flags
+#define m_nextpkt m_hdr.mh_nextpkt
+#define m_act m_nextpkt
+#define m_pkthdr M_dat.MH.MH_pkthdr
+#define m_ext M_dat.MH.MH_dat.MH_ext
+#define m_pktdat M_dat.MH.MH_dat.MH_databuf
+#define m_dat M_dat.M_databuf
}
diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh
index 70fb4d688..b1af4ec0e 100644
--- a/src/kern/tru64/tru64.hh
+++ b/src/kern/tru64/tru64.hh
@@ -52,7 +52,7 @@ class Tru64 {};
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <string.h> // for memset()
+#include <string.h> // for memset()
#include <unistd.h>
#include "cpu/base.hh"
@@ -102,7 +102,7 @@ class Tru64 : public OperatingSystem
int32_t f_retired5;
int32_t f_retired6;
int32_t f_retired7;
- fsid_t f_fsid;
+ fsid_t f_fsid;
int32_t f_spare[9];
char f_retired8[90];
char f_retired9[90];
@@ -141,10 +141,10 @@ class Tru64 : public OperatingSystem
/// 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
+ 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
};
@@ -162,106 +162,106 @@ class Tru64 : public OperatingSystem
/// Limit struct for getrlimit/setrlimit.
struct rlimit {
- uint64_t rlim_cur; //!< soft limit
- uint64_t rlim_max; //!< hard limit
+ 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
+ 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
+ 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 "
+ 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
+ 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
+ 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.
+ 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
+ Addr attr; //!< allocation policy
+ uint64_t reserved; //!< reserved
};
/// Return values for nxm calls.
@@ -271,17 +271,17 @@ class Tru64 : public OperatingSystem
};
/// For nxm_task_init.
- static const int NXM_TASK_INIT_VP = 2; //!< initial thread is VP
+ 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
+ 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.
@@ -316,9 +316,9 @@ class Tru64 : public OperatingSystem
// the kernel but are never context-switched by the library.
int nxm_ssig; //!< scheduler's synchronous signals
- int reserved1; //!< reserved1
+ int reserved1; //!< reserved1
int64_t nxm_active; //!< scheduler active
- int64_t reserved2; //!< reserved2
+ int64_t reserved2; //!< reserved2
};
struct nxm_sched_state {
@@ -328,14 +328,14 @@ class Tru64 : public OperatingSystem
int nxm_set_quantum; //!< quantum reset value
int nxm_sysevent; //!< syscall state
// struct nxm_upcall *
- Addr nxm_uc_ret; //!< stack ptr of null thread
+ 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
+ int64_t pad[2]; //!< pad
};
/// nxm_shared.
@@ -343,7 +343,7 @@ class Tru64 : public OperatingSystem
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
+ unsigned short pad1; //!< pad1
int64_t space[2]; //!< future growth
struct nxm_sched_state nxm_ss[1]; //!< array of shared areas
};
@@ -368,29 +368,29 @@ class Tru64 : public OperatingSystem
/// For nxm_thread_create.
enum nxm_thread_type {
- NXM_TYPE_SCS = 0,
- NXM_TYPE_VP = 1,
- NXM_TYPE_MANAGER = 2
+ 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
+ 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
+ Addr pthid; //!< pthid
+ sigset_t sigmask; //!< sigmask
/// Initial register values.
struct {
- uint64_t pc; //!< pc
- uint64_t sp; //!< sp
- uint64_t a0; //!< a0
+ uint64_t pc; //!< pc
+ uint64_t sp; //!< sp
+ uint64_t a0; //!< a0
} registers;
- uint64_t pad2[2]; //!< pad2
+ uint64_t pad2[2]; //!< pad2
};
/// Helper function to convert a host statfs buffer to a target statfs
@@ -437,10 +437,10 @@ class Tru64 : public OperatingSystem
#ifdef __CYGWIN__
panic("getdirent not implemented on cygwin!");
#else
- int fd = process->sim_fd(tc->getSyscallArg(0));
- Addr tgt_buf = tc->getSyscallArg(1);
- int tgt_nbytes = tc->getSyscallArg(2);
- Addr tgt_basep = tc->getSyscallArg(3);
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
+ Addr tgt_buf = process->getSyscallArg(tc, 1);
+ int tgt_nbytes = process->getSyscallArg(tc, 2);
+ Addr tgt_basep = process->getSyscallArg(tc, 3);
char * const host_buf = new char[tgt_nbytes];
@@ -496,7 +496,7 @@ class Tru64 : public OperatingSystem
using namespace TheISA;
using TheISA::RegFile;
- TypedBufferArg<Tru64::sigcontext> sc(tc->getSyscallArg(0));
+ TypedBufferArg<Tru64::sigcontext> sc(process->getSyscallArg(tc, 0));
sc.copyIn(tc->getMemPort());
@@ -528,7 +528,7 @@ class Tru64 : public OperatingSystem
{
using namespace TheISA;
- TypedBufferArg<Tru64::vm_stack> argp(tc->getSyscallArg(0));
+ TypedBufferArg<Tru64::vm_stack> argp(process->getSyscallArg(tc, 0));
argp.copyIn(tc->getMemPort());
@@ -576,8 +576,9 @@ class Tru64 : public OperatingSystem
using namespace std;
using namespace TheISA;
- TypedBufferArg<Tru64::nxm_task_attr> attrp(tc->getSyscallArg(0));
- TypedBufferArg<Addr> configptr_ptr(tc->getSyscallArg(1));
+ TypedBufferArg<Tru64::nxm_task_attr>
+ attrp(process->getSyscallArg(tc, 0));
+ TypedBufferArg<Addr> configptr_ptr(process->getSyscallArg(tc, 1));
attrp.copyIn(tc->getMemPort());
@@ -605,7 +606,7 @@ class Tru64 : public OperatingSystem
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
+ cur_addr = 0x14000; // bump up addr for alignment
Addr rad_state_addr = cur_addr;
int rad_state_size =
(sizeof(Tru64::nxm_shared)
@@ -616,7 +617,7 @@ class Tru64 : public OperatingSystem
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_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);
@@ -683,14 +684,14 @@ class Tru64 : public OperatingSystem
/// Initialize thread context.
static void
- init_thread_context(ThreadContext *tc,
+ init_thread_context(LiveProcess *process, ThreadContext *tc,
Tru64::nxm_thread_attr *attrp, uint64_t uniq_val)
{
using namespace TheISA;
tc->clearArchRegs();
- tc->setIntReg(TheISA::ArgumentReg[0], gtoh(attrp->registers.a0));
+ process->setSyscallArg(tc, 0, gtoh(attrp->registers.a0));
tc->setIntReg(27/*t12*/, gtoh(attrp->registers.pc));
tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp));
tc->setMiscRegNoEffect(AlphaISA::MISCREG_UNIQ, uniq_val);
@@ -709,9 +710,10 @@ class Tru64 : public OperatingSystem
using namespace std;
using namespace TheISA;
- TypedBufferArg<Tru64::nxm_thread_attr> attrp(tc->getSyscallArg(0));
- TypedBufferArg<uint64_t> kidp(tc->getSyscallArg(1));
- int thread_index = tc->getSyscallArg(2);
+ TypedBufferArg<Tru64::nxm_thread_attr>
+ attrp(process->getSyscallArg(tc, 0));
+ TypedBufferArg<uint64_t> kidp(process->getSyscallArg(tc, 1));
+ int thread_index = process->getSyscallArg(tc, 2);
// get attribute args
attrp.copyIn(tc->getMemPort());
@@ -723,7 +725,7 @@ class Tru64 : public OperatingSystem
abort();
}
- if (thread_index < 0 | thread_index > process->numCpus()) {
+ if (thread_index < 0 || thread_index > process->numCpus()) {
cerr << "nxm_thread_create: bad thread index " << thread_index
<< endl;
abort();
@@ -789,21 +791,18 @@ class Tru64 : public OperatingSystem
slot_state.copyOut(tc->getMemPort());
// Find a free simulator thread context.
- for (int i = 0; i < process->numCpus(); ++i) {
- ThreadContext *tc = process->threadContexts[i];
-
- if (tc->status() == ThreadContext::Unallocated) {
- // inactive context... grab it
- init_thread_context(tc, 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(tc->getMemPort());
-
- return 0;
- }
+ ThreadContext *tc = process->findFreeContext();
+ if (tc) {
+ // inactive context... grab it
+ init_thread_context(process, tc, 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(tc->getMemPort());
+
+ return 0;
}
// fell out of loop... no available inactive context
@@ -833,11 +832,11 @@ class Tru64 : public OperatingSystem
{
using namespace std;
- uint64_t tid = tc->getSyscallArg(0);
- uint64_t secs = tc->getSyscallArg(1);
- uint64_t flags = tc->getSyscallArg(2);
- uint64_t action = tc->getSyscallArg(3);
- uint64_t usecs = tc->getSyscallArg(4);
+ uint64_t tid = process->getSyscallArg(tc, 0);
+ uint64_t secs = process->getSyscallArg(tc, 1);
+ uint64_t flags = process->getSyscallArg(tc, 2);
+ uint64_t action = process->getSyscallArg(tc, 3);
+ uint64_t usecs = process->getSyscallArg(tc, 4);
cout << tc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " "
<< secs << " " << flags << " " << action << " " << usecs << endl;
@@ -852,11 +851,11 @@ class Tru64 : public OperatingSystem
{
using namespace std;
- Addr uaddr = tc->getSyscallArg(0);
- uint64_t val = tc->getSyscallArg(1);
- uint64_t secs = tc->getSyscallArg(2);
- uint64_t usecs = tc->getSyscallArg(3);
- uint64_t flags = tc->getSyscallArg(4);
+ Addr uaddr = process->getSyscallArg(tc, 0);
+ uint64_t val = process->getSyscallArg(tc, 1);
+ uint64_t secs = process->getSyscallArg(tc, 2);
+ uint64_t usecs = process->getSyscallArg(tc, 3);
+ uint64_t flags = process->getSyscallArg(tc, 4);
BaseCPU *cpu = tc->getCpuPtr();
@@ -875,7 +874,7 @@ class Tru64 : public OperatingSystem
{
using namespace std;
- Addr uaddr = tc->getSyscallArg(0);
+ Addr uaddr = process->getSyscallArg(tc, 0);
cout << tc->getCpuPtr()->name() << ": nxm_unblock "
<< hex << uaddr << dec << endl;
@@ -976,7 +975,7 @@ class Tru64 : public OperatingSystem
m5_mutex_lockFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- Addr uaddr = tc->getSyscallArg(0);
+ Addr uaddr = process->getSyscallArg(tc, 0);
m5_lock_mutex(uaddr, process, tc);
@@ -993,7 +992,7 @@ class Tru64 : public OperatingSystem
{
using namespace TheISA;
- Addr uaddr = tc->getSyscallArg(0);
+ Addr uaddr = process->getSyscallArg(tc, 0);
TypedBufferArg<uint64_t> lockp(uaddr);
lockp.copyIn(tc->getMemPort());
@@ -1013,7 +1012,7 @@ class Tru64 : public OperatingSystem
m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- Addr uaddr = tc->getSyscallArg(0);
+ Addr uaddr = process->getSyscallArg(tc, 0);
m5_unlock_mutex(uaddr, process, tc);
@@ -1025,7 +1024,7 @@ class Tru64 : public OperatingSystem
m5_cond_signalFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- Addr cond_addr = tc->getSyscallArg(0);
+ Addr cond_addr = process->getSyscallArg(tc, 0);
// Wake up one process waiting on the condition variable.
activate_waiting_context(cond_addr, process);
@@ -1038,7 +1037,7 @@ class Tru64 : public OperatingSystem
m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- Addr cond_addr = tc->getSyscallArg(0);
+ Addr cond_addr = process->getSyscallArg(tc, 0);
activate_waiting_context(cond_addr, process, true);
@@ -1052,8 +1051,8 @@ class Tru64 : public OperatingSystem
{
using namespace TheISA;
- Addr cond_addr = tc->getSyscallArg(0);
- Addr lock_addr = tc->getSyscallArg(1);
+ Addr cond_addr = process->getSyscallArg(tc, 0);
+ Addr lock_addr = process->getSyscallArg(tc, 1);
TypedBufferArg<uint64_t> condp(cond_addr);
TypedBufferArg<uint64_t> lockp(lock_addr);
@@ -1085,10 +1084,10 @@ class Tru64 : public OperatingSystem
indirectSyscallFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int new_callnum = tc->getSyscallArg(0);
+ int new_callnum = process->getSyscallArg(tc, 0);
for (int i = 0; i < 5; ++i)
- tc->setSyscallArg(i, tc->getSyscallArg(i+1));
+ process->setSyscallArg(tc, i, process->getSyscallArg(tc, i+1));
SyscallDesc *new_desc = process->getDesc(new_callnum);
@@ -1111,37 +1110,37 @@ class Tru64_F64 : public Tru64
/// 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
+ 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
};
typedef F64_stat tgt_stat;
diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc
index c798c3ced..4867df559 100644
--- a/src/kern/tru64/tru64_events.cc
+++ b/src/kern/tru64/tru64_events.cc
@@ -51,7 +51,7 @@ BadAddrEvent::process(ThreadContext *tc)
// annotation for vmunix::badaddr in:
// simos/simulation/apps/tcl/osf/tlaser.tcl
- uint64_t a0 = tc->readIntReg(ArgumentReg[0]);
+ uint64_t a0 = tc->readIntReg(16);
AddrRangeList resp;
bool snoop;
@@ -59,20 +59,19 @@ BadAddrEvent::process(ThreadContext *tc)
bool found = false;
tc->getPhysPort()->getPeerAddressRanges(resp, snoop);
- for(iter = resp.begin(); iter != resp.end(); iter++)
- {
- if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask))
+ for (iter = resp.begin(); iter != resp.end(); iter++) {
+ if (*iter == (K0Seg2Phys(a0) & PAddrImplMask))
found = true;
}
- if (!TheISA::IsK0Seg(a0) || found ) {
+ if (!IsK0Seg(a0) || found ) {
DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
tc->setIntReg(ReturnValueReg, 0x1);
SkipFuncEvent::process(tc);
- }
- else
+ } else {
DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
+ }
}
void
diff --git a/src/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc
index 8051b9efb..602271b36 100644
--- a/src/kern/tru64/tru64_syscalls.cc
+++ b/src/kern/tru64/tru64_syscalls.cc
@@ -33,394 +33,394 @@
namespace {
const char *
standard_strings[SystemCalls<Tru64>::StandardNumber] = {
- "syscall", // 0
- "exit", // 1
- "fork", // 2
- "read", // 3
- "write", // 4
- "old_open", // 5
- "close", // 6
- "wait4", // 7
- "old_creat", // 8
- "link", // 9
-
- "unlink", // 10
- "execv", // 11
- "chdir", // 12
- "fchdir", // 13
- "mknod", // 14
- "chmod", // 15
- "chown", // 16
- "obreak", // 17
- "pre_F64_getfsstat", // 18
- "lseek", // 19
-
- "getpid", // 20
- "mount", // 21
- "unmount", // 22
- "setuid", // 23
- "getuid", // 24
- "exec_with_loader", // 25
- "ptrace", // 26
- "recvmsg", // 27
- "sendmsg", // 28
- "recvfrom", // 29
-
- "accept", // 30
- "getpeername", // 31
- "getsockname", // 32
- "access", // 33
- "chflags", // 34
- "fchflags", // 35
- "sync", // 36
- "kill", // 37
- "old_stat", // 38
- "setpgid", // 39
-
- "old_lstat", // 40
- "dup", // 41
- "pipe", // 42
- "set_program_attributes", // 43
- "profil", // 44
- "open", // 45
- "obsolete_osigaction", // 46
- "getgid", // 47
- "sigprocmask", // 48
- "getlogin", // 49
-
- "setlogin", // 50
- "acct", // 51
- "sigpending", // 52
- "classcntl", // 53
- "ioctl", // 54
- "reboot", // 55
- "revoke", // 56
- "symlink", // 57
- "readlink", // 58
- "execve", // 59
-
- "umask", // 60
- "chroot", // 61
- "old_fstat", // 62
- "getpgrp", // 63
- "getpagesize", // 64
- "mremap", // 65
- "vfork", // 66
- "pre_F64_stat", // 67
- "pre_F64_lstat", // 68
- "sbrk", // 69
-
- "sstk", // 70
- "mmap", // 71
- "ovadvise", // 72
- "munmap", // 73
- "mprotect", // 74
- "madvise", // 75
- "old_vhangup", // 76
- "kmodcall", // 77
- "mincore", // 78
- "getgroups", // 79
-
- "setgroups", // 80
- "old_getpgrp", // 81
- "setpgrp", // 82
- "setitimer", // 83
- "old_wait", // 84
- "table", // 85
- "getitimer", // 86
- "gethostname", // 87
- "sethostname", // 88
- "getdtablesize", // 89
-
- "dup2", // 90
- "pre_F64_fstat", // 91
- "fcntl", // 92
- "select", // 93
- "poll", // 94
- "fsync", // 95
- "setpriority", // 96
- "socket", // 97
- "connect", // 98
- "old_accept", // 99
-
- "getpriority", // 100
- "old_send", // 101
- "old_recv", // 102
- "sigreturn", // 103
- "bind", // 104
- "setsockopt", // 105
- "listen", // 106
- "plock", // 107
- "old_sigvec", // 108
- "old_sigblock", // 109
-
- "old_sigsetmask", // 110
- "sigsuspend", // 111
- "sigstack", // 112
- "old_recvmsg", // 113
- "old_sendmsg", // 114
- "obsolete_vtrcae", // 115
- "gettimeofday", // 116
- "getrusage", // 117
- "getsockopt", // 118
- "numa_syscalls", // 119
-
- "readv", // 120
- "writev", // 121
- "settimeofday", // 122
- "fchown", // 123
- "fchmod", // 124
- "old_recvfrom", // 125
- "setreuid", // 126
- "setregid", // 127
- "rename", // 128
- "truncate", // 129
-
- "ftruncate", // 130
- "flock", // 131
- "setgid", // 132
- "sendto", // 133
- "shutdown", // 134
- "socketpair", // 135
- "mkdir", // 136
- "rmdir", // 137
- "utimes", // 138
- "obsolete_42_sigreturn", // 139
-
- "adjtime", // 140
- "old_getpeername", // 141
- "gethostid", // 142
- "sethostid", // 143
- "getrlimit", // 144
- "setrlimit", // 145
- "old_killpg", // 146
- "setsid", // 147
- "quotactl", // 148
- "oldquota", // 149
-
- "old_getsockname", // 150
- "pread", // 151
- "pwrite", // 152
- "pid_block", // 153
- "pid_unblock", // 154
- "signal_urti", // 155
- "sigaction", // 156
- "sigwaitprim", // 157
- "nfssvc", // 158
- "getdirentries", // 159
-
- "pre_F64_statfs", // 160
- "pre_F64_fstatfs", // 161
- 0, // 162
- "async_daemon", // 163
- "getfh", // 164
- "getdomainname", // 165
- "setdomainname", // 166
- 0, // 167
- 0, // 168
- "exportfs", // 169
-
- 0, // 170
- 0, // 171
- 0, // 172
- 0, // 173
- 0, // 174
- 0, // 175
- 0, // 176
- 0, // 177
- 0, // 178
- 0, // 179
-
- 0, // 180
- "alt_plock", // 181
- 0, // 182
- 0, // 183
- "getmnt", // 184
- 0, // 185
- 0, // 186
- "alt_sigpending", // 187
- "alt_setsid", // 188
- 0, // 189
-
- 0, // 190
- 0, // 191
- 0, // 192
- 0, // 193
- 0, // 194
- 0, // 195
- 0, // 196
- 0, // 197
- 0, // 198
- "swapon", // 199
-
- "msgctl", // 200
- "msgget", // 201
- "msgrcv", // 202
- "msgsnd", // 203
- "semctl", // 204
- "semget", // 205
- "semop", // 206
- "uname", // 207
- "lchown", // 208
- "shmat", // 209
-
- "shmctl", // 210
- "shmdt", // 211
- "shmget", // 212
- "mvalid", // 213
- "getaddressconf", // 214
- "msleep", // 215
- "mwakeup", // 216
- "msync", // 217
- "signal", // 218
- "utc_gettime", // 219
-
- "utc_adjtime", // 220
- 0, // 221
- "security", // 222
- "kloadcall", // 223
- "stat", // 224
- "lstat", // 225
- "fstat", // 226
- "statfs", // 227
- "fstatfs", // 228
- "getfsstat", // 229
-
- "gettimeofday64", // 230
- "settimeofday64", // 231
- 0, // 232
- "getpgid", // 233
- "getsid", // 234
- "sigaltstack", // 235
- "waitid", // 236
- "priocntlset", // 237
- "sigsendset", // 238
- "set_speculative", // 239
-
- "msfs_syscall", // 240
- "sysinfo", // 241
- "uadmin", // 242
- "fuser", // 243
- "proplist_syscall", // 244
- "ntp_adjtime", // 245
- "ntp_gettime", // 246
- "pathconf", // 247
- "fpathconf", // 248
- "sync2", // 249
-
- "uswitch", // 250
- "usleep_thread", // 251
- "audcntl", // 252
- "audgen", // 253
- "sysfs", // 254
- "subsys_info", // 255
- "getsysinfo", // 256
- "setsysinfo", // 257
- "afs_syscall", // 258
- "swapctl", // 259
-
- "memcntl", // 260
- "fdatasync", // 261
- "oflock", // 262
- "_F64_readv", // 263
- "_F64_writev", // 264
- "cdslxlate", // 265
- "sendfile", // 266
+ "syscall", // 0
+ "exit", // 1
+ "fork", // 2
+ "read", // 3
+ "write", // 4
+ "old_open", // 5
+ "close", // 6
+ "wait4", // 7
+ "old_creat", // 8
+ "link", // 9
+
+ "unlink", // 10
+ "execv", // 11
+ "chdir", // 12
+ "fchdir", // 13
+ "mknod", // 14
+ "chmod", // 15
+ "chown", // 16
+ "obreak", // 17
+ "pre_F64_getfsstat", // 18
+ "lseek", // 19
+
+ "getpid", // 20
+ "mount", // 21
+ "unmount", // 22
+ "setuid", // 23
+ "getuid", // 24
+ "exec_with_loader", // 25
+ "ptrace", // 26
+ "recvmsg", // 27
+ "sendmsg", // 28
+ "recvfrom", // 29
+
+ "accept", // 30
+ "getpeername", // 31
+ "getsockname", // 32
+ "access", // 33
+ "chflags", // 34
+ "fchflags", // 35
+ "sync", // 36
+ "kill", // 37
+ "old_stat", // 38
+ "setpgid", // 39
+
+ "old_lstat", // 40
+ "dup", // 41
+ "pipe", // 42
+ "set_program_attributes", // 43
+ "profil", // 44
+ "open", // 45
+ "obsolete_osigaction", // 46
+ "getgid", // 47
+ "sigprocmask", // 48
+ "getlogin", // 49
+
+ "setlogin", // 50
+ "acct", // 51
+ "sigpending", // 52
+ "classcntl", // 53
+ "ioctl", // 54
+ "reboot", // 55
+ "revoke", // 56
+ "symlink", // 57
+ "readlink", // 58
+ "execve", // 59
+
+ "umask", // 60
+ "chroot", // 61
+ "old_fstat", // 62
+ "getpgrp", // 63
+ "getpagesize", // 64
+ "mremap", // 65
+ "vfork", // 66
+ "pre_F64_stat", // 67
+ "pre_F64_lstat", // 68
+ "sbrk", // 69
+
+ "sstk", // 70
+ "mmap", // 71
+ "ovadvise", // 72
+ "munmap", // 73
+ "mprotect", // 74
+ "madvise", // 75
+ "old_vhangup", // 76
+ "kmodcall", // 77
+ "mincore", // 78
+ "getgroups", // 79
+
+ "setgroups", // 80
+ "old_getpgrp", // 81
+ "setpgrp", // 82
+ "setitimer", // 83
+ "old_wait", // 84
+ "table", // 85
+ "getitimer", // 86
+ "gethostname", // 87
+ "sethostname", // 88
+ "getdtablesize", // 89
+
+ "dup2", // 90
+ "pre_F64_fstat", // 91
+ "fcntl", // 92
+ "select", // 93
+ "poll", // 94
+ "fsync", // 95
+ "setpriority", // 96
+ "socket", // 97
+ "connect", // 98
+ "old_accept", // 99
+
+ "getpriority", // 100
+ "old_send", // 101
+ "old_recv", // 102
+ "sigreturn", // 103
+ "bind", // 104
+ "setsockopt", // 105
+ "listen", // 106
+ "plock", // 107
+ "old_sigvec", // 108
+ "old_sigblock", // 109
+
+ "old_sigsetmask", // 110
+ "sigsuspend", // 111
+ "sigstack", // 112
+ "old_recvmsg", // 113
+ "old_sendmsg", // 114
+ "obsolete_vtrcae", // 115
+ "gettimeofday", // 116
+ "getrusage", // 117
+ "getsockopt", // 118
+ "numa_syscalls", // 119
+
+ "readv", // 120
+ "writev", // 121
+ "settimeofday", // 122
+ "fchown", // 123
+ "fchmod", // 124
+ "old_recvfrom", // 125
+ "setreuid", // 126
+ "setregid", // 127
+ "rename", // 128
+ "truncate", // 129
+
+ "ftruncate", // 130
+ "flock", // 131
+ "setgid", // 132
+ "sendto", // 133
+ "shutdown", // 134
+ "socketpair", // 135
+ "mkdir", // 136
+ "rmdir", // 137
+ "utimes", // 138
+ "obsolete_42_sigreturn", // 139
+
+ "adjtime", // 140
+ "old_getpeername", // 141
+ "gethostid", // 142
+ "sethostid", // 143
+ "getrlimit", // 144
+ "setrlimit", // 145
+ "old_killpg", // 146
+ "setsid", // 147
+ "quotactl", // 148
+ "oldquota", // 149
+
+ "old_getsockname", // 150
+ "pread", // 151
+ "pwrite", // 152
+ "pid_block", // 153
+ "pid_unblock", // 154
+ "signal_urti", // 155
+ "sigaction", // 156
+ "sigwaitprim", // 157
+ "nfssvc", // 158
+ "getdirentries", // 159
+
+ "pre_F64_statfs", // 160
+ "pre_F64_fstatfs", // 161
+ 0, // 162
+ "async_daemon", // 163
+ "getfh", // 164
+ "getdomainname", // 165
+ "setdomainname", // 166
+ 0, // 167
+ 0, // 168
+ "exportfs", // 169
+
+ 0, // 170
+ 0, // 171
+ 0, // 172
+ 0, // 173
+ 0, // 174
+ 0, // 175
+ 0, // 176
+ 0, // 177
+ 0, // 178
+ 0, // 179
+
+ 0, // 180
+ "alt_plock", // 181
+ 0, // 182
+ 0, // 183
+ "getmnt", // 184
+ 0, // 185
+ 0, // 186
+ "alt_sigpending", // 187
+ "alt_setsid", // 188
+ 0, // 189
+
+ 0, // 190
+ 0, // 191
+ 0, // 192
+ 0, // 193
+ 0, // 194
+ 0, // 195
+ 0, // 196
+ 0, // 197
+ 0, // 198
+ "swapon", // 199
+
+ "msgctl", // 200
+ "msgget", // 201
+ "msgrcv", // 202
+ "msgsnd", // 203
+ "semctl", // 204
+ "semget", // 205
+ "semop", // 206
+ "uname", // 207
+ "lchown", // 208
+ "shmat", // 209
+
+ "shmctl", // 210
+ "shmdt", // 211
+ "shmget", // 212
+ "mvalid", // 213
+ "getaddressconf", // 214
+ "msleep", // 215
+ "mwakeup", // 216
+ "msync", // 217
+ "signal", // 218
+ "utc_gettime", // 219
+
+ "utc_adjtime", // 220
+ 0, // 221
+ "security", // 222
+ "kloadcall", // 223
+ "stat", // 224
+ "lstat", // 225
+ "fstat", // 226
+ "statfs", // 227
+ "fstatfs", // 228
+ "getfsstat", // 229
+
+ "gettimeofday64", // 230
+ "settimeofday64", // 231
+ 0, // 232
+ "getpgid", // 233
+ "getsid", // 234
+ "sigaltstack", // 235
+ "waitid", // 236
+ "priocntlset", // 237
+ "sigsendset", // 238
+ "set_speculative", // 239
+
+ "msfs_syscall", // 240
+ "sysinfo", // 241
+ "uadmin", // 242
+ "fuser", // 243
+ "proplist_syscall", // 244
+ "ntp_adjtime", // 245
+ "ntp_gettime", // 246
+ "pathconf", // 247
+ "fpathconf", // 248
+ "sync2", // 249
+
+ "uswitch", // 250
+ "usleep_thread", // 251
+ "audcntl", // 252
+ "audgen", // 253
+ "sysfs", // 254
+ "subsys_info", // 255
+ "getsysinfo", // 256
+ "setsysinfo", // 257
+ "afs_syscall", // 258
+ "swapctl", // 259
+
+ "memcntl", // 260
+ "fdatasync", // 261
+ "oflock", // 262
+ "_F64_readv", // 263
+ "_F64_writev", // 264
+ "cdslxlate", // 265
+ "sendfile", // 266
};
const char *
mach_strings[SystemCalls<Tru64>::MachNumber] = {
- 0, // 0
- 0, // 1
- 0, // 2
- 0, // 3
- 0, // 4
- 0, // 5
- 0, // 6
- 0, // 7
- 0, // 8
- 0, // 9
-
- "task_self", // 10
- "thread_reply", // 11
- "task_notify", // 12
- "thread_self", // 13
- 0, // 14
- 0, // 15
- 0, // 16
- 0, // 17
- 0, // 18
- 0, // 19
-
- "msg_send_trap", // 20
- "msg_receive_trap", // 21
- "msg_rpc_trap", // 22
- 0, // 23
- "nxm_block", // 24
- "nxm_unblock", // 25
- 0, // 26
- 0, // 27
- 0, // 28
- "nxm_thread_destroy", // 29
-
- "lw_wire", // 30
- "lw_unwire", // 31
- "nxm_thread_create", // 32
- "nxm_task_init", // 33
- 0, // 34
- "nxm_idle", // 35
- "nxm_wakeup_idle", // 36
- "nxm_set_pthid", // 37
- "nxm_thread_kill", // 38
- "nxm_thread_block", // 39
-
- "nxm_thread_wakeup", // 40
- "init_process", // 41
- "nxm_get_binding", // 42
- "map_fd", // 43
- "nxm_resched", // 44
- "nxm_set_cancel", // 45
- "nxm_set_binding", // 46
- "stack_create", // 47
- "nxm_get_state", // 48
- "nxm_thread_suspend", // 49
-
- "nxm_thread_resume", // 50
- "nxm_signal_check", // 51
- "htg_unix_syscall", // 52
- 0, // 53
- 0, // 54
- "host_self", // 55
- "host_priv_self", // 56
- 0, // 57
- 0, // 58
- "swtch_pri", // 59
-
- "swtch", // 60
- "thread_switch", // 61
- "semop_fast", // 62
- "nxm_pshared_init", // 63
- "nxm_pshared_block", // 64
- "nxm_pshared_unblock", // 65
- "nxm_pshared_destroy", // 66
- "nxm_swtch_pri", // 67
- "lw_syscall", // 68
- 0, // 69
-
- "mach_sctimes_0", // 70
- "mach_sctimes_1", // 71
- "mach_sctimes_2", // 72
- "mach_sctimes_3", // 73
- "mach_sctimes_4", // 74
- "mach_sctimes_5", // 75
- "mach_sctimes_6", // 76
- "mach_sctimes_7", // 77
- "mach_sctimes_8", // 78
- "mach_sctimes_9", // 79
-
- "mach_sctimes_10", // 80
- "mach_sctimes_11", // 81
- "mach_sctimes_port_alloc_dealloc", // 82
+ 0, // 0
+ 0, // 1
+ 0, // 2
+ 0, // 3
+ 0, // 4
+ 0, // 5
+ 0, // 6
+ 0, // 7
+ 0, // 8
+ 0, // 9
+
+ "task_self", // 10
+ "thread_reply", // 11
+ "task_notify", // 12
+ "thread_self", // 13
+ 0, // 14
+ 0, // 15
+ 0, // 16
+ 0, // 17
+ 0, // 18
+ 0, // 19
+
+ "msg_send_trap", // 20
+ "msg_receive_trap", // 21
+ "msg_rpc_trap", // 22
+ 0, // 23
+ "nxm_block", // 24
+ "nxm_unblock", // 25
+ 0, // 26
+ 0, // 27
+ 0, // 28
+ "nxm_thread_destroy", // 29
+
+ "lw_wire", // 30
+ "lw_unwire", // 31
+ "nxm_thread_create", // 32
+ "nxm_task_init", // 33
+ 0, // 34
+ "nxm_idle", // 35
+ "nxm_wakeup_idle", // 36
+ "nxm_set_pthid", // 37
+ "nxm_thread_kill", // 38
+ "nxm_thread_block", // 39
+
+ "nxm_thread_wakeup", // 40
+ "init_process", // 41
+ "nxm_get_binding", // 42
+ "map_fd", // 43
+ "nxm_resched", // 44
+ "nxm_set_cancel", // 45
+ "nxm_set_binding", // 46
+ "stack_create", // 47
+ "nxm_get_state", // 48
+ "nxm_thread_suspend", // 49
+
+ "nxm_thread_resume", // 50
+ "nxm_signal_check", // 51
+ "htg_unix_syscall", // 52
+ 0, // 53
+ 0, // 54
+ "host_self", // 55
+ "host_priv_self", // 56
+ 0, // 57
+ 0, // 58
+ "swtch_pri", // 59
+
+ "swtch", // 60
+ "thread_switch", // 61
+ "semop_fast", // 62
+ "nxm_pshared_init", // 63
+ "nxm_pshared_block", // 64
+ "nxm_pshared_unblock", // 65
+ "nxm_pshared_destroy", // 66
+ "nxm_swtch_pri", // 67
+ "lw_syscall", // 68
+ 0, // 69
+
+ "mach_sctimes_0", // 70
+ "mach_sctimes_1", // 71
+ "mach_sctimes_2", // 72
+ "mach_sctimes_3", // 73
+ "mach_sctimes_4", // 74
+ "mach_sctimes_5", // 75
+ "mach_sctimes_6", // 76
+ "mach_sctimes_7", // 77
+ "mach_sctimes_8", // 78
+ "mach_sctimes_9", // 79
+
+ "mach_sctimes_10", // 80
+ "mach_sctimes_11", // 81
+ "mach_sctimes_port_alloc_dealloc", // 82
};
}
diff --git a/src/mem/PhysicalMemory.py b/src/mem/PhysicalMemory.py
index 99bd27f2b..95cc73daa 100644
--- a/src/mem/PhysicalMemory.py
+++ b/src/mem/PhysicalMemory.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# Copyright (c) 2005-2008 The Regents of The University of Michigan
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -35,8 +35,10 @@ class PhysicalMemory(MemObject):
port = VectorPort("the access port")
range = Param.AddrRange(AddrRange('128MB'), "Device Address")
file = Param.String('', "memory mapped file")
- latency = Param.Latency('1t', "latency of an access")
+ latency = Param.Latency('30ns', "latency of an access")
+ latency_var = Param.Latency('0ns', "access variablity")
zero = Param.Bool(False, "zero initialize memory")
+ null = Param.Bool(False, "do not store data, always return zero")
class DRAMMemory(PhysicalMemory):
type = 'DRAMMemory'
diff --git a/src/mem/SConscript b/src/mem/SConscript
index b572f703c..0b0017f81 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -43,6 +43,7 @@ Source('packet.cc')
Source('physical.cc')
Source('port.cc')
Source('tport.cc')
+Source('mport.cc')
if env['FULL_SYSTEM']:
Source('vport.cc')
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index 3d3966491..cc9b83d3e 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -47,7 +47,7 @@ Bridge::BridgePort::BridgePort(const std::string &_name,
int _delay, int _nack_delay, int _req_limit,
int _resp_limit,
std::vector<Range<Addr> > filter_ranges)
- : Port(_name), bridge(_bridge), otherPort(_otherPort),
+ : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
outstandingResponses(0), queuedRequests(0), inRetry(false),
reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
@@ -89,7 +89,7 @@ void
Bridge::init()
{
// Make sure that both sides are connected to.
- if (portA.getPeer() == NULL || portB.getPeer() == NULL)
+ if (!portA.isConnected() || !portB.isConnected())
fatal("Both ports of bus bridge are not connected to a bus.\n");
if (portA.peerBlockSize() != portB.peerBlockSize())
@@ -130,7 +130,7 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
return true;
}
- if (pkt->needsResponse())
+ if (pkt->needsResponse()) {
if (respQueueFull()) {
DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
@@ -141,6 +141,7 @@ Bridge::BridgePort::recvTiming(PacketPtr pkt)
DPRINTF(BusBridge, "Request Needs response, reserving space\n");
++outstandingResponses;
}
+ }
otherPort->queueForSendTiming(pkt);
@@ -161,7 +162,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
// nothing on the list, add it and we're done
if (sendQueue.empty()) {
assert(!sendEvent.scheduled());
- sendEvent.schedule(readyTime);
+ schedule(sendEvent, readyTime);
sendQueue.push_back(buf);
return;
}
@@ -183,7 +184,7 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
while (i != end && !done) {
if (readyTime < (*i)->ready) {
if (i == begin)
- sendEvent.reschedule(readyTime);
+ reschedule(sendEvent, readyTime);
sendQueue.insert(i,buf);
done = true;
}
@@ -226,7 +227,7 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
// should already be an event scheduled for sending the head
// packet.
if (sendQueue.empty()) {
- sendEvent.schedule(readyTime);
+ schedule(sendEvent, readyTime);
}
sendQueue.push_back(buf);
}
@@ -280,7 +281,7 @@ Bridge::BridgePort::trySend()
if (!sendQueue.empty()) {
buf = sendQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
- sendEvent.schedule(std::max(buf->ready, curTick + 1));
+ schedule(sendEvent, std::max(buf->ready, curTick + 1));
}
} else {
DPRINTF(BusBridge, " unsuccessful\n");
@@ -301,7 +302,7 @@ Bridge::BridgePort::recvRetry()
if (nextReady <= curTick)
trySend();
else
- sendEvent.schedule(nextReady);
+ schedule(sendEvent, nextReady);
}
/** Function called by the port when the bus is receiving a Atomic
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
index 1331a45f9..40f033811 100644
--- a/src/mem/bridge.hh
+++ b/src/mem/bridge.hh
@@ -42,6 +42,7 @@
#include <inttypes.h>
#include <queue>
+#include "base/fast_alloc.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
@@ -73,7 +74,7 @@ class Bridge : public MemObject
/** Pass ranges from one side of the bridge to the other? */
std::vector<Range<Addr> > filterRanges;
- class PacketBuffer : public Packet::SenderState {
+ class PacketBuffer : public Packet::SenderState, public FastAlloc {
public:
Tick ready;
@@ -145,11 +146,8 @@ class Bridge : public MemObject
BridgePort *port;
public:
- SendEvent(BridgePort *p)
- : Event(&mainEventQueue), port(p) {}
-
+ SendEvent(BridgePort *p) : port(p) {}
virtual void process() { port->trySend(); }
-
virtual const char *description() const { return "bridge send"; }
};
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index ff4512aca..2eb823051 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -97,34 +97,39 @@ Bus::init()
intIter->second->sendStatusChange(Port::RangeChange);
}
-Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus)
+Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
+ : bus(_bus)
{}
-void Bus::BusFreeEvent::process()
+void
+Bus::BusFreeEvent::process()
{
bus->recvRetry(-1);
}
-const char * Bus::BusFreeEvent::description() const
+const char *
+Bus::BusFreeEvent::description() const
{
return "bus became available";
}
-void Bus::preparePacket(PacketPtr pkt, Tick & headerTime)
+Tick
+Bus::calcPacketTiming(PacketPtr pkt)
{
- //Bring tickNextIdle up to the present tick
- //There is some potential ambiguity where a cycle starts, which might make
- //a difference when devices are acting right around a cycle boundary. Using
- //a < allows things which happen exactly on a cycle boundary to take up
- //only the following cycle. Anything that happens later will have to "wait"
- //for the end of that cycle, and then start using the bus after that.
+ // Bring tickNextIdle up to the present tick.
+ // There is some potential ambiguity where a cycle starts, which
+ // might make a difference when devices are acting right around a
+ // cycle boundary. Using a < allows things which happen exactly on
+ // a cycle boundary to take up only the following cycle. Anything
+ // that happens later will have to "wait" for the end of that
+ // cycle, and then start using the bus after that.
if (tickNextIdle < curTick) {
tickNextIdle = curTick;
if (tickNextIdle % clock != 0)
tickNextIdle = curTick - (curTick % clock) + clock;
}
- headerTime = tickNextIdle + headerCycles * clock;
+ Tick headerTime = tickNextIdle + headerCycles * clock;
// The packet will be sent. Figure out how long it occupies the bus, and
// how much of that time is for the first "word", aka bus width.
@@ -142,17 +147,20 @@ void Bus::preparePacket(PacketPtr pkt, Tick & headerTime)
pkt->firstWordTime = headerTime + clock;
pkt->finishTime = headerTime + numCycles * clock;
+
+ return headerTime;
}
void Bus::occupyBus(Tick until)
{
+ if (until == 0) {
+ // shortcut for express snoop packets
+ return;
+ }
+
tickNextIdle = until;
+ reschedule(busIdle, tickNextIdle, true);
- if (!busIdle.scheduled()) {
- busIdle.schedule(tickNextIdle);
- } else {
- busIdle.reschedule(tickNextIdle);
- }
DPRINTF(Bus, "The bus is now occupied from tick %d to %d\n",
curTick, tickNextIdle);
}
@@ -190,11 +198,8 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x\n",
src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
- Tick headerTime = 0;
-
- if (!pkt->isExpressSnoop()) {
- preparePacket(pkt, headerTime);
- }
+ Tick headerFinishTime = pkt->isExpressSnoop() ? 0 : calcPacketTiming(pkt);
+ Tick packetFinishTime = pkt->isExpressSnoop() ? 0 : pkt->finishTime;
short dest = pkt->getDest();
int dest_port_id;
@@ -243,17 +248,16 @@ Bus::recvTiming(PacketPtr pkt)
DPRINTF(Bus, "recvTiming: src %d dst %d %s 0x%x TGT RETRY\n",
src, pkt->getDest(), pkt->cmdString(), pkt->getAddr());
addToRetryList(src_port);
- if (!pkt->isExpressSnoop()) {
- occupyBus(headerTime);
- }
+ occupyBus(headerFinishTime);
return false;
}
- // send OK, fall through
+ // send OK, fall through... pkt may have been deleted by
+ // target at this point, so it should *not* be referenced
+ // again. We'll set it to NULL here just to be safe.
+ pkt = NULL;
}
- if (!pkt->isExpressSnoop()) {
- occupyBus(pkt->finishTime);
- }
+ occupyBus(packetFinishTime);
// Packet was successfully sent.
// Also take care of retries
@@ -289,7 +293,7 @@ Bus::recvRetry(int id)
//Burn a cycle for the missed grant.
tickNextIdle += clock;
- busIdle.reschedule(tickNextIdle, true);
+ reschedule(busIdle, tickNextIdle, true);
}
}
//If we weren't able to drain before, we might be able to now.
@@ -327,10 +331,10 @@ Bus::findPort(Addr addr)
if (responderSet) {
panic("Unable to find destination for addr (user set default "
- "responder): %#llx", addr);
+ "responder): %#llx\n", addr);
} else {
DPRINTF(Bus, "Unable to find destination for addr: %#llx, will use "
- "default port", addr);
+ "default port\n", addr);
return defaultId;
}
@@ -519,9 +523,12 @@ Bus::recvStatusChange(Port::Status status, int id)
for (iter = ranges.begin(); iter != ranges.end(); iter++) {
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
iter->start, iter->end, id);
- if (portMap.insert(*iter, id) == portMap.end())
- panic("Two devices with same range\n");
-
+ if (portMap.insert(*iter, id) == portMap.end()) {
+ int conflict_id = portMap.find(*iter)->second;
+ fatal("%s has two ports with same range:\n\t%s\n\t%s\n",
+ name(), interfaces[id]->getPeer()->name(),
+ interfaces[conflict_id]->getPeer()->name());
+ }
}
}
DPRINTF(MMU, "port list has %d entries\n", portMap.size());
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index 274c02de4..74901d626 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -245,10 +245,12 @@ class Bus : public MemObject
*/
void addressRanges(AddrRangeList &resp, bool &snoop, int id);
- /** Prepare a packet to be sent on the bus. The header finishes at tick
- * headerTime
+ /** Calculate the timing parameters for the packet. Updates the
+ * firstWordTime and finishTime fields of the packet object.
+ * Returns the tick at which the packet header is completed (which
+ * will be all that is sent if the target rejects the packet).
*/
- void preparePacket(PacketPtr pkt, Tick & headerTime);
+ Tick calcPacketTiming(PacketPtr pkt);
/** Occupy the bus until until */
void occupyBus(Tick until);
diff --git a/src/mem/cache/BaseCache.py b/src/mem/cache/BaseCache.py
index f6d42b1ef..bef1b45d2 100644
--- a/src/mem/cache/BaseCache.py
+++ b/src/mem/cache/BaseCache.py
@@ -38,8 +38,6 @@ class BaseCache(MemObject):
block_size = Param.Int("block size in bytes")
latency = Param.Latency("Latency")
hash_delay = Param.Int(1, "time in cycles of hash access")
- lifo = Param.Bool(False,
- "whether this NIC partition should use LIFO repl. policy")
max_miss_count = Param.Counter(0,
"number of misses to handle before calling exit")
mshrs = Param.Int("number of MSHRs (max outstanding requests)")
@@ -47,9 +45,6 @@ class BaseCache(MemObject):
"always service demand misses first")
repl = Param.Repl(NULL, "replacement policy")
size = Param.MemorySize("capacity in bytes")
- split = Param.Bool(False, "whether or not this cache is split")
- split_size = Param.Int(0,
- "How many ways of the cache belong to CPU/LRU partition")
subblock_size = Param.Int(0,
"Size of subblock in IIC used for compression")
tgts_per_mshr = Param.Int("max number of accesses per MSHR")
@@ -57,12 +52,10 @@ class BaseCache(MemObject):
two_queue = Param.Bool(False,
"whether the lifo should have two queue replacement")
write_buffers = Param.Int(8, "number of write buffers")
- prefetch_miss = Param.Bool(False,
- "wheter you are using the hardware prefetcher from Miss stream")
- prefetch_access = Param.Bool(False,
- "wheter you are using the hardware prefetcher from Access stream")
+ prefetch_on_access = Param.Bool(False,
+ "notify the hardware prefetcher on every access (not just misses)")
prefetcher_size = Param.Int(100,
- "Number of entries in the harware prefetch queue")
+ "Number of entries in the hardware prefetch queue")
prefetch_past_page = Param.Bool(False,
"Allow prefetches to cross virtual page boundaries")
prefetch_serial_squash = Param.Bool(False,
@@ -74,9 +67,9 @@ class BaseCache(MemObject):
prefetch_policy = Param.Prefetch('none',
"Type of prefetcher to use")
prefetch_cache_check_push = Param.Bool(True,
- "Check if in cash on push or pop of prefetch queue")
+ "Check if in cache on push or pop of prefetch queue")
prefetch_use_cpu_id = Param.Bool(True,
- "Use the CPU ID to seperate calculations of prefetches")
+ "Use the CPU ID to separate calculations of prefetches")
prefetch_data_accesses_only = Param.Bool(False,
"Only prefetch on data not on instruction accesses")
cpu_side = Port("Port on side closer to CPU")
diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index ac0d54bf6..956375530 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -122,7 +122,7 @@ BaseCache::CachePort::clearBlocked()
mustSendRetry = false;
SendRetryEvent *ev = new SendRetryEvent(this, true);
// @TODO: need to find a better time (next bus cycle?)
- ev->schedule(curTick + 1);
+ schedule(ev, curTick + 1);
}
}
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index d97021024..4319717e5 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -223,14 +223,14 @@ class BaseCache : public MemObject
*/
/** Number of hits per thread for each type of command. @sa Packet::Command */
- Stats::Vector<> hits[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector hits[MemCmd::NUM_MEM_CMDS];
/** Number of hits for demand accesses. */
Stats::Formula demandHits;
/** Number of hit for all accesses. */
Stats::Formula overallHits;
/** Number of misses per thread for each type of command. @sa Packet::Command */
- Stats::Vector<> misses[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector misses[MemCmd::NUM_MEM_CMDS];
/** Number of misses for demand accesses. */
Stats::Formula demandMisses;
/** Number of misses for all accesses. */
@@ -240,7 +240,7 @@ class BaseCache : public MemObject
* Total number of cycles per thread/command spent waiting for a miss.
* Used to calculate the average miss latency.
*/
- Stats::Vector<> missLatency[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector missLatency[MemCmd::NUM_MEM_CMDS];
/** Total number of cycles spent waiting for demand misses. */
Stats::Formula demandMissLatency;
/** Total number of cycles spent waiting for all misses. */
@@ -268,50 +268,50 @@ class BaseCache : public MemObject
Stats::Formula overallAvgMissLatency;
/** The total number of cycles blocked for each blocked cause. */
- Stats::Vector<> blocked_cycles;
+ Stats::Vector blocked_cycles;
/** The number of times this cache blocked for each blocked cause. */
- Stats::Vector<> blocked_causes;
+ Stats::Vector blocked_causes;
/** The average number of cycles blocked for each blocked cause. */
Stats::Formula avg_blocked;
/** The number of fast writes (WH64) performed. */
- Stats::Scalar<> fastWrites;
+ Stats::Scalar fastWrites;
/** The number of cache copies performed. */
- Stats::Scalar<> cacheCopies;
+ Stats::Scalar cacheCopies;
/** Number of blocks written back per thread. */
- Stats::Vector<> writebacks;
+ Stats::Vector writebacks;
/** Number of misses that hit in the MSHRs per command and thread. */
- Stats::Vector<> mshr_hits[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector mshr_hits[MemCmd::NUM_MEM_CMDS];
/** Demand misses that hit in the MSHRs. */
Stats::Formula demandMshrHits;
/** Total number of misses that hit in the MSHRs. */
Stats::Formula overallMshrHits;
/** Number of misses that miss in the MSHRs, per command and thread. */
- Stats::Vector<> mshr_misses[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector mshr_misses[MemCmd::NUM_MEM_CMDS];
/** Demand misses that miss in the MSHRs. */
Stats::Formula demandMshrMisses;
/** Total number of misses that miss in the MSHRs. */
Stats::Formula overallMshrMisses;
/** Number of misses that miss in the MSHRs, per command and thread. */
- Stats::Vector<> mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector mshr_uncacheable[MemCmd::NUM_MEM_CMDS];
/** Total number of misses that miss in the MSHRs. */
Stats::Formula overallMshrUncacheable;
/** Total cycle latency of each MSHR miss, per command and thread. */
- Stats::Vector<> mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector mshr_miss_latency[MemCmd::NUM_MEM_CMDS];
/** Total cycle latency of demand MSHR misses. */
Stats::Formula demandMshrMissLatency;
/** Total cycle latency of overall MSHR misses. */
Stats::Formula overallMshrMissLatency;
/** Total cycle latency of each MSHR miss, per command and thread. */
- Stats::Vector<> mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
+ Stats::Vector mshr_uncacheable_lat[MemCmd::NUM_MEM_CMDS];
/** Total cycle latency of overall MSHR misses. */
Stats::Formula overallMshrUncacheableLatency;
@@ -342,11 +342,11 @@ class BaseCache : public MemObject
Stats::Formula overallAvgMshrUncacheableLatency;
/** The number of times a thread hit its MSHR cap. */
- Stats::Vector<> mshr_cap_events;
+ Stats::Vector mshr_cap_events;
/** The number of times software prefetches caused the MSHR to block. */
- Stats::Vector<> soft_prefetch_mshr_full;
+ Stats::Vector soft_prefetch_mshr_full;
- Stats::Scalar<> mshr_no_allocate_misses;
+ Stats::Scalar mshr_no_allocate_misses;
/**
* @}
@@ -445,12 +445,6 @@ class BaseCache : public MemObject
}
}
- Tick nextMSHRReadyTime()
- {
- return std::min(mshrQueue.nextMSHRReadyTime(),
- writeBuffer.nextMSHRReadyTime());
- }
-
/**
* Request the master bus for the given cause and time.
* @param cause The reason for the request.
@@ -467,10 +461,11 @@ class BaseCache : public MemObject
*/
void deassertMemSideBusRequest(RequestCause cause)
{
- // obsolete!!
- assert(false);
- // memSidePort->deassertBusRequest(cause);
- // checkDrain();
+ // Obsolete... we no longer signal bus requests explicitly so
+ // we can't deassert them. Leaving this in as a no-op since
+ // the prefetcher calls it to indicate that it no longer wants
+ // to request a prefetch, and someday that might be
+ // interesting again.
}
virtual unsigned int drain(Event *de);
@@ -481,7 +476,7 @@ class BaseCache : public MemObject
void incMissCount(PacketPtr pkt)
{
- misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
if (missCount) {
--missCount;
diff --git a/src/mem/cache/blk.hh b/src/mem/cache/blk.hh
index 127c547ac..fe65672d6 100644
--- a/src/mem/cache/blk.hh
+++ b/src/mem/cache/blk.hh
@@ -38,8 +38,8 @@
#include <list>
#include "base/printable.hh"
-#include "sim/core.hh" // for Tick
-#include "arch/isa_traits.hh" // for Addr
+#include "sim/core.hh" // for Tick
+#include "arch/isa_traits.hh" // for Addr
#include "mem/packet.hh"
#include "mem/request.hh"
@@ -48,17 +48,17 @@
*/
enum CacheBlkStatusBits {
/** valid, readable */
- BlkValid = 0x01,
+ BlkValid = 0x01,
/** write permission */
- BlkWritable = 0x02,
+ BlkWritable = 0x02,
/** read permission (yes, block can be valid but not readable) */
- BlkReadable = 0x04,
+ BlkReadable = 0x04,
/** dirty (modified) */
- BlkDirty = 0x08,
+ BlkDirty = 0x08,
/** block was referenced */
- BlkReferenced = 0x10,
+ BlkReferenced = 0x10,
/** block was a hardware prefetch yet unaccessed*/
- BlkHWPrefetched = 0x20
+ BlkHWPrefetched = 0x20
};
/**
@@ -108,18 +108,16 @@ class CacheBlk
*/
class Lock {
public:
- int cpuNum; // locking CPU
- int threadNum; // locking thread ID within CPU
+ int contextId; // locking context
// check for matching execution context
bool matchesContext(Request *req)
{
- return (cpuNum == req->getCpuNum() &&
- threadNum == req->getThreadNum());
+ return (contextId == req->contextId());
}
Lock(Request *req)
- : cpuNum(req->getCpuNum()), threadNum(req->getThreadNum())
+ : contextId(req->contextId())
{
}
};
@@ -207,7 +205,7 @@ class CacheBlk
* be touched.
* @return True if the block was a hardware prefetch, unaccesed.
*/
- bool isPrefetch() const
+ bool wasPrefetched() const
{
return (status & BlkHWPrefetched) != 0;
}
diff --git a/src/mem/cache/builder.cc b/src/mem/cache/builder.cc
index db900c64c..599353b88 100644
--- a/src/mem/cache/builder.cc
+++ b/src/mem/cache/builder.cc
@@ -38,7 +38,6 @@
// Must be included first to determine which caches we want
#include "enums/Prefetch.hh"
#include "mem/config/cache.hh"
-#include "mem/config/prefetch.hh"
#include "mem/cache/base.hh"
#include "mem/cache/cache.hh"
#include "mem/bus.hh"
@@ -57,149 +56,78 @@
#include "mem/cache/tags/iic.hh"
#endif
-#if defined(USE_CACHE_SPLIT)
-#include "mem/cache/tags/split.hh"
-#endif
-
-#if defined(USE_CACHE_SPLIT_LIFO)
-#include "mem/cache/tags/split_lifo.hh"
-#endif
-
//Prefetcher Headers
-#if defined(USE_GHB)
#include "mem/cache/prefetch/ghb.hh"
-#endif
-#if defined(USE_TAGGED)
#include "mem/cache/prefetch/tagged.hh"
-#endif
-#if defined(USE_STRIDED)
#include "mem/cache/prefetch/stride.hh"
-#endif
using namespace std;
using namespace TheISA;
-#define BUILD_CACHE(TAGS, tags) \
- do { \
- BasePrefetcher *pf; \
- if (prefetch_policy == Enums::tagged) { \
- BUILD_TAGGED_PREFETCHER(TAGS); \
- } \
- else if (prefetch_policy == Enums::stride) { \
- BUILD_STRIDED_PREFETCHER(TAGS); \
- } \
- else if (prefetch_policy == Enums::ghb) { \
- BUILD_GHB_PREFETCHER(TAGS); \
- } \
- else { \
- BUILD_NULL_PREFETCHER(TAGS); \
- } \
- Cache<TAGS> *retval = \
- new Cache<TAGS>(this, tags, pf); \
- return retval; \
+#define BUILD_CACHE(TAGS, tags) \
+ do { \
+ BasePrefetcher *pf; \
+ if (prefetch_policy == Enums::tagged) { \
+ pf = new TaggedPrefetcher(this); \
+ } \
+ else if (prefetch_policy == Enums::stride) { \
+ pf = new StridePrefetcher(this); \
+ } \
+ else if (prefetch_policy == Enums::ghb) { \
+ pf = new GHBPrefetcher(this); \
+ } \
+ else { \
+ pf = NULL; \
+ } \
+ Cache<TAGS> *retval = \
+ new Cache<TAGS>(this, tags, pf); \
+ return retval; \
} while (0)
-#define BUILD_CACHE_PANIC(x) do { \
- panic("%s not compiled into M5", x); \
+#define BUILD_CACHE_PANIC(x) do { \
+ panic("%s not compiled into M5", x); \
} while (0)
#if defined(USE_CACHE_FALRU)
-#define BUILD_FALRU_CACHE do { \
+#define BUILD_FALRU_CACHE do { \
FALRU *tags = new FALRU(block_size, size, latency); \
- BUILD_CACHE(FALRU, tags); \
+ BUILD_CACHE(FALRU, tags); \
} while (0)
#else
#define BUILD_FALRU_CACHE BUILD_CACHE_PANIC("falru cache")
#endif
#if defined(USE_CACHE_LRU)
-#define BUILD_LRU_CACHE do { \
- LRU *tags = new LRU(numSets, block_size, assoc, latency); \
- BUILD_CACHE(LRU, tags); \
+#define BUILD_LRU_CACHE do { \
+ LRU *tags = new LRU(numSets, block_size, assoc, latency); \
+ BUILD_CACHE(LRU, tags); \
} while (0)
#else
#define BUILD_LRU_CACHE BUILD_CACHE_PANIC("lru cache")
#endif
-#if defined(USE_CACHE_SPLIT)
-#define BUILD_SPLIT_CACHE do { \
- Split *tags = new Split(numSets, block_size, assoc, split_size, lifo, \
- two_queue, latency); \
- BUILD_CACHE(Split, tags); \
- } while (0)
-#else
-#define BUILD_SPLIT_CACHE BUILD_CACHE_PANIC("split cache")
-#endif
-
-#if defined(USE_CACHE_SPLIT_LIFO)
-#define BUILD_SPLIT_LIFO_CACHE do { \
- SplitLIFO *tags = new SplitLIFO(block_size, size, assoc, \
- latency, two_queue, -1); \
- BUILD_CACHE(SplitLIFO, tags); \
- } while (0)
-#else
-#define BUILD_SPLIT_LIFO_CACHE BUILD_CACHE_PANIC("lifo cache")
-#endif
-
#if defined(USE_CACHE_IIC)
-#define BUILD_IIC_CACHE do { \
- IIC *tags = new IIC(iic_params); \
- BUILD_CACHE(IIC, tags); \
+#define BUILD_IIC_CACHE do { \
+ IIC *tags = new IIC(iic_params); \
+ BUILD_CACHE(IIC, tags); \
} while (0)
#else
#define BUILD_IIC_CACHE BUILD_CACHE_PANIC("iic")
#endif
-#define BUILD_CACHES do { \
- if (repl == NULL) { \
- if (numSets == 1) { \
- BUILD_FALRU_CACHE; \
- } else { \
- if (split == true) { \
- BUILD_SPLIT_CACHE; \
- } else if (lifo == true) { \
- BUILD_SPLIT_LIFO_CACHE; \
- } else { \
- BUILD_LRU_CACHE; \
- } \
- } \
- } else { \
- BUILD_IIC_CACHE; \
- } \
- } while (0)
-
-#define BUILD_COHERENCE(b) do { \
+#define BUILD_CACHES do { \
+ if (repl == NULL) { \
+ if (numSets == 1) { \
+ BUILD_FALRU_CACHE; \
+ } else { \
+ BUILD_LRU_CACHE; \
+ } \
+ } else { \
+ BUILD_IIC_CACHE; \
+ } \
} while (0)
-#if defined(USE_TAGGED)
-#define BUILD_TAGGED_PREFETCHER(t) \
- pf = new TaggedPrefetcher(this)
-#else
-#define BUILD_TAGGED_PREFETCHER(t) BUILD_CACHE_PANIC("Tagged Prefetcher")
-#endif
-
-#if defined(USE_STRIDED)
-#define BUILD_STRIDED_PREFETCHER(t) \
- pf = new StridePrefetcher(this)
-#else
-#define BUILD_STRIDED_PREFETCHER(t) BUILD_CACHE_PANIC("Stride Prefetcher")
-#endif
-
-#if defined(USE_GHB)
-#define BUILD_GHB_PREFETCHER(t) \
- pf = new GHBPrefetcher(this)
-#else
-#define BUILD_GHB_PREFETCHER(t) BUILD_CACHE_PANIC("GHB Prefetcher")
-#endif
-
-#if defined(USE_TAGGED)
-#define BUILD_NULL_PREFETCHER(t) \
- pf = new TaggedPrefetcher(this)
-#else
-#define BUILD_NULL_PREFETCHER(t) BUILD_CACHE_PANIC("NULL Prefetcher (uses Tagged)")
-#endif
-
BaseCache *
BaseCacheParams::create()
{
@@ -208,24 +136,6 @@ BaseCacheParams::create()
subblock_size = block_size;
}
- //Warnings about prefetcher policy
- if (prefetch_policy == Enums::none) {
- if (prefetch_miss || prefetch_access)
- panic("With no prefetcher, you shouldn't prefetch from"
- " either miss or access stream\n");
- }
-
- if (prefetch_policy == Enums::tagged || prefetch_policy == Enums::stride ||
- prefetch_policy == Enums::ghb) {
-
- if (!prefetch_miss && !prefetch_access)
- warn("With this prefetcher you should chose a prefetch"
- " stream (miss or access)\nNo Prefetching will occur\n");
-
- if (prefetch_miss && prefetch_access)
- panic("Can't do prefetches from both miss and access stream");
- }
-
#if defined(USE_CACHE_IIC)
// Build IIC params
IIC::Params iic_params;
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
index c640d4a60..d403535fc 100644
--- a/src/mem/cache/cache.cc
+++ b/src/mem/cache/cache.cc
@@ -50,14 +50,6 @@
#include "mem/cache/tags/iic.hh"
#endif
-#if defined(USE_CACHE_SPLIT)
-#include "mem/cache/tags/split.hh"
-#endif
-
-#if defined(USE_CACHE_SPLIT_LIFO)
-#include "mem/cache/tags/split_lifo.hh"
-#endif
-
#include "mem/cache/cache_impl.hh"
// Template Instantiations
@@ -76,12 +68,4 @@ template class Cache<IIC>;
template class Cache<LRU>;
#endif
-#if defined(USE_CACHE_SPLIT)
-template class Cache<Split>;
-#endif
-
-#if defined(USE_CACHE_SPLIT_LIFO)
-template class Cache<SplitLIFO>;
-#endif
-
#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index f5f65d4dd..4570b067b 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -64,8 +64,6 @@ class Cache : public BaseCache
/** A typedef for a list of BlkType pointers. */
typedef typename TagStore::BlkList BlkList;
- bool prefetchAccess;
-
protected:
class CpuSidePort : public CachePort
@@ -137,21 +135,14 @@ class Cache : public BaseCache
BlkType *tempBlock;
/**
- * Can this cache should allocate a block on a line-sized write miss.
+ * This cache should allocate a block on a line-sized write miss.
*/
const bool doFastWrites;
- const bool prefetchMiss;
-
/**
- * Handle a replacement for the given request.
- * @param blk A pointer to the block, usually NULL
- * @param pkt The memory request to satisfy.
- * @param new_state The new state of the block.
- * @param writebacks A list to store any generated writebacks.
+ * Notify the prefetcher on every access, not just misses.
*/
- BlkType* doReplacement(BlkType *blk, PacketPtr pkt,
- CacheBlk::State new_state, PacketList &writebacks);
+ const bool prefetchOnAccess;
/**
* Does all the processing necessary to perform the provided request.
@@ -159,10 +150,10 @@ class Cache : public BaseCache
* @param lat The latency of the access.
* @param writebacks List for any writebacks that need to be performed.
* @param update True if the replacement data should be updated.
- * @return Pointer to the cache block touched by the request. NULL if it
- * was a miss.
+ * @return Boolean indicating whether the request was satisfied.
*/
- bool access(PacketPtr pkt, BlkType *&blk, int &lat);
+ bool access(PacketPtr pkt, BlkType *&blk,
+ int &lat, PacketList &writebacks);
/**
*Handle doing the Compare and Swap function for SPARC.
@@ -181,7 +172,6 @@ class Cache : public BaseCache
* Populates a cache block and handles all outstanding requests for the
* satisfied fill request. This version takes two memory requests. One
* contains the fill data, the other is an optional target to satisfy.
- * Used for Cache::probe.
* @param pkt The memory request with the fill data.
* @param blk The cache block if it already exists.
* @param writebacks List for any writebacks that need to be performed.
@@ -331,6 +321,11 @@ class Cache : public BaseCache
bool inMissQueue(Addr addr) {
return (mshrQueue.findMatch(addr) != 0);
}
+
+ /**
+ * Find next request ready time from among possible sources.
+ */
+ Tick nextMSHRReadyTime();
};
#endif // __CACHE_HH__
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index e546e2a9a..a78fd3637 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -38,6 +38,7 @@
*/
#include "sim/host.hh"
+#include "base/fast_alloc.hh"
#include "base/misc.hh"
#include "base/range_ops.hh"
@@ -52,11 +53,10 @@
template<class TagStore>
Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf)
: BaseCache(p),
- prefetchAccess(p->prefetch_access),
tags(tags),
prefetcher(pf),
doFastWrites(true),
- prefetchMiss(p->prefetch_miss)
+ prefetchOnAccess(p->prefetch_on_access)
{
tempBlock = new BlkType();
tempBlock->data = new uint8_t[blkSize];
@@ -71,7 +71,8 @@ Cache<TagStore>::Cache(const Params *p, TagStore *tags, BasePrefetcher *pf)
memSidePort->setOtherPort(cpuSidePort);
tags->setCache(this);
- prefetcher->setCache(this);
+ if (prefetcher)
+ prefetcher->setCache(this);
}
template<class TagStore>
@@ -80,7 +81,8 @@ Cache<TagStore>::regStats()
{
BaseCache::regStats();
tags->regStats(name());
- prefetcher->regStats(name());
+ if (prefetcher)
+ prefetcher->regStats(name());
}
template<class TagStore>
@@ -147,8 +149,10 @@ Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt)
panic("Invalid size for conditional read/write\n");
}
- if (overwrite_mem)
+ if (overwrite_mem) {
std::memcpy(blk_data, &overwrite_val, pkt->getSize());
+ blk->status |= BlkDirty;
+ }
}
@@ -259,7 +263,8 @@ Cache<TagStore>::squash(int threadNum)
template<class TagStore>
bool
-Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
+Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk,
+ int &lat, PacketList &writebacks)
{
if (pkt->req->isUncacheable()) {
blk = NULL;
@@ -267,34 +272,16 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
return false;
}
- blk = tags->findBlock(pkt->getAddr(), lat);
-
- if (prefetchAccess) {
- //We are determining prefetches on access stream, call prefetcher
- prefetcher->handleMiss(pkt, curTick);
- }
+ blk = tags->accessBlock(pkt->getAddr(), lat);
DPRINTF(Cache, "%s %x %s\n", pkt->cmdString(), pkt->getAddr(),
(blk) ? "hit" : "miss");
if (blk != NULL) {
- if (blk->isPrefetch()) {
- //Signal that this was a hit under prefetch (no need for
- //use prefetch (only can get here if true)
- DPRINTF(HWPrefetch, "Hit a block that was prefetched\n");
- blk->status &= ~BlkHWPrefetched;
- if (prefetchMiss) {
- //If we are using the miss stream, signal the
- //prefetcher otherwise the access stream would have
- //already signaled this hit
- prefetcher->handleMiss(pkt, curTick);
- }
- }
-
if (pkt->needsExclusive() ? blk->isWritable() : blk->isReadable()) {
// OK to satisfy access
- hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
satisfyCpuSideRequest(pkt, blk);
return true;
}
@@ -307,7 +294,6 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
// into the cache without having a writeable copy (or any copy at
// all).
if (pkt->cmd == MemCmd::Writeback) {
- PacketList writebacks;
assert(blkSize == pkt->getSize());
if (blk == NULL) {
// need to do a replacement
@@ -318,19 +304,14 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
incMissCount(pkt);
return false;
}
+ tags->insertBlock(pkt->getAddr(), blk);
blk->status = BlkValid | BlkReadable;
}
std::memcpy(blk->data, pkt->getPtr<uint8_t>(), blkSize);
blk->status |= BlkDirty;
- // copy writebacks from replacement to write buffer
- while (!writebacks.empty()) {
- PacketPtr wbPkt = writebacks.front();
- allocateWriteBuffer(wbPkt, curTick + hitLatency, true);
- writebacks.pop_front();
- }
// nothing else to do; writeback doesn't expect response
assert(!pkt->needsResponse());
- hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
return true;
}
@@ -346,7 +327,7 @@ Cache<TagStore>::access(PacketPtr pkt, BlkType *&blk, int &lat)
}
-class ForwardResponseRecord : public Packet::SenderState
+class ForwardResponseRecord : public Packet::SenderState, public FastAlloc
{
Packet::SenderState *prevSenderState;
int prevSrc;
@@ -407,6 +388,9 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
memSidePort->sendTiming(snoopPkt);
// main memory will delete snoopPkt
}
+ // since we're the official target but we aren't responding,
+ // delete the packet now.
+ delete pkt;
return true;
}
@@ -423,13 +407,13 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
int lat = hitLatency;
BlkType *blk = NULL;
- bool satisfied = access(pkt, blk, lat);
+ PacketList writebacks;
+
+ bool satisfied = access(pkt, blk, lat, writebacks);
#if 0
/** @todo make the fast write alloc (wh64) work with coherence. */
- PacketList writebacks;
-
// If this is a block size write/hint (WH64) allocate the block here
// if the coherence protocol allows it.
if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
@@ -447,15 +431,11 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
++fastWrites;
}
}
-
- // copy writebacks to write buffer
- while (!writebacks.empty()) {
- PacketPtr wbPkt = writebacks.front();
- allocateWriteBuffer(wbPkt, time, true);
- writebacks.pop_front();
- }
#endif
+ // track time of availability of next prefetch, if any
+ Tick next_pf_time = 0;
+
bool needsResponse = pkt->needsResponse();
if (satisfied) {
@@ -465,10 +445,14 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
} else {
delete pkt;
}
+
+ if (prefetcher && (prefetchOnAccess || (blk && blk->wasPrefetched()))) {
+ if (blk)
+ blk->status &= ~BlkHWPrefetched;
+ next_pf_time = prefetcher->notify(pkt, time);
+ }
} else {
// miss
- if (prefetchMiss)
- prefetcher->handleMiss(pkt, time);
Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
MSHR *mshr = mshrQueue.findMatch(blk_addr);
@@ -476,8 +460,8 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
if (mshr) {
// MSHR hit
//@todo remove hw_pf here
- mshr_hits[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
- if (mshr->threadNum != 0/*pkt->req->getThreadNum()*/) {
+ mshr_hits[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
+ if (mshr->threadNum != 0/*pkt->req->threadId()*/) {
mshr->threadNum = -1;
}
mshr->allocateTarget(pkt, time, order++);
@@ -491,7 +475,7 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
}
} else {
// no MSHR
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
// always mark as cache fill for now... if we implement
// no-write-allocate or bypass accesses this will have to
// be changed.
@@ -520,9 +504,23 @@ Cache<TagStore>::timingAccess(PacketPtr pkt)
allocateMissBuffer(pkt, time, true);
}
+
+ if (prefetcher) {
+ next_pf_time = prefetcher->notify(pkt, time);
+ }
}
}
+ if (next_pf_time != 0)
+ requestMemSideBus(Request_PF, std::max(time, next_pf_time));
+
+ // copy writebacks to write buffer
+ while (!writebacks.empty()) {
+ PacketPtr wbPkt = writebacks.front();
+ allocateWriteBuffer(wbPkt, time, true);
+ writebacks.pop_front();
+ }
+
return true;
}
@@ -610,53 +608,79 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt)
// access in timing mode
BlkType *blk = NULL;
+ PacketList writebacks;
- if (!access(pkt, blk, lat)) {
+ if (!access(pkt, blk, lat, writebacks)) {
// MISS
- PacketPtr busPkt = getBusPacket(pkt, blk, pkt->needsExclusive());
+ PacketPtr bus_pkt = getBusPacket(pkt, blk, pkt->needsExclusive());
- bool isCacheFill = (busPkt != NULL);
+ bool is_forward = (bus_pkt == NULL);
- if (busPkt == NULL) {
+ if (is_forward) {
// just forwarding the same request to the next level
// no local cache operation involved
- busPkt = pkt;
+ bus_pkt = pkt;
}
DPRINTF(Cache, "Sending an atomic %s for %x\n",
- busPkt->cmdString(), busPkt->getAddr());
+ bus_pkt->cmdString(), bus_pkt->getAddr());
#if TRACING_ON
CacheBlk::State old_state = blk ? blk->status : 0;
#endif
- lat += memSidePort->sendAtomic(busPkt);
+ lat += memSidePort->sendAtomic(bus_pkt);
DPRINTF(Cache, "Receive response: %s for addr %x in state %i\n",
- busPkt->cmdString(), busPkt->getAddr(), old_state);
-
- bool is_error = busPkt->isError();
- assert(!busPkt->wasNacked());
-
- if (is_error && pkt->needsResponse()) {
- pkt->makeAtomicResponse();
- pkt->copyError(busPkt);
- } else if (isCacheFill && !is_error) {
- PacketList writebacks;
- blk = handleFill(busPkt, blk, writebacks);
- satisfyCpuSideRequest(pkt, blk);
- delete busPkt;
-
- // Handle writebacks if needed
- while (!writebacks.empty()){
- PacketPtr wbPkt = writebacks.front();
- memSidePort->sendAtomic(wbPkt);
- writebacks.pop_front();
- delete wbPkt;
+ bus_pkt->cmdString(), bus_pkt->getAddr(), old_state);
+
+ assert(!bus_pkt->wasNacked());
+
+ // If packet was a forward, the response (if any) is already
+ // in place in the bus_pkt == pkt structure, so we don't need
+ // to do anything. Otherwise, use the separate bus_pkt to
+ // generate response to pkt and then delete it.
+ if (!is_forward) {
+ if (pkt->needsResponse()) {
+ assert(bus_pkt->isResponse());
+ if (bus_pkt->isError()) {
+ pkt->makeAtomicResponse();
+ pkt->copyError(bus_pkt);
+ } else if (bus_pkt->isRead() ||
+ bus_pkt->cmd == MemCmd::UpgradeResp) {
+ // we're updating cache state to allow us to
+ // satisfy the upstream request from the cache
+ blk = handleFill(bus_pkt, blk, writebacks);
+ satisfyCpuSideRequest(pkt, blk);
+ } else {
+ // we're satisfying the upstream request without
+ // modifying cache state, e.g., a write-through
+ pkt->makeAtomicResponse();
+ }
}
+ delete bus_pkt;
}
}
+ // Note that we don't invoke the prefetcher at all in atomic mode.
+ // It's not clear how to do it properly, particularly for
+ // prefetchers that aggressively generate prefetch candidates and
+ // rely on bandwidth contention to throttle them; these will tend
+ // to pollute the cache in atomic mode since there is no bandwidth
+ // contention. If we ever do want to enable prefetching in atomic
+ // mode, though, this is the place to do it... see timingAccess()
+ // for an example (though we'd want to issue the prefetch(es)
+ // immediately rather than calling requestMemSideBus() as we do
+ // there).
+
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ PacketPtr wbPkt = writebacks.front();
+ memSidePort->sendAtomic(wbPkt);
+ writebacks.pop_front();
+ delete wbPkt;
+ }
+
// We now have the block one way or another (hit or completed miss)
if (pkt->needsResponse()) {
@@ -742,14 +766,17 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
PacketList writebacks;
if (pkt->req->isUncacheable()) {
- mshr_uncacheable_lat[stats_cmd_idx][0/*pkt->req->getThreadNum()*/] +=
+ mshr_uncacheable_lat[stats_cmd_idx][0/*pkt->req->threadId()*/] +=
miss_latency;
} else {
- mshr_miss_latency[stats_cmd_idx][0/*pkt->req->getThreadNum()*/] +=
+ mshr_miss_latency[stats_cmd_idx][0/*pkt->req->threadId()*/] +=
miss_latency;
}
- if (mshr->isCacheFill && !is_error) {
+ bool is_fill = !mshr->isForward &&
+ (pkt->isRead() || pkt->cmd == MemCmd::UpgradeResp);
+
+ if (is_fill && !is_error) {
DPRINTF(Cache, "Block for addr %x being updated in Cache\n",
pkt->getAddr());
@@ -770,9 +797,10 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
while (mshr->hasTargets()) {
MSHR::Target *target = mshr->getTarget();
- if (target->isCpuSide()) {
+ switch (target->source) {
+ case MSHR::Target::FromCPU:
Tick completion_time;
- if (blk != NULL) {
+ if (is_fill) {
satisfyCpuSideRequest(target->pkt, blk);
// How many bytes past the first request is this one
int transfer_offset =
@@ -786,7 +814,7 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
(transfer_offset ? pkt->finishTime : pkt->firstWordTime);
assert(!target->pkt->req->isUncacheable());
- missLatency[target->pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] +=
+ missLatency[target->pkt->cmdToIndex()][0/*pkt->req->threadId()*/] +=
completion_time - target->recvTime;
} else {
// not a cache fill, just forwarding response
@@ -808,13 +836,27 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
target->pkt->cmd = MemCmd::ReadRespWithInvalidate;
}
cpuSidePort->respond(target->pkt, completion_time);
- } else {
+ break;
+
+ case MSHR::Target::FromPrefetcher:
+ assert(target->pkt->cmd == MemCmd::HardPFReq);
+ if (blk)
+ blk->status |= BlkHWPrefetched;
+ delete target->pkt->req;
+ delete target->pkt;
+ break;
+
+ case MSHR::Target::FromSnoop:
// I don't believe that a snoop can be in an error state
assert(!is_error);
// response to snoop request
DPRINTF(Cache, "processing deferred snoop...\n");
handleSnoop(target->pkt, blk, true, true,
mshr->pendingInvalidate || pkt->isInvalidate());
+ break;
+
+ default:
+ panic("Illegal target->source enum %d\n", target->source);
}
mshr->popTarget();
@@ -825,6 +867,9 @@ Cache<TagStore>::handleResponse(PacketPtr pkt)
}
if (mshr->promoteDeferredTargets()) {
+ // avoid later read getting stale data while write miss is
+ // outstanding.. see comment in timingAccess()
+ blk->status &= ~BlkReadable;
MSHRQueue *mq = mshr->queue;
mq->markPending(mshr);
requestMemSideBus((RequestCause)mq->index, pkt->finishTime);
@@ -861,7 +906,7 @@ Cache<TagStore>::writebackBlk(BlkType *blk)
{
assert(blk && blk->isValid() && blk->isDirty());
- writebacks[0/*pkt->req->getThreadNum()*/]++;
+ writebacks[0/*pkt->req->threadId()*/]++;
Request *writebackReq =
new Request(tags->regenerateBlkAddr(blk->tag, blk->set), blkSize, 0);
@@ -878,7 +923,7 @@ template<class TagStore>
typename Cache<TagStore>::BlkType*
Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks)
{
- BlkType *blk = tags->findReplacement(addr, writebacks);
+ BlkType *blk = tags->findVictim(addr, writebacks);
if (blk->isValid()) {
Addr repl_addr = tags->regenerateBlkAddr(blk->tag, blk->set);
@@ -889,6 +934,7 @@ Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks)
assert(!blk->isWritable());
assert(repl_mshr->needsExclusive());
// too hard to replace block with transient state
+ // allocation failed, block not inserted
return NULL;
} else {
DPRINTF(Cache, "replacement: replacing %x with %x: %s\n",
@@ -902,8 +948,6 @@ Cache<TagStore>::allocateBlock(Addr addr, PacketList &writebacks)
}
}
- // Set tag for new block. Caller is responsible for setting status.
- blk->tag = tags->extractTag(addr);
return blk;
}
@@ -934,7 +978,10 @@ Cache<TagStore>::handleFill(PacketPtr pkt, BlkType *blk,
assert(!tempBlock->isValid());
blk = tempBlock;
tempBlock->set = tags->extractSet(addr);
+ tempBlock->tag = tags->extractTag(addr);
DPRINTF(Cache, "using temp block for %x\n", addr);
+ } else {
+ tags->insertBlock(addr, blk);
}
} else {
// existing block... probably an upgrade
@@ -1088,6 +1135,11 @@ Cache<TagStore>::handleSnoop(PacketPtr pkt, BlkType *blk,
pkt->makeAtomicResponse();
pkt->setDataFromBlock(blk->data, blkSize);
}
+ } else if (is_timing && is_deferred) {
+ // if it's a deferred timing snoop then we've made a copy of
+ // the packet, and so if we're not using that copy to respond
+ // then we need to delete it here.
+ delete pkt;
}
// Do this last in case it deallocates block data or something
@@ -1156,6 +1208,7 @@ Cache<TagStore>::snoopTiming(PacketPtr pkt)
if (pkt->isInvalidate()) {
// Invalidation trumps our writeback... discard here
markInService(mshr);
+ delete wb_pkt;
}
// If this was a shared writeback, there may still be
@@ -1253,7 +1306,7 @@ Cache<TagStore>::getNextMSHR()
if (pkt) {
// Update statistic on number of prefetches issued
// (hwpf_mshr_misses)
- mshr_misses[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/]++;
+ mshr_misses[pkt->cmdToIndex()][0/*pkt->req->threadId()*/]++;
// Don't request bus, since we already have it
return allocateMissBuffer(pkt, curTick, false);
}
@@ -1277,7 +1330,7 @@ Cache<TagStore>::getTimingPacket()
PacketPtr tgt_pkt = mshr->getTarget()->pkt;
PacketPtr pkt = NULL;
- if (mshr->isSimpleForward()) {
+ if (mshr->isForwardNoResponse()) {
// no response expected, just forward packet as it is
assert(tags->findBlock(mshr->addr) == NULL);
pkt = tgt_pkt;
@@ -1285,11 +1338,10 @@ Cache<TagStore>::getTimingPacket()
BlkType *blk = tags->findBlock(mshr->addr);
pkt = getBusPacket(tgt_pkt, blk, mshr->needsExclusive());
- mshr->isCacheFill = (pkt != NULL);
+ mshr->isForward = (pkt == NULL);
- if (pkt == NULL) {
+ if (mshr->isForward) {
// not a cache block request, but a response is expected
- assert(!mshr->isSimpleForward());
// make copy of current packet to forward, keep current
// copy for response handling
pkt = new Packet(tgt_pkt);
@@ -1306,6 +1358,22 @@ Cache<TagStore>::getTimingPacket()
}
+template<class TagStore>
+Tick
+Cache<TagStore>::nextMSHRReadyTime()
+{
+ Tick nextReady = std::min(mshrQueue.nextMSHRReadyTime(),
+ writeBuffer.nextMSHRReadyTime());
+
+ if (prefetcher) {
+ nextReady = std::min(nextReady,
+ prefetcher->nextPrefetchReadyTime());
+ }
+
+ return nextReady;
+}
+
+
///////////////
//
// CpuSidePort
@@ -1463,7 +1531,7 @@ Cache<TagStore>::MemSidePort::sendPacket()
waitingOnRetry = !success;
if (waitingOnRetry) {
DPRINTF(CachePort, "now waiting on a retry\n");
- if (!mshr->isSimpleForward()) {
+ if (!mshr->isForwardNoResponse()) {
delete pkt;
}
} else {
@@ -1481,7 +1549,7 @@ Cache<TagStore>::MemSidePort::sendPacket()
// @TODO: need to facotr in prefetch requests here somehow
if (nextReady != MaxTick) {
DPRINTF(CachePort, "more packets to send @ %d\n", nextReady);
- sendEvent->schedule(std::max(nextReady, curTick + 1));
+ schedule(sendEvent, std::max(nextReady, curTick + 1));
} else {
// no more to send right now: if we're draining, we may be done
if (drainEvent) {
diff --git a/src/mem/cache/mshr.cc b/src/mem/cache/mshr.cc
index 6537f6343..9ec9c090c 100644
--- a/src/mem/cache/mshr.cc
+++ b/src/mem/cache/mshr.cc
@@ -64,9 +64,9 @@ MSHR::TargetList::TargetList()
inline void
MSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
- Counter order, bool cpuSide, bool markPending)
+ Counter order, Target::Source source, bool markPending)
{
- if (cpuSide) {
+ if (source != Target::FromSnoop) {
if (pkt->needsExclusive()) {
needsExclusive = true;
}
@@ -84,7 +84,7 @@ MSHR::TargetList::add(PacketPtr pkt, Tick readyTime,
}
}
- push_back(Target(pkt, readyTime, order, cpuSide, markPending));
+ push_back(Target(pkt, readyTime, order, source, markPending));
}
@@ -141,7 +141,14 @@ print(std::ostream &os, int verbosity, const std::string &prefix) const
{
ConstIterator end_i = end();
for (ConstIterator i = begin(); i != end_i; ++i) {
- ccprintf(os, "%s%s: ", prefix, i->isCpuSide() ? "cpu" : "mem");
+ const char *s;
+ switch (i->source) {
+ case Target::FromCPU: s = "FromCPU";
+ case Target::FromSnoop: s = "FromSnoop";
+ case Target::FromPrefetcher: s = "FromPrefetcher";
+ default: s = "";
+ }
+ ccprintf(os, "%s%s: ", prefix, s);
i->pkt->print(os, verbosity, "");
}
}
@@ -156,16 +163,18 @@ MSHR::allocate(Addr _addr, int _size, PacketPtr target,
readyTime = whenReady;
order = _order;
assert(target);
- isCacheFill = false;
+ isForward = false;
_isUncacheable = target->req->isUncacheable();
inService = false;
downstreamPending = false;
threadNum = 0;
ntargets = 1;
- // Don't know of a case where we would allocate a new MSHR for a
- // snoop (mem-side request), so set cpuSide to true here.
assert(targets->isReset());
- targets->add(target, whenReady, _order, true, true);
+ // Don't know of a case where we would allocate a new MSHR for a
+ // snoop (mem-side request), so set source according to request here
+ Target::Source source = (target->cmd == MemCmd::HardPFReq) ?
+ Target::FromPrefetcher : Target::FromCPU;
+ targets->add(target, whenReady, _order, source, true);
assert(deferredTargets->isReset());
pendingInvalidate = false;
pendingShared = false;
@@ -187,7 +196,7 @@ bool
MSHR::markInService()
{
assert(!inService);
- if (isSimpleForward()) {
+ if (isForwardNoResponse()) {
// we just forwarded the request packet & don't expect a
// response, so get rid of it
assert(getNumTargets() == 1);
@@ -230,17 +239,22 @@ MSHR::allocateTarget(PacketPtr pkt, Tick whenReady, Counter _order)
// comes back (but before this target is processed)
// - the outstanding request is for a non-exclusive block and this
// target requires an exclusive block
+
+ // assume we'd never issue a prefetch when we've got an
+ // outstanding miss
+ assert(pkt->cmd != MemCmd::HardPFReq);
+
if (inService &&
(!deferredTargets->empty() || pendingInvalidate ||
(!targets->needsExclusive && pkt->needsExclusive()))) {
// need to put on deferred list
- deferredTargets->add(pkt, whenReady, _order, true, true);
+ deferredTargets->add(pkt, whenReady, _order, Target::FromCPU, true);
} else {
// No request outstanding, or still OK to append to
// outstanding request: append to regular target list. Only
// mark pending if current request hasn't been issued yet
// (isn't in service).
- targets->add(pkt, whenReady, _order, true, !inService);
+ targets->add(pkt, whenReady, _order, Target::FromCPU, !inService);
}
++ntargets;
@@ -291,7 +305,7 @@ MSHR::handleSnoop(PacketPtr pkt, Counter _order)
// actual target device (typ. PhysicalMemory) will delete the
// packet on reception, so we need to save a copy here
PacketPtr cp_pkt = new Packet(pkt, true);
- targets->add(cp_pkt, curTick, _order, false,
+ targets->add(cp_pkt, curTick, _order, Target::FromSnoop,
downstreamPending && targets->needsExclusive);
++ntargets;
@@ -403,7 +417,8 @@ MSHR::print(std::ostream &os, int verbosity, const std::string &prefix) const
{
ccprintf(os, "%s[%x:%x] %s %s %s state: %s %s %s %s\n",
prefix, addr, addr+size-1,
- isCacheFill ? "Fill" : "",
+ isForward ? "Forward" : "",
+ isForwardNoResponse() ? "ForwNoResp" : "",
needsExclusive() ? "Excl" : "",
_isUncacheable ? "Unc" : "",
inService ? "InSvc" : "",
diff --git a/src/mem/cache/mshr.hh b/src/mem/cache/mshr.hh
index fdb0485cb..bed7012b0 100644
--- a/src/mem/cache/mshr.hh
+++ b/src/mem/cache/mshr.hh
@@ -55,20 +55,25 @@ class MSHR : public Packet::SenderState, public Printable
class Target {
public:
+
+ enum Source {
+ FromCPU,
+ FromSnoop,
+ FromPrefetcher
+ };
+
Tick recvTime; //!< Time when request was received (for stats)
Tick readyTime; //!< Time when request is ready to be serviced
Counter order; //!< Global order (for memory consistency mgmt)
PacketPtr pkt; //!< Pending request packet.
- bool cpuSide; //!< Did request come from cpu side or mem side?
+ Source source; //!< Did request come from cpu, memory, or prefetcher?
bool markedPending; //!< Did we mark upstream MSHR
//!< as downstreamPending?
- bool isCpuSide() const { return cpuSide; }
-
Target(PacketPtr _pkt, Tick _readyTime, Counter _order,
- bool _cpuSide, bool _markedPending)
+ Source _source, bool _markedPending)
: recvTime(curTick), readyTime(_readyTime), order(_order),
- pkt(_pkt), cpuSide(_cpuSide), markedPending(_markedPending)
+ pkt(_pkt), source(_source), markedPending(_markedPending)
{}
};
@@ -85,7 +90,7 @@ class MSHR : public Packet::SenderState, public Printable
void resetFlags() { needsExclusive = hasUpgrade = false; }
bool isReset() { return !needsExclusive && !hasUpgrade; }
void add(PacketPtr pkt, Tick readyTime, Counter order,
- bool cpuSide, bool markPending);
+ Target::Source source, bool markPending);
void replaceUpgrades();
void clearDownstreamPending();
bool checkFunctional(PacketPtr pkt);
@@ -118,8 +123,8 @@ class MSHR : public Packet::SenderState, public Printable
/** True if the request has been sent to the bus. */
bool inService;
- /** True if we will be putting the returned block in the cache */
- bool isCacheFill;
+ /** True if the request is just a simple forward from an upper level */
+ bool isForward;
/** True if we need to get an exclusive copy of the block. */
bool needsExclusive() const { return targets->needsExclusive; }
@@ -200,7 +205,7 @@ public:
* Returns the current number of allocated targets.
* @return The current number of allocated targets.
*/
- int getNumTargets() { return ntargets; }
+ int getNumTargets() const { return ntargets; }
/**
* Returns a pointer to the target list.
@@ -212,13 +217,17 @@ public:
* Returns true if there are targets left.
* @return true if there are targets
*/
- bool hasTargets() { return !targets->empty(); }
+ bool hasTargets() const { return !targets->empty(); }
/**
* Returns a reference to the first target.
* @return A pointer to the first target.
*/
- Target *getTarget() { assert(hasTargets()); return &targets->front(); }
+ Target *getTarget() const
+ {
+ assert(hasTargets());
+ return &targets->front();
+ }
/**
* Pop first target.
@@ -229,12 +238,12 @@ public:
targets->pop_front();
}
- bool isSimpleForward()
+ bool isForwardNoResponse() const
{
if (getNumTargets() != 1)
return false;
Target *tgt = getTarget();
- return tgt->isCpuSide() && !tgt->pkt->needsResponse();
+ return tgt->source == Target::FromCPU && !tgt->pkt->needsResponse();
}
bool promoteDeferredTargets();
diff --git a/src/mem/cache/mshr_queue.cc b/src/mem/cache/mshr_queue.cc
index 45331c33d..b5c6cc7b8 100644
--- a/src/mem/cache/mshr_queue.cc
+++ b/src/mem/cache/mshr_queue.cc
@@ -230,7 +230,7 @@ MSHRQueue::squash(int threadNum)
if (mshr->threadNum == threadNum) {
while (mshr->hasTargets()) {
mshr->popTarget();
- assert(0/*target->req->getThreadNum()*/ == threadNum);
+ assert(0/*target->req->threadId()*/ == threadNum);
}
assert(!mshr->hasTargets());
assert(mshr->ntargets==0);
diff --git a/src/mem/cache/prefetch/base.cc b/src/mem/cache/prefetch/base.cc
index fcc02ff28..365ce6727 100644
--- a/src/mem/cache/prefetch/base.cc
+++ b/src/mem/cache/prefetch/base.cc
@@ -33,6 +33,7 @@
* Hardware Prefetcher Definition.
*/
+#include "arch/isa_traits.hh"
#include "base/trace.hh"
#include "mem/cache/base.hh"
#include "mem/cache/prefetch/base.hh"
@@ -43,7 +44,7 @@ BasePrefetcher::BasePrefetcher(const BaseCacheParams *p)
: size(p->prefetcher_size), pageStop(!p->prefetch_past_page),
serialSquash(p->prefetch_serial_squash),
cacheCheckPush(p->prefetch_cache_check_push),
- only_data(p->prefetch_data_accesses_only)
+ onlyData(p->prefetch_data_accesses_only)
{
}
@@ -52,6 +53,7 @@ BasePrefetcher::setCache(BaseCache *_cache)
{
cache = _cache;
blkSize = cache->getBlockSize();
+ _name = cache->name() + "-pf";
}
void
@@ -99,7 +101,8 @@ BasePrefetcher::regStats(const std::string &name)
pfSquashed
.name(name + ".prefetcher.num_hwpf_squashed_from_miss")
- .desc("number of hwpf that got squashed due to a miss aborting calculation time")
+ .desc("number of hwpf that got squashed due to a miss "
+ "aborting calculation time")
;
}
@@ -126,60 +129,79 @@ BasePrefetcher::inMissQueue(Addr addr)
PacketPtr
BasePrefetcher::getPacket()
{
- DPRINTF(HWPrefetch, "%s:Requesting a hw_pf to issue\n", cache->name());
+ DPRINTF(HWPrefetch, "Requesting a hw_pf to issue\n");
if (pf.empty()) {
- DPRINTF(HWPrefetch, "%s:No HW_PF found\n", cache->name());
+ DPRINTF(HWPrefetch, "No HW_PF found\n");
return NULL;
}
PacketPtr pkt;
- bool keepTrying = false;
+ bool keep_trying = false;
do {
pkt = *pf.begin();
pf.pop_front();
if (!cacheCheckPush) {
- keepTrying = cache->inCache(pkt->getAddr());
+ keep_trying = cache->inCache(pkt->getAddr());
}
+
+ if (keep_trying) {
+ DPRINTF(HWPrefetch, "addr 0x%x in cache, skipping\n",
+ pkt->getAddr());
+ delete pkt->req;
+ delete pkt;
+ }
+
if (pf.empty()) {
cache->deassertMemSideBusRequest(BaseCache::Request_PF);
- if (keepTrying) return NULL; //None left, all were in cache
+ if (keep_trying) {
+ return NULL; // None left, all were in cache
+ }
}
- } while (keepTrying);
+ } while (keep_trying);
pfIssued++;
+ assert(pkt != NULL);
+ DPRINTF(HWPrefetch, "returning 0x%x\n", pkt->getAddr());
return pkt;
}
-void
-BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
+
+Tick
+BasePrefetcher::notify(PacketPtr &pkt, Tick time)
{
- if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && only_data))
- {
- //Calculate the blk address
- Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
+ if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && onlyData)) {
+ // Calculate the blk address
+ Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1);
- //Check if miss is in pfq, if so remove it
- std::list<PacketPtr>::iterator iter = inPrefetch(blkAddr);
+ // Check if miss is in pfq, if so remove it
+ std::list<PacketPtr>::iterator iter = inPrefetch(blk_addr);
if (iter != pf.end()) {
- DPRINTF(HWPrefetch, "%s:Saw a miss to a queued prefetch, removing it\n", cache->name());
+ DPRINTF(HWPrefetch, "Saw a miss to a queued prefetch addr: "
+ "0x%x, removing it\n", blk_addr);
pfRemovedMSHR++;
+ delete (*iter)->req;
+ delete (*iter);
pf.erase(iter);
if (pf.empty())
cache->deassertMemSideBusRequest(BaseCache::Request_PF);
}
- //Remove anything in queue with delay older than time
- //since everything is inserted in time order, start from end
- //and work until pf.empty() or time is earlier
- //This is done to emulate Aborting the previous work on a new miss
- //Needed for serial calculators like GHB
+ // Remove anything in queue with delay older than time
+ // since everything is inserted in time order, start from end
+ // and work until pf.empty() or time is earlier
+ // This is done to emulate Aborting the previous work on a new miss
+ // Needed for serial calculators like GHB
if (serialSquash) {
iter = pf.end();
iter--;
while (!pf.empty() && ((*iter)->time >= time)) {
pfSquashed++;
- pf.pop_back();
+ DPRINTF(HWPrefetch, "Squashing old prefetch addr: 0x%x\n",
+ (*iter)->getAddr());
+ delete (*iter)->req;
+ delete (*iter);
+ pf.erase(iter);
iter--;
}
if (pf.empty())
@@ -191,74 +213,70 @@ BasePrefetcher::handleMiss(PacketPtr &pkt, Tick time)
std::list<Tick> delays;
calculatePrefetch(pkt, addresses, delays);
- std::list<Addr>::iterator addr = addresses.begin();
- std::list<Tick>::iterator delay = delays.begin();
- while (addr != addresses.end())
- {
- DPRINTF(HWPrefetch, "%s:Found a pf canidate, inserting into prefetch queue\n", cache->name());
- //temp calc this here...
+ std::list<Addr>::iterator addrIter = addresses.begin();
+ std::list<Tick>::iterator delayIter = delays.begin();
+ for (; addrIter != addresses.end(); ++addrIter, ++delayIter) {
+ Addr addr = *addrIter;
+
pfIdentified++;
- //create a prefetch memreq
- Request * prefetchReq = new Request(*addr, blkSize, 0);
- PacketPtr prefetch;
- prefetch = new Packet(prefetchReq, MemCmd::HardPFReq, -1);
- prefetch->allocate();
- prefetch->req->setThreadContext(pkt->req->getCpuNum(),
- pkt->req->getThreadNum());
-
- prefetch->time = time + (*delay); //@todo ADD LATENCY HERE
- //... initialize
-
- //Check if it is already in the cache
- if (cacheCheckPush) {
- if (cache->inCache(prefetch->getAddr())) {
- addr++;
- delay++;
- continue;
- }
+
+ DPRINTF(HWPrefetch, "Found a pf candidate addr: 0x%x, "
+ "inserting into prefetch queue with delay %d time %d\n",
+ addr, *delayIter, time);
+
+ // Check if it is already in the cache
+ if (cacheCheckPush && cache->inCache(addr)) {
+ DPRINTF(HWPrefetch, "Prefetch addr already in cache\n");
+ continue;
}
- //Check if it is already in the miss_queue
- if (cache->inMissQueue(prefetch->getAddr())) {
- addr++;
- delay++;
+ // Check if it is already in the miss_queue
+ if (cache->inMissQueue(addr)) {
+ DPRINTF(HWPrefetch, "Prefetch addr already in miss queue\n");
continue;
}
- //Check if it is already in the pf buffer
- if (inPrefetch(prefetch->getAddr()) != pf.end()) {
+ // Check if it is already in the pf buffer
+ if (inPrefetch(addr) != pf.end()) {
pfBufferHit++;
- addr++;
- delay++;
+ DPRINTF(HWPrefetch, "Prefetch addr already in pf buffer\n");
continue;
}
- //We just remove the head if we are full
- if (pf.size() == size)
- {
- DPRINTF(HWPrefetch, "%s:Inserting into prefetch queue, it was full removing oldest\n", cache->name());
+ // create a prefetch memreq
+ Request *prefetchReq = new Request(*addrIter, blkSize, 0);
+ PacketPtr prefetch =
+ new Packet(prefetchReq, MemCmd::HardPFReq, Packet::Broadcast);
+ prefetch->allocate();
+ prefetch->req->setThreadContext(pkt->req->contextId(),
+ pkt->req->threadId());
+
+ prefetch->time = time + (*delayIter); // @todo ADD LATENCY HERE
+
+ // We just remove the head if we are full
+ if (pf.size() == size) {
pfRemovedFull++;
+ PacketPtr old_pkt = *pf.begin();
+ DPRINTF(HWPrefetch, "Prefetch queue full, "
+ "removing oldest 0x%x\n", old_pkt->getAddr());
+ delete old_pkt->req;
+ delete old_pkt;
pf.pop_front();
}
pf.push_back(prefetch);
-
- //Make sure to request the bus, with proper delay
- cache->requestMemSideBus(BaseCache::Request_PF, prefetch->time);
-
- //Increment through the list
- addr++;
- delay++;
}
}
+
+ return pf.empty() ? 0 : pf.front()->time;
}
std::list<PacketPtr>::iterator
BasePrefetcher::inPrefetch(Addr address)
{
- //Guaranteed to only be one match, we always check before inserting
+ // Guaranteed to only be one match, we always check before inserting
std::list<PacketPtr>::iterator iter;
- for (iter=pf.begin(); iter != pf.end(); iter++) {
+ for (iter = pf.begin(); iter != pf.end(); iter++) {
if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) {
return iter;
}
@@ -266,4 +284,8 @@ BasePrefetcher::inPrefetch(Addr address)
return pf.end();
}
-
+bool
+BasePrefetcher::samePage(Addr a, Addr b)
+{
+ return roundDown(a, TheISA::VMPageSize) == roundDown(b, TheISA::VMPageSize);
+}
diff --git a/src/mem/cache/prefetch/base.hh b/src/mem/cache/prefetch/base.hh
index 1515d8a93..fc027cb3b 100644
--- a/src/mem/cache/prefetch/base.hh
+++ b/src/mem/cache/prefetch/base.hh
@@ -73,30 +73,40 @@ class BasePrefetcher
bool cacheCheckPush;
/** Do we prefetch on only data reads, or on inst reads as well. */
- bool only_data;
+ bool onlyData;
+
+ std::string _name;
public:
- Stats::Scalar<> pfIdentified;
- Stats::Scalar<> pfMSHRHit;
- Stats::Scalar<> pfCacheHit;
- Stats::Scalar<> pfBufferHit;
- Stats::Scalar<> pfRemovedFull;
- Stats::Scalar<> pfRemovedMSHR;
- Stats::Scalar<> pfIssued;
- Stats::Scalar<> pfSpanPage;
- Stats::Scalar<> pfSquashed;
+ Stats::Scalar pfIdentified;
+ Stats::Scalar pfMSHRHit;
+ Stats::Scalar pfCacheHit;
+ Stats::Scalar pfBufferHit;
+ Stats::Scalar pfRemovedFull;
+ Stats::Scalar pfRemovedMSHR;
+ Stats::Scalar pfIssued;
+ Stats::Scalar pfSpanPage;
+ Stats::Scalar pfSquashed;
void regStats(const std::string &name);
public:
+
BasePrefetcher(const BaseCacheParams *p);
virtual ~BasePrefetcher() {}
+ const std::string name() const { return _name; }
+
void setCache(BaseCache *_cache);
- void handleMiss(PacketPtr &pkt, Tick time);
+ /**
+ * Notify prefetcher of cache access (may be any access or just
+ * misses, depending on cache parameters.)
+ * @retval Time of next prefetch availability, or 0 if none.
+ */
+ Tick notify(PacketPtr &pkt, Tick time);
bool inCache(Addr addr);
@@ -109,11 +119,21 @@ class BasePrefetcher
return !pf.empty();
}
+ Tick nextPrefetchReadyTime()
+ {
+ return pf.empty() ? MaxTick : pf.front()->time;
+ }
+
virtual void calculatePrefetch(PacketPtr &pkt,
std::list<Addr> &addresses,
std::list<Tick> &delays) = 0;
std::list<PacketPtr>::iterator inPrefetch(Addr address);
+
+ /**
+ * Utility function: are addresses a and b on the same VM page?
+ */
+ bool samePage(Addr a, Addr b);
};
diff --git a/src/mem/cache/prefetch/ghb.cc b/src/mem/cache/prefetch/ghb.cc
index f5b88e1a6..f8f7de1db 100644
--- a/src/mem/cache/prefetch/ghb.cc
+++ b/src/mem/cache/prefetch/ghb.cc
@@ -34,39 +34,37 @@
* GHB Prefetcher implementation.
*/
+#include "base/trace.hh"
#include "mem/cache/prefetch/ghb.hh"
-#include "arch/isa_traits.hh"
void
GHBPrefetcher::calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses,
std::list<Tick> &delays)
{
- Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1);
- int cpuID = pkt->req->getCpuNum();
- if (!useCPUId) cpuID = 0;
+ if (useContextId && !pkt->req->hasContextId()) {
+ DPRINTF(HWPrefetch, "ignoring request with no context ID");
+ return;
+ }
+ Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1);
+ int ctx_id = useContextId ? pkt->req->contextId() : 0;
+ assert(ctx_id < Max_Contexts);
- int new_stride = blkAddr - last_miss_addr[cpuID];
- int old_stride = last_miss_addr[cpuID] -
- second_last_miss_addr[cpuID];
+ int new_stride = blk_addr - lastMissAddr[ctx_id];
+ int old_stride = lastMissAddr[ctx_id] - secondLastMissAddr[ctx_id];
- second_last_miss_addr[cpuID] = last_miss_addr[cpuID];
- last_miss_addr[cpuID] = blkAddr;
+ secondLastMissAddr[ctx_id] = lastMissAddr[ctx_id];
+ lastMissAddr[ctx_id] = blk_addr;
if (new_stride == old_stride) {
- for (int d=1; d <= degree; d++) {
- Addr newAddr = blkAddr + d * new_stride;
- if (this->pageStop &&
- (blkAddr & ~(TheISA::VMPageSize - 1)) !=
- (newAddr & ~(TheISA::VMPageSize - 1)))
- {
- //Spanned the page, so now stop
- this->pfSpanPage += degree - d + 1;
+ for (int d = 1; d <= degree; d++) {
+ Addr new_addr = blk_addr + d * new_stride;
+ if (pageStop && !samePage(blk_addr, new_addr)) {
+ // Spanned the page, so now stop
+ pfSpanPage += degree - d + 1;
return;
- }
- else
- {
- addresses.push_back(newAddr);
+ } else {
+ addresses.push_back(new_addr);
delays.push_back(latency);
}
}
diff --git a/src/mem/cache/prefetch/ghb.hh b/src/mem/cache/prefetch/ghb.hh
index 4fb692016..c85221a39 100644
--- a/src/mem/cache/prefetch/ghb.hh
+++ b/src/mem/cache/prefetch/ghb.hh
@@ -42,18 +42,20 @@ class GHBPrefetcher : public BasePrefetcher
{
protected:
- Addr second_last_miss_addr[64/*MAX_CPUS*/];
- Addr last_miss_addr[64/*MAX_CPUS*/];
+ static const int Max_Contexts = 64;
+
+ Addr secondLastMissAddr[Max_Contexts];
+ Addr lastMissAddr[Max_Contexts];
Tick latency;
int degree;
- bool useCPUId;
+ bool useContextId;
public:
GHBPrefetcher(const BaseCacheParams *p)
: BasePrefetcher(p), latency(p->prefetch_latency),
- degree(p->prefetch_degree), useCPUId(p->prefetch_use_cpu_id)
+ degree(p->prefetch_degree), useContextId(p->prefetch_use_cpu_id)
{
}
diff --git a/src/mem/cache/prefetch/stride.cc b/src/mem/cache/prefetch/stride.cc
index b116b66c7..8af4e615e 100644
--- a/src/mem/cache/prefetch/stride.cc
+++ b/src/mem/cache/prefetch/stride.cc
@@ -34,59 +34,97 @@
* Stride Prefetcher template instantiations.
*/
+#include "base/trace.hh"
#include "mem/cache/prefetch/stride.hh"
void
StridePrefetcher::calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses,
std::list<Tick> &delays)
{
-// Addr blkAddr = pkt->paddr & ~(Addr)(this->blkSize-1);
- int cpuID = pkt->req->getCpuNum();
- if (!useCPUId) cpuID = 0;
-
- /* Scan Table for IAddr Match */
-/* std::list<strideEntry*>::iterator iter;
- for (iter=table[cpuID].begin();
- iter !=table[cpuID].end();
- iter++) {
- if ((*iter)->IAddr == pkt->pc) break;
- }
-
- if (iter != table[cpuID].end()) {
- //Hit in table
-
- int newStride = blkAddr - (*iter)->MAddr;
- if (newStride == (*iter)->stride) {
- (*iter)->confidence++;
- }
- else {
- (*iter)->stride = newStride;
- (*iter)->confidence--;
- }
-
- (*iter)->MAddr = blkAddr;
-
- for (int d=1; d <= degree; d++) {
- Addr newAddr = blkAddr + d * newStride;
- if (this->pageStop &&
- (blkAddr & ~(TheISA::VMPageSize - 1)) !=
- (newAddr & ~(TheISA::VMPageSize - 1)))
- {
- //Spanned the page, so now stop
- this->pfSpanPage += degree - d + 1;
- return;
- }
- else
- {
- addresses.push_back(newAddr);
- delays.push_back(latency);
- }
- }
- }
- else {
- //Miss in table
- //Find lowest confidence and replace
-
- }
-*/
+ if (!pkt->req->hasPC()) {
+ DPRINTF(HWPrefetch, "ignoring request with no PC");
+ return;
+ }
+
+ if (useContextId && !pkt->req->hasContextId()) {
+ DPRINTF(HWPrefetch, "ignoring request with no context ID");
+ return;
+ }
+
+ Addr blk_addr = pkt->getAddr() & ~(Addr)(blkSize-1);
+ int ctx_id = useContextId ? pkt->req->contextId() : 0;
+ Addr pc = pkt->req->getPC();
+ assert(ctx_id < Max_Contexts);
+ std::list<StrideEntry*> &tab = table[ctx_id];
+
+ /* Scan Table for instAddr Match */
+ std::list<StrideEntry*>::iterator iter;
+ for (iter = tab.begin(); iter != tab.end(); iter++) {
+ if ((*iter)->instAddr == pc)
+ break;
+ }
+
+ if (iter != tab.end()) {
+ // Hit in table
+
+ int new_stride = blk_addr - (*iter)->missAddr;
+ bool stride_match = (new_stride == (*iter)->stride);
+
+ if (stride_match && new_stride != 0) {
+ if ((*iter)->confidence < Max_Conf)
+ (*iter)->confidence++;
+ } else {
+ (*iter)->stride = new_stride;
+ if ((*iter)->confidence > Min_Conf)
+ (*iter)->confidence = 0;
+ }
+
+ DPRINTF(HWPrefetch, "hit: PC %x blk_addr %x stride %d (%s), conf %d\n",
+ pc, blk_addr, new_stride, stride_match ? "match" : "change",
+ (*iter)->confidence);
+
+ (*iter)->missAddr = blk_addr;
+
+ if ((*iter)->confidence <= 0)
+ return;
+
+ for (int d = 1; d <= degree; d++) {
+ Addr new_addr = blk_addr + d * new_stride;
+ if (pageStop && !samePage(blk_addr, new_addr)) {
+ // Spanned the page, so now stop
+ pfSpanPage += degree - d + 1;
+ return;
+ } else {
+ DPRINTF(HWPrefetch, " queuing prefetch to %x @ %d\n",
+ new_addr, latency);
+ addresses.push_back(new_addr);
+ delays.push_back(latency);
+ }
+ }
+ } else {
+ // Miss in table
+ // Find lowest confidence and replace
+
+ DPRINTF(HWPrefetch, "miss: PC %x blk_addr %x\n", pc, blk_addr);
+
+ if (tab.size() >= 256) { //set default table size is 256
+ std::list<StrideEntry*>::iterator min_pos = tab.begin();
+ int min_conf = (*min_pos)->confidence;
+ for (iter = min_pos, ++iter; iter != tab.end(); ++iter) {
+ if ((*iter)->confidence < min_conf){
+ min_pos = iter;
+ min_conf = (*iter)->confidence;
+ }
+ }
+ DPRINTF(HWPrefetch, " replacing PC %x\n", (*min_pos)->instAddr);
+ tab.erase(min_pos);
+ }
+
+ StrideEntry *new_entry = new StrideEntry;
+ new_entry->instAddr = pc;
+ new_entry->missAddr = blk_addr;
+ new_entry->stride = 0;
+ new_entry->confidence = 0;
+ tab.push_back(new_entry);
+ }
}
diff --git a/src/mem/cache/prefetch/stride.hh b/src/mem/cache/prefetch/stride.hh
index f6bdbc424..6ccd32b91 100644
--- a/src/mem/cache/prefetch/stride.hh
+++ b/src/mem/cache/prefetch/stride.hh
@@ -36,41 +36,41 @@
#ifndef __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
#define __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
+#include <limits.h>
#include "mem/cache/prefetch/base.hh"
class StridePrefetcher : public BasePrefetcher
{
protected:
- class strideEntry
+ static const int Max_Contexts = 64;
+
+ // These constants need to be changed with the type of the
+ // 'confidence' field below.
+ static const int Max_Conf = INT_MAX;
+ static const int Min_Conf = INT_MIN;
+
+ class StrideEntry
{
public:
- Addr IAddr;
- Addr MAddr;
+ Addr instAddr;
+ Addr missAddr;
int stride;
- int64_t confidence;
-
-/* bool operator < (strideEntry a,strideEntry b)
- {
- if (a.confidence == b.confidence) {
- return true; //??????
- }
- else return a.confidence < b.confidence;
- }*/
+ int confidence;
};
- Addr* lastMissAddr[64/*MAX_CPUS*/];
- std::list<strideEntry*> table[64/*MAX_CPUS*/];
+ Addr *lastMissAddr[Max_Contexts];
+
+ std::list<StrideEntry*> table[Max_Contexts];
Tick latency;
int degree;
- bool useCPUId;
-
+ bool useContextId;
public:
StridePrefetcher(const BaseCacheParams *p)
: BasePrefetcher(p), latency(p->prefetch_latency),
- degree(p->prefetch_degree), useCPUId(p->prefetch_use_cpu_id)
+ degree(p->prefetch_degree), useContextId(p->prefetch_use_cpu_id)
{
}
diff --git a/src/mem/cache/prefetch/tagged.cc b/src/mem/cache/prefetch/tagged.cc
index 6afe1c6c2..a6c2403ba 100644
--- a/src/mem/cache/prefetch/tagged.cc
+++ b/src/mem/cache/prefetch/tagged.cc
@@ -47,20 +47,15 @@ TaggedPrefetcher::
calculatePrefetch(PacketPtr &pkt, std::list<Addr> &addresses,
std::list<Tick> &delays)
{
- Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1);
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
- for (int d=1; d <= degree; d++) {
- Addr newAddr = blkAddr + d*(this->blkSize);
- if (this->pageStop &&
- (blkAddr & ~(TheISA::VMPageSize - 1)) !=
- (newAddr & ~(TheISA::VMPageSize - 1)))
- {
- //Spanned the page, so now stop
- this->pfSpanPage += degree - d + 1;
+ for (int d = 1; d <= degree; d++) {
+ Addr newAddr = blkAddr + d*(blkSize);
+ if (pageStop && !samePage(blkAddr, newAddr)) {
+ // Spanned the page, so now stop
+ pfSpanPage += degree - d + 1;
return;
- }
- else
- {
+ } else {
addresses.push_back(newAddr);
delays.push_back(latency);
}
diff --git a/src/mem/cache/tags/SConscript b/src/mem/cache/tags/SConscript
index 9153d97e7..7255e0b7e 100644
--- a/src/mem/cache/tags/SConscript
+++ b/src/mem/cache/tags/SConscript
@@ -34,13 +34,9 @@ Source('base.cc')
Source('fa_lru.cc')
Source('iic.cc')
Source('lru.cc')
-Source('split.cc')
-Source('split_lifo.cc')
-Source('split_lru.cc')
SimObject('iic_repl/Repl.py')
Source('iic_repl/gen.cc')
TraceFlag('IIC')
TraceFlag('IICMore')
-TraceFlag('Split')
diff --git a/src/mem/cache/tags/base.hh b/src/mem/cache/tags/base.hh
index b7b0c7ef0..46c7186b1 100644
--- a/src/mem/cache/tags/base.hh
+++ b/src/mem/cache/tags/base.hh
@@ -70,19 +70,19 @@ class BaseTags
*/
/** Number of replacements of valid blocks per thread. */
- Stats::Vector<> replacements;
+ Stats::Vector replacements;
/** Per cycle average of the number of tags that hold valid data. */
- Stats::Average<> tagsInUse;
+ Stats::Average tagsInUse;
/** The total number of references to a block before it is replaced. */
- Stats::Scalar<> totalRefs;
+ Stats::Scalar totalRefs;
/**
* The number of reference counts sampled. This is different from
* replacements because we sample all the valid blocks when the simulator
* exits.
*/
- Stats::Scalar<> sampledRefs;
+ Stats::Scalar sampledRefs;
/**
* Average number of references to a block before is was replaced.
@@ -91,7 +91,7 @@ class BaseTags
Stats::Formula avgRefs;
/** The cycle that the warmup percentage was hit. */
- Stats::Scalar<> warmupCycle;
+ Stats::Scalar warmupCycle;
/**
* @}
*/
diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
index 607e89a75..f92d4cb37 100644
--- a/src/mem/cache/tags/fa_lru.cc
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -144,14 +144,6 @@ FALRU::hashLookup(Addr addr) const
return NULL;
}
-bool
-FALRU::probe(Addr addr) const
-{
- Addr blkAddr = blkAlign(addr);
- FALRUBlk* blk = hashLookup(blkAddr);
- return blk && blk->tag == blkAddr && blk->isValid();
-}
-
void
FALRU::invalidateBlk(FALRU::BlkType *blk)
{
@@ -163,7 +155,7 @@ FALRU::invalidateBlk(FALRU::BlkType *blk)
}
FALRUBlk*
-FALRU::findBlock(Addr addr, int &lat, int *inCache)
+FALRU::accessBlock(Addr addr, int &lat, int *inCache)
{
accesses++;
int tmp_in_cache = 0;
@@ -215,7 +207,7 @@ FALRU::findBlock(Addr addr) const
}
FALRUBlk*
-FALRU::findReplacement(Addr addr, PacketList &writebacks)
+FALRU::findVictim(Addr addr, PacketList &writebacks)
{
FALRUBlk * blk = tail;
assert(blk->inCache == 0);
@@ -237,6 +229,11 @@ FALRU::findReplacement(Addr addr, PacketList &writebacks)
}
void
+FALRU::insertBlock(Addr addr, FALRU::BlkType *blk)
+{
+}
+
+void
FALRU::moveToHead(FALRUBlk *blk)
{
int updateMask = blk->inCache ^ cacheMask;
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
index cabcf18b4..4eab10c49 100644
--- a/src/mem/cache/tags/fa_lru.hh
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -139,11 +139,11 @@ class FALRU : public BaseTags
*/
/** Hits in each cache size >= 128K. */
- Stats::Vector<> hits;
+ Stats::Vector hits;
/** Misses in each cache size >= 128K. */
- Stats::Vector<> misses;
+ Stats::Vector misses;
/** Total number of accesses. */
- Stats::Scalar<> accesses;
+ Stats::Scalar accesses;
/**
* @}
@@ -165,29 +165,23 @@ public:
void regStats(const std::string &name);
/**
- * Return true if the address is found in the cache.
- * @param asid The address space ID.
- * @param addr The address to look for.
- * @return True if the address is in the cache.
- */
- bool probe(Addr addr) const;
-
- /**
* Invalidate a cache block.
* @param blk The block to invalidate.
*/
void invalidateBlk(BlkType *blk);
/**
- * Find the block in the cache and update the replacement data. Returns
- * the access latency and the in cache flags as a side effect
+ * Access block and update replacement data. May not succeed, in which case
+ * NULL pointer is returned. This has all the implications of a cache
+ * access and should only be used as such.
+ * Returns the access latency and inCache flags as a side effect.
* @param addr The address to look for.
* @param asid The address space ID.
* @param lat The latency of the access.
* @param inCache The FALRUBlk::inCache flags.
* @return Pointer to the cache block.
*/
- FALRUBlk* findBlock(Addr addr, int &lat, int *inCache = 0);
+ FALRUBlk* accessBlock(Addr addr, int &lat, int *inCache = 0);
/**
* Find the block in the cache, do not update the replacement data.
@@ -203,7 +197,9 @@ public:
* @param writebacks List for any writebacks to be performed.
* @return The block to place the replacement in.
*/
- FALRUBlk* findReplacement(Addr addr, PacketList & writebacks);
+ FALRUBlk* findVictim(Addr addr, PacketList & writebacks);
+
+ void insertBlock(Addr addr, BlkType *blk);
/**
* Return the hit latency of this cache.
@@ -283,31 +279,6 @@ public:
{
return (tag);
}
-
- /**
- * Read the data out of the internal storage of a cache block. FALRU
- * currently doesn't support data storage.
- * @param blk The cache block to read.
- * @param data The buffer to read the data into.
- * @return The data from the cache block.
- */
- void readData(FALRUBlk *blk, uint8_t *data)
- {
- }
-
- /**
- * Write data into the internal storage of a cache block. FALRU
- * currently doesn't support data storage.
- * @param blk The cache block to be written.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(FALRUBlk *blk, uint8_t *data, int size,
- PacketList &writebacks)
- {
- }
};
#endif
diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc
index 2825599f6..7bc2543c5 100644
--- a/src/mem/cache/tags/iic.cc
+++ b/src/mem/cache/tags/iic.cc
@@ -219,15 +219,9 @@ IIC::regStats(const string &name)
;
}
-// probe cache for presence of given block.
-bool
-IIC::probe(Addr addr) const
-{
- return (findBlock(addr) != NULL);
-}
IICTag*
-IIC::findBlock(Addr addr, int &lat)
+IIC::accessBlock(Addr addr, int &lat)
{
Addr tag = extractTag(addr);
unsigned set = hash(addr);
@@ -303,7 +297,7 @@ IIC::findBlock(Addr addr) const
IICTag*
-IIC::findReplacement(Addr addr, PacketList &writebacks)
+IIC::findVictim(Addr addr, PacketList &writebacks)
{
DPRINTF(IIC, "Finding Replacement for %x\n", addr);
unsigned set = hash(addr);
@@ -346,6 +340,11 @@ IIC::findReplacement(Addr addr, PacketList &writebacks)
}
void
+IIC::insertBlock(Addr addr, BlkType* blk)
+{
+}
+
+void
IIC::freeReplacementBlock(PacketList & writebacks)
{
IICTag *tag_ptr;
@@ -365,7 +364,7 @@ IIC::freeReplacementBlock(PacketList & writebacks)
tag_ptr->refCount = 0;
if (tag_ptr->isDirty()) {
-/* PacketPtr writeback =
+/* PacketPtr writeback =
buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
tag_ptr->req->asid, tag_ptr->xc, blkSize,
tag_ptr->data,
@@ -635,66 +634,6 @@ IIC::invalidateBlk(IIC::BlkType *tag_ptr)
}
void
-IIC::readData(IICTag *blk, uint8_t *data)
-{
- assert(blk->size <= trivialSize || blk->numData > 0);
- int data_size = blk->size;
- if (data_size > trivialSize) {
- for (int i = 0; i < blk->numData; ++i){
- memcpy(data+i*subSize,
- &(dataBlks[blk->data_ptr[i]][0]),
- (data_size>subSize)?subSize:data_size);
- data_size -= subSize;
- }
- } else {
- memcpy(data,blk->trivialData,data_size);
- }
-}
-
-void
-IIC::writeData(IICTag *blk, uint8_t *write_data, int size,
- PacketList & writebacks)
-{
- DPRINTF(IIC, "Writing %d bytes to %x\n", size,
- blk->tag<<tagShift);
- // Find the number of subblocks needed, (round up)
- int num_subs = (size + (subSize -1))/subSize;
- if (size <= trivialSize) {
- num_subs = 0;
- }
- assert(num_subs <= numSub);
- if (num_subs > blk->numData) {
- // need to allocate more data blocks
- for (int i = blk->numData; i < num_subs; ++i){
- blk->data_ptr[i] = getFreeDataBlock(writebacks);
- dataReferenceCount[blk->data_ptr[i]] += 1;
- }
- } else if (num_subs < blk->numData){
- // can free data blocks
- for (int i=num_subs; i < blk->numData; ++i){
- // decrement reference count and compare to zero
- if (--dataReferenceCount[blk->data_ptr[i]] == 0) {
- freeDataBlock(blk->data_ptr[i]);
- }
- }
- }
-
- blk->numData = num_subs;
- blk->size = size;
- assert(size <= trivialSize || blk->numData > 0);
- if (size > trivialSize){
- for (int i = 0; i < blk->numData; ++i){
- memcpy(&dataBlks[blk->data_ptr[i]][0], write_data + i*subSize,
- (size>subSize)?subSize:size);
- size -= subSize;
- }
- } else {
- memcpy(blk->trivialData,write_data,size);
- }
-}
-
-
-void
IIC::cleanupRefs()
{
for (int i = 0; i < numTags; ++i) {
diff --git a/src/mem/cache/tags/iic.hh b/src/mem/cache/tags/iic.hh
index c9d080683..45c8ee801 100644
--- a/src/mem/cache/tags/iic.hh
+++ b/src/mem/cache/tags/iic.hh
@@ -248,20 +248,20 @@ class IIC : public BaseTags
*/
/** Hash hit depth of cache hits. */
- Stats::Distribution<> hitHashDepth;
+ Stats::Distribution hitHashDepth;
/** Hash depth for cache misses. */
- Stats::Distribution<> missHashDepth;
+ Stats::Distribution missHashDepth;
/** Count of accesses to each hash set. */
- Stats::Distribution<> setAccess;
+ Stats::Distribution setAccess;
/** The total hash depth for every miss. */
- Stats::Scalar<> missDepthTotal;
+ Stats::Scalar missDepthTotal;
/** The total hash depth for all hits. */
- Stats::Scalar<> hitDepthTotal;
+ Stats::Scalar hitDepthTotal;
/** The number of hash misses. */
- Stats::Scalar<> hashMiss;
+ Stats::Scalar hashMiss;
/** The number of hash hits. */
- Stats::Scalar<> hashHit;
+ Stats::Scalar hashHit;
/** @} */
public:
@@ -385,14 +385,6 @@ class IIC : public BaseTags
}
/**
- * Check for the address in the tagstore.
- * @param asid The address space ID.
- * @param addr The address to find.
- * @return true if it is found.
- */
- bool probe(Addr addr) const;
-
- /**
* Swap the position of two tags.
* @param index1 The first tag location.
* @param index2 The second tag location.
@@ -418,14 +410,16 @@ class IIC : public BaseTags
void invalidateBlk(BlkType *blk);
/**
- * Find the block and update the replacement data. This call also returns
- * the access latency as a side effect.
+ * Access block and update replacement data. May not succeed, in which case
+ * NULL pointer is returned. This has all the implications of a cache
+ * access and should only be used as such.
+ * Returns the access latency and inCache flags as a side effect.
* @param addr The address to find.
* @param asid The address space ID.
* @param lat The access latency.
* @return A pointer to the block found, if any.
*/
- IICTag* findBlock(Addr addr, int &lat);
+ IICTag* accessBlock(Addr addr, int &lat);
/**
* Find the block, do not update the replacement data.
@@ -441,31 +435,15 @@ class IIC : public BaseTags
* @param writebacks List for any writebacks to be performed.
* @return The block to place the replacement in.
*/
- IICTag* findReplacement(Addr addr, PacketList &writebacks);
+ IICTag* findVictim(Addr addr, PacketList &writebacks);
- /**
- * Read the data from the internal storage of the given cache block.
- * @param blk The block to read the data from.
- * @param data The buffer to read the data into.
- * @return The cache block's data.
- */
- void readData(IICTag *blk, uint8_t *data);
-
- /**
- * Write the data into the internal storage of the given cache block.
- * @param blk The block to write to.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(IICTag *blk, uint8_t *data, int size,
- PacketList & writebacks);
+ void insertBlock(Addr addr, BlkType *blk);
/**
* Called at end of simulation to complete average block reference stats.
*/
virtual void cleanupRefs();
+
private:
/**
* Return the hash of the address.
diff --git a/src/mem/cache/tags/iic_repl/gen.hh b/src/mem/cache/tags/iic_repl/gen.hh
index 22436b384..fe105d95a 100644
--- a/src/mem/cache/tags/iic_repl/gen.hh
+++ b/src/mem/cache/tags/iic_repl/gen.hh
@@ -162,11 +162,11 @@ class GenRepl : public Repl
* @{
*/
/** The number of replacements from each pool. */
- Stats::Distribution<> repl_pool;
+ Stats::Distribution repl_pool;
/** The number of advances out of each pool. */
- Stats::Distribution<> advance_pool;
+ Stats::Distribution advance_pool;
/** The number of demotions from each pool. */
- Stats::Distribution<> demote_pool;
+ Stats::Distribution demote_pool;
/**
* @}
*/
diff --git a/src/mem/cache/tags/lru.cc b/src/mem/cache/tags/lru.cc
index 7f352e9c4..ff353ff6a 100644
--- a/src/mem/cache/tags/lru.cc
+++ b/src/mem/cache/tags/lru.cc
@@ -113,7 +113,7 @@ LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
// allocate data storage in one big chunk
dataBlks = new uint8_t[numSets*assoc*blkSize];
- blkIndex = 0; // index into blks array
+ blkIndex = 0; // index into blks array
for (i = 0; i < numSets; ++i) {
sets[i].assoc = assoc;
@@ -150,21 +150,8 @@ LRU::~LRU()
delete [] sets;
}
-// probe cache for presence of given block.
-bool
-LRU::probe(Addr addr) const
-{
- // return(findBlock(Read, addr, asid) != 0);
- Addr tag = extractTag(addr);
- unsigned myset = extractSet(addr);
-
- LRUBlk *blk = sets[myset].findBlk(tag);
-
- return (blk != NULL); // true if in cache
-}
-
LRUBlk*
-LRU::findBlock(Addr addr, int &lat)
+LRU::accessBlock(Addr addr, int &lat)
{
Addr tag = extractTag(addr);
unsigned set = extractSet(addr);
@@ -196,12 +183,11 @@ LRU::findBlock(Addr addr) const
}
LRUBlk*
-LRU::findReplacement(Addr addr, PacketList &writebacks)
+LRU::findVictim(Addr addr, PacketList &writebacks)
{
unsigned set = extractSet(addr);
// grab a replacement candidate
LRUBlk *blk = sets[set].blks[assoc-1];
- sets[set].moveToHead(blk);
if (blk->isValid()) {
replacements[0]++;
totalRefs += blk->refCount;
@@ -210,7 +196,14 @@ LRU::findReplacement(Addr addr, PacketList &writebacks)
DPRINTF(CacheRepl, "set %x: selecting blk %x for replacement\n",
set, regenerateBlkAddr(blk->tag, set));
- } else if (!blk->isTouched) {
+ }
+ return blk;
+}
+
+void
+LRU::insertBlock(Addr addr, LRU::BlkType *blk)
+{
+ if (!blk->isTouched) {
tagsInUse++;
blk->isTouched = true;
if (!warmedUp && tagsInUse.value() >= warmupBound) {
@@ -219,7 +212,11 @@ LRU::findReplacement(Addr addr, PacketList &writebacks)
}
}
- return blk;
+ // Set tag for new block. Caller is responsible for setting status.
+ blk->tag = extractTag(addr);
+
+ unsigned set = extractSet(addr);
+ sets[set].moveToHead(blk);
}
void
diff --git a/src/mem/cache/tags/lru.hh b/src/mem/cache/tags/lru.hh
index ea5606cde..7b6e95e84 100644
--- a/src/mem/cache/tags/lru.hh
+++ b/src/mem/cache/tags/lru.hh
@@ -127,7 +127,7 @@ public:
* @param _assoc The associativity of the cache.
* @param _hit_latency The latency in cycles for a hit.
*/
- LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency);
+ LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency);
/**
* Destructor
@@ -154,31 +154,25 @@ public:
}
/**
- * Search for the address in the cache.
- * @param asid The address space ID.
- * @param addr The address to find.
- * @return True if the address is in the cache.
- */
- bool probe(Addr addr) const;
-
- /**
* Invalidate the given block.
* @param blk The block to invalidate.
*/
void invalidateBlk(BlkType *blk);
/**
- * Finds the given address in the cache and update replacement data.
- * Returns the access latency as a side effect.
+ * Access block and update replacement data. May not succeed, in which case
+ * NULL pointer is returned. This has all the implications of a cache
+ * access and should only be used as such. Returns the access latency as a side effect.
* @param addr The address to find.
* @param asid The address space ID.
* @param lat The access latency.
* @return Pointer to the cache block if found.
*/
- LRUBlk* findBlock(Addr addr, int &lat);
+ LRUBlk* accessBlock(Addr addr, int &lat);
/**
* Finds the given address in the cache, do not update replacement data.
+ * i.e. This is a no-side-effect find of a block.
* @param addr The address to find.
* @param asid The address space ID.
* @return Pointer to the cache block if found.
@@ -186,12 +180,20 @@ public:
LRUBlk* findBlock(Addr addr) const;
/**
- * Find a replacement block for the address provided.
- * @param pkt The request to a find a replacement candidate for.
+ * Find a block to evict for the address provided.
+ * @param addr The addr to a find a replacement candidate for.
* @param writebacks List for any writebacks to be performed.
- * @return The block to place the replacement in.
+ * @return The candidate block.
*/
- LRUBlk* findReplacement(Addr addr, PacketList &writebacks);
+ LRUBlk* findVictim(Addr addr, PacketList &writebacks);
+
+ /**
+ * Insert the new block into the cache. For LRU this means inserting into
+ * the MRU position of the set.
+ * @param addr The address to update.
+ * @param blk The block to update.
+ */
+ void insertBlock(Addr addr, BlkType *blk);
/**
* Generate the tag from the given address.
@@ -254,33 +256,6 @@ public:
}
/**
- * Read the data out of the internal storage of the given cache block.
- * @param blk The cache block to read.
- * @param data The buffer to read the data into.
- * @return The cache block's data.
- */
- void readData(LRUBlk *blk, uint8_t *data)
- {
- std::memcpy(data, blk->data, blk->size);
- }
-
- /**
- * Write data into the internal storage of the given cache block. Since in
- * LRU does not store data differently this just needs to update the size.
- * @param blk The cache block to write.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(LRUBlk *blk, uint8_t *data, int size,
- PacketList & writebacks)
- {
- assert(size <= blkSize);
- blk->size = size;
- }
-
- /**
* Called at end of simulation to complete average block reference stats.
*/
virtual void cleanupRefs();
diff --git a/src/mem/cache/tags/split.cc b/src/mem/cache/tags/split.cc
deleted file mode 100644
index 0df85cc92..000000000
--- a/src/mem/cache/tags/split.cc
+++ /dev/null
@@ -1,420 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Definitions of split cache tag store.
- */
-
-#include <string>
-#include <iostream>
-#include <fstream>
-
-#include "base/cprintf.hh"
-#include "base/intmath.hh"
-#include "base/output.hh"
-#include "base/trace.hh"
-#include "mem/cache/base.hh"
-#include "mem/cache/tags/split.hh"
-#include "mem/cache/tags/split_lifo.hh"
-#include "mem/cache/tags/split_lru.hh"
-
-
-using namespace std;
-using namespace TheISA;
-
-// create and initialize a partitioned cache structure
-Split::Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
- bool _lifo, bool _two_queue, int _hit_latency) :
- numSets(_numSets), blkSize(_blkSize), lifo(_lifo), hitLatency(_hit_latency)
-{
- DPRINTF(Split, "new split cache!!\n");
-
- DPRINTF(Split, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n",
- numSets, blkSize, LRU1_assoc, hitLatency);
-
- lru = new SplitLRU(_numSets, _blkSize, LRU1_assoc, _hit_latency, 1);
-
- if (total_ways - LRU1_assoc == 0) {
- lifo_net = NULL;
- lru_net = NULL;
- } else {
- if (lifo) {
- DPRINTF(Split, "Other partition is a LIFO with size %d in bytes. it gets %d ways\n",
- (total_ways - LRU1_assoc)*_numSets*_blkSize, (total_ways - LRU1_assoc));
- lifo_net = new SplitLIFO(_blkSize, (total_ways - LRU1_assoc)*_numSets*_blkSize,
- (total_ways - LRU1_assoc), _hit_latency, _two_queue, 2);
- lru_net = NULL;
- }
- else {
- DPRINTF(Split, "other LRU gets %d ways\n", total_ways - LRU1_assoc);
- lru_net = new SplitLRU(_numSets, _blkSize, total_ways - LRU1_assoc, _hit_latency, 2);
- lifo_net = NULL;
- }
- }
-
- blkMask = blkSize - 1;
-
- if (!isPowerOf2(total_ways))
- warn("total cache ways/columns %d should be power of 2",
- total_ways);
-
- warmedUp = false;
- /** @todo Make warmup percentage a parameter. */
- warmupBound = numSets * total_ways;
-
-}
-
-Split::~Split()
-{
- delete lru;
- if (lifo)
- delete lifo_net;
- else
- delete lru_net;
-}
-
-void
-Split::regStats(const string &name)
-{
- using namespace Stats;
-
- BaseTags::regStats(name);
-
- usedEvictDist.init(0,3000,40);
- unusedEvictDist.init(0,3000,40);
- useByCPUCycleDist.init(0,35,1);
-
- nic_repl
- .name(name + ".nic_repl")
- .desc("number of replacements in the nic partition")
- .precision(0)
- ;
-
- cpu_repl
- .name(name + ".cpu_repl")
- .desc("number of replacements in the cpu partition")
- .precision(0)
- ;
-
- lru->regStats(name + ".lru");
-
- if (lifo && lifo_net) {
- lifo_net->regStats(name + ".lifo_net");
- } else if (lru_net) {
- lru_net->regStats(name + ".lru_net");
- }
-
- nicUsedWhenEvicted
- .name(name + ".nicUsedWhenEvicted")
- .desc("number of NIC blks that were used before evicted")
- ;
-
- nicUsedTotLatency
- .name(name + ".nicUsedTotLatency")
- .desc("total cycles before eviction of used NIC blks")
- ;
-
- nicUsedTotEvicted
- .name(name + ".nicUsedTotEvicted")
- .desc("total number of used NIC blks evicted")
- ;
-
- nicUsedAvgLatency
- .name(name + ".nicUsedAvgLatency")
- .desc("avg number of cycles a used NIC blk is in cache")
- .precision(0)
- ;
- nicUsedAvgLatency = nicUsedTotLatency / nicUsedTotEvicted;
-
- usedEvictDist
- .name(name + ".usedEvictDist")
- .desc("distribution of used NIC blk eviction times")
- .flags(pdf | cdf)
- ;
-
- nicUnusedWhenEvicted
- .name(name + ".nicUnusedWhenEvicted")
- .desc("number of NIC blks that were unused when evicted")
- ;
-
- nicUnusedTotLatency
- .name(name + ".nicUnusedTotLatency")
- .desc("total cycles before eviction of unused NIC blks")
- ;
-
- nicUnusedTotEvicted
- .name(name + ".nicUnusedTotEvicted")
- .desc("total number of unused NIC blks evicted")
- ;
-
- nicUnusedAvgLatency
- .name(name + ".nicUnusedAvgLatency")
- .desc("avg number of cycles an unused NIC blk is in cache")
- .precision(0)
- ;
- nicUnusedAvgLatency = nicUnusedTotLatency / nicUnusedTotEvicted;
-
- unusedEvictDist
- .name(name + ".unusedEvictDist")
- .desc("distribution of unused NIC blk eviction times")
- .flags(pdf | cdf)
- ;
-
- nicUseByCPUCycleTotal
- .name(name + ".nicUseByCPUCycleTotal")
- .desc("total latency of NIC blks til usage time")
- ;
-
- nicBlksUsedByCPU
- .name(name + ".nicBlksUsedByCPU")
- .desc("total number of NIC blks used")
- ;
-
- nicAvgUsageByCPULatency
- .name(name + ".nicAvgUsageByCPULatency")
- .desc("average number of cycles before a NIC blk that is used gets used")
- .precision(0)
- ;
- nicAvgUsageByCPULatency = nicUseByCPUCycleTotal / nicBlksUsedByCPU;
-
- useByCPUCycleDist
- .name(name + ".useByCPUCycleDist")
- .desc("the distribution of cycle time in cache before NIC blk is used")
- .flags(pdf | cdf)
- ;
-
- cpuUsedBlks
- .name(name + ".cpuUsedBlks")
- .desc("number of cpu blks that were used before evicted")
- ;
-
- cpuUnusedBlks
- .name(name + ".cpuUnusedBlks")
- .desc("number of cpu blks that were unused before evicted")
- ;
-
- nicAvgLatency
- .name(name + ".nicAvgLatency")
- .desc("avg number of cycles a NIC blk is in cache before evicted")
- .precision(0)
- ;
- nicAvgLatency = (nicUnusedTotLatency + nicUsedTotLatency) /
- (nicUnusedTotEvicted + nicUsedTotEvicted);
-
- NR_CP_hits
- .name(name + ".NR_CP_hits")
- .desc("NIC requests hitting in CPU Partition")
- ;
-
- NR_NP_hits
- .name(name + ".NR_NP_hits")
- .desc("NIC requests hitting in NIC Partition")
- ;
-
- CR_CP_hits
- .name(name + ".CR_CP_hits")
- .desc("CPU requests hitting in CPU partition")
- ;
-
- CR_NP_hits
- .name(name + ".CR_NP_hits")
- .desc("CPU requests hitting in NIC partition")
- ;
-
-}
-
-// probe cache for presence of given block.
-bool
-Split::probe(Addr addr) const
-{
- bool success = lru->probe(addr);
- if (!success) {
- if (lifo && lifo_net)
- success = lifo_net->probe(addr);
- else if (lru_net)
- success = lru_net->probe(addr);
- }
-
- return success;
-}
-
-
-SplitBlk*
-Split::findBlock(Addr addr, int &lat)
-{
- SplitBlk *blk = lru->findBlock(addr, lat);
- if (!blk) {
- if (lifo && lifo_net) {
- blk = lifo_net->findBlock(addr, lat);
- } else if (lru_net) {
- blk = lru_net->findBlock(addr, lat);
- }
- }
-
- return blk;
-}
-
-SplitBlk*
-Split::findBlock(Addr addr) const
-{
- SplitBlk *blk = lru->findBlock(addr);
- if (!blk) {
- if (lifo && lifo_net) {
- blk = lifo_net->findBlock(addr);
- } else if (lru_net) {
- blk = lru_net->findBlock(addr);
- }
- }
-
- return blk;
-}
-
-SplitBlk*
-Split::findReplacement(Addr addr, PacketList &writebacks)
-{
- SplitBlk *blk = NULL;
-
- assert(0);
-#if 0
- if (pkt->nic_pkt()) {
- DPRINTF(Split, "finding a replacement for nic_req\n");
- nic_repl++;
- if (lifo && lifo_net)
- blk = lifo_net->findReplacement(addr, writebacks);
- else if (lru_net)
- blk = lru_net->findReplacement(addr, writebacks);
- // in this case, this is an LRU only cache, it's non partitioned
- else
- blk = lru->findReplacement(addr, writebacks);
- } else {
- DPRINTF(Split, "finding replacement for cpu_req\n");
- blk = lru->findReplacement(addr, writebacks);
- cpu_repl++;
- }
-
- Tick latency = curTick - blk->ts;
- if (blk->isNIC) {
- if (blk->isUsed) {
- nicUsedWhenEvicted++;
- usedEvictDist.sample(latency);
- nicUsedTotLatency += latency;
- nicUsedTotEvicted++;
- } else {
- nicUnusedWhenEvicted++;
- unusedEvictDist.sample(latency);
- nicUnusedTotLatency += latency;
- nicUnusedTotEvicted++;
- }
- } else {
- if (blk->isUsed) {
- cpuUsedBlks++;
- } else {
- cpuUnusedBlks++;
- }
- }
-
- // blk attributes for the new blk coming IN
- blk->ts = curTick;
- blk->isNIC = (pkt->nic_pkt()) ? true : false;
-#endif
-
- return blk;
-}
-
-void
-Split::invalidateBlk(Split::BlkType *blk)
-{
- if (!blk) {
- fatal("FIXME!\n");
-#if 0
- if (lifo && lifo_net)
- blk = lifo_net->findBlock(addr);
- else if (lru_net)
- blk = lru_net->findBlock(addr);
-#endif
-
- if (!blk)
- return;
- }
-
- blk->status = 0;
- blk->isTouched = false;
- tagsInUse--;
-}
-
-void
-Split::cleanupRefs()
-{
- lru->cleanupRefs();
- if (lifo && lifo_net)
- lifo_net->cleanupRefs();
- else if (lru_net)
- lru_net->cleanupRefs();
-
- ofstream memPrint(simout.resolve("memory_footprint.txt").c_str(),
- ios::trunc);
-
- // this shouldn't be here but it happens at the end, which is what i want
- memIter end = memHash.end();
- for (memIter iter = memHash.begin(); iter != end; ++iter) {
- ccprintf(memPrint, "%8x\t%d\n", (*iter).first, (*iter).second);
- }
-}
-
-Addr
-Split::regenerateBlkAddr(Addr tag, int set) const
-{
- if (lifo_net)
- return lifo_net->regenerateBlkAddr(tag, set);
- else
- return lru->regenerateBlkAddr(tag, set);
-}
-
-Addr
-Split::extractTag(Addr addr) const
-{
- // need to fix this if we want to use it... old interface of
- // passing in blk was too weird
- assert(0);
- return 0;
-/*
- if (blk->part == 2) {
- if (lifo_net)
- return lifo_net->extractTag(addr);
- else if (lru_net)
- return lru_net->extractTag(addr);
- else
- panic("this shouldn't happen");
- } else
- return lru->extractTag(addr);
-*/
-}
-
diff --git a/src/mem/cache/tags/split.hh b/src/mem/cache/tags/split.hh
deleted file mode 100644
index e8954f791..000000000
--- a/src/mem/cache/tags/split.hh
+++ /dev/null
@@ -1,308 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Declaration of a split/partitioned tag store.
- */
-
-#ifndef __SPLIT_HH__
-#define __SPLIT_HH__
-
-#include <cstring>
-#include <list>
-
-#include "mem/cache/blk.hh" // base class
-#include "mem/cache/tags/split_blk.hh"
-#include "mem/packet.hh" // for inlined functions
-#include <assert.h>
-#include "mem/cache/tags/base.hh"
-#include "base/hashmap.hh"
-
-class BaseCache;
-class SplitLRU;
-class SplitLIFO;
-
-/**
- * A cache tag store.
- */
-class Split : public BaseTags
-{
- public:
- /** Typedef the block type used in this tag store. */
- typedef SplitBlk BlkType;
- /** Typedef for a list of pointers to the local block class. */
- typedef std::list<SplitBlk*> BlkList;
- protected:
- /** The number of sets in the cache. */
- const int numSets;
- /** The number of bytes in a block. */
- const int blkSize;
- /** Whether the 2nd partition (for the nic) is LIFO or not */
- const bool lifo;
- /** The hit latency. */
- const int hitLatency;
-
- Addr blkMask;
-
- /** Number of NIC requests that hit in the NIC partition */
- Stats::Scalar<> NR_NP_hits;
- /** Number of NIC requests that hit in the CPU partition */
- Stats::Scalar<> NR_CP_hits;
- /** Number of CPU requests that hit in the NIC partition */
- Stats::Scalar<> CR_NP_hits;
- /** Number of CPU requests that hit in the CPU partition */
- Stats::Scalar<> CR_CP_hits;
- /** The number of nic replacements (i.e. misses) */
- Stats::Scalar<> nic_repl;
- /** The number of cpu replacements (i.e. misses) */
- Stats::Scalar<> cpu_repl;
-
- //For latency studies
- /** the number of NIC blks that were used before evicted */
- Stats::Scalar<> nicUsedWhenEvicted;
- /** the total latency of used NIC blocks in the cache */
- Stats::Scalar<> nicUsedTotLatency;
- /** the total number of used NIC blocks evicted */
- Stats::Scalar<> nicUsedTotEvicted;
- /** the average number of cycles a used NIC blk is in the cache */
- Stats::Formula nicUsedAvgLatency;
- /** the Distribution of used NIC blk eviction times */
- Stats::Distribution<> usedEvictDist;
-
- /** the number of NIC blks that were unused before evicted */
- Stats::Scalar<> nicUnusedWhenEvicted;
- /** the total latency of unused NIC blks in the cache */
- Stats::Scalar<> nicUnusedTotLatency;
- /** the total number of unused NIC blocks evicted */
- Stats::Scalar<> nicUnusedTotEvicted;
- /** the average number of cycles an unused NIC blk is in the cache */
- Stats::Formula nicUnusedAvgLatency;
- /** the Distribution of unused NIC blk eviction times */
- Stats::Distribution<> unusedEvictDist;
-
- /** The total latency of NIC blocks to 1st usage time by CPU */
- Stats::Scalar<> nicUseByCPUCycleTotal;
- /** The total number of NIC blocks used */
- Stats::Scalar<> nicBlksUsedByCPU;
- /** the average number of cycles before a NIC blk that is used gets used by CPU */
- Stats::Formula nicAvgUsageByCPULatency;
- /** the Distribution of cycles time before a NIC blk is used by CPU*/
- Stats::Distribution<> useByCPUCycleDist;
-
- /** the number of CPU blks that were used before evicted */
- Stats::Scalar<> cpuUsedBlks;
- /** the number of CPU blks that were unused before evicted */
- Stats::Scalar<> cpuUnusedBlks;
-
- /** the avg number of cycles before a NIC blk is evicted */
- Stats::Formula nicAvgLatency;
-
- typedef m5::hash_map<Addr, int, m5::hash<Addr> > hash_t;
- typedef hash_t::const_iterator memIter;
- hash_t memHash;
-
-
- private:
- SplitLRU *lru;
- SplitLRU *lru_net;
- SplitLIFO *lifo_net;
-
- public:
- /**
- * Construct and initialize this tag store.
- * @param _numSets The number of sets in the cache.
- * @param _blkSize The number of bytes in a block.
- * @param _assoc The associativity of the cache.
- * @param _hit_latency The latency in cycles for a hit.
- */
- Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
- bool _lifo, bool _two_queue, int _hit_latency);
-
- /**
- * Destructor
- */
- virtual ~Split();
-
- /**
- * Register the stats for this object
- * @param name The name to prepend to the stats name.
- */
- void regStats(const std::string &name);
-
- /**
- * Return the block size.
- * @return the block size.
- */
- int getBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Return the subblock size. In the case of Split it is always the block
- * size.
- * @return The block size.
- */
- int getSubBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Search for the address in the cache.
- * @param asid The address space ID.
- * @param addr The address to find.
- * @return True if the address is in the cache.
- */
- bool probe(Addr addr) const;
-
- /**
- * Invalidate the given block.
- * @param blk The block to invalidate.
- */
- void invalidateBlk(BlkType *blk);
-
- /**
- * Finds the given address in the cache and update replacement data.
- * Returns the access latency as a side effect.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @param lat The access latency.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr, int &lat);
-
- /**
- * Finds the given address in the cache, do not update replacement data.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr) const;
-
- /**
- * Find a replacement block for the address provided.
- * @param pkt The request to a find a replacement candidate for.
- * @param writebacks List for any writebacks to be performed.
- * @return The block to place the replacement in.
- */
- SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
-
-
- /**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr) const;
-
- /**
- * Calculate the set index from the address.
- * @param addr The address to get the set from.
- * @return The set index of the address.
- */
- int extractSet(Addr addr) const
- {
- panic("should never call this!\n");
- M5_DUMMY_RETURN
- }
-
- /**
- * Get the block offset from an address.
- * @param addr The address to get the offset of.
- * @return The block offset.
- */
- int extractBlkOffset(Addr addr) const
- {
- return (addr & blkMask);
- }
-
- /**
- * Align an address to the block size.
- * @param addr the address to align.
- * @return The block address.
- */
- Addr blkAlign(Addr addr) const
- {
- return (addr & ~(Addr) (blkMask));
- }
-
- /**
- * Regenerate the block address from the tag.
- * @param tag The tag of the block.
- * @param set The set of the block.
- * @return The block address.
- */
- Addr regenerateBlkAddr(Addr tag, int set) const;
-
- /**
- * Return the hit latency.
- * @return the hit latency.
- */
- int getHitLatency() const
- {
- return hitLatency;
- }
-
- /**
- * Read the data out of the internal storage of the given cache block.
- * @param blk The cache block to read.
- * @param data The buffer to read the data into.
- * @return The cache block's data.
- */
- void readData(SplitBlk *blk, uint8_t *data)
- {
- std::memcpy(data, blk->data, blk->size);
- }
-
- /**
- * Write data into the internal storage of the given cache block. Since in
- * Split does not store data differently this just needs to update the size.
- * @param blk The cache block to write.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(SplitBlk *blk, uint8_t *data, int size,
- PacketList & writebacks)
- {
- assert(size <= blkSize);
- blk->size = size;
- }
-
- /**
- * Called at end of simulation to complete average block reference stats.
- */
- virtual void cleanupRefs();
-};
-
-#endif
diff --git a/src/mem/cache/tags/split_blk.hh b/src/mem/cache/tags/split_blk.hh
deleted file mode 100644
index d2efe08df..000000000
--- a/src/mem/cache/tags/split_blk.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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Declaration of partitioned tag store cache block class.
- */
-
-#ifndef __SPLIT_BLK_HH__
-#define __SPLIT_BLK_HH__
-
-#include "mem/cache/blk.hh" // base class
-
-/**
- * Split cache block.
- */
-class SplitBlk : public CacheBlk {
- public:
- /** Has this block been touched? Used to aid calculation of warmup time. */
- bool isTouched;
- /** Has this block been used after being brought in? (for LIFO partition) */
- bool isUsed;
- /** is this blk a NIC block? (i.e. requested by the NIC) */
- bool isNIC;
- /** timestamp of the arrival of this block into the cache */
- Tick ts;
- /** the previous block in the LIFO partition (brought in before than me) */
- SplitBlk *prev;
- /** the next block in the LIFO partition (brought in later than me) */
- SplitBlk *next;
- /** which partition this block is in */
- int part;
-
- SplitBlk()
- : isTouched(false), isUsed(false), isNIC(false), ts(0), prev(NULL), next(NULL),
- part(0)
- {}
-};
-
-#endif
-
diff --git a/src/mem/cache/tags/split_lifo.cc b/src/mem/cache/tags/split_lifo.cc
deleted file mode 100644
index 3bdc7cae9..000000000
--- a/src/mem/cache/tags/split_lifo.cc
+++ /dev/null
@@ -1,331 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Definitions of LIFO tag store usable in a partitioned cache.
- */
-
-#include <string>
-
-#include "mem/cache/base.hh"
-#include "base/intmath.hh"
-#include "mem/cache/tags/split_lifo.hh"
-#include "sim/core.hh"
-#include "base/trace.hh"
-
-using namespace std;
-
-SplitBlk*
-LIFOSet::findBlk(Addr tag) const
-{
- for (SplitBlk *blk = firstIn; blk != NULL; blk = blk->next) {
- if (blk->tag == tag && blk->isValid()) {
- return blk;
- }
- }
- return NULL;
-}
-
-void
-LIFOSet::moveToLastIn(SplitBlk *blk)
-{
- if (blk == lastIn)
- return;
-
- if (blk == firstIn) {
- blk->next->prev = NULL;
- } else {
- blk->prev->next = blk->next;
- blk->next->prev = blk->prev;
- }
- blk->next = NULL;
- blk->prev = lastIn;
- lastIn->next = blk;
-
- lastIn = blk;
-}
-
-void
-LIFOSet::moveToFirstIn(SplitBlk *blk)
-{
- if (blk == firstIn)
- return;
-
- if (blk == lastIn) {
- blk->prev->next = NULL;
- } else {
- blk->next->prev = blk->prev;
- blk->prev->next = blk->next;
- }
-
- blk->prev = NULL;
- blk->next = firstIn;
- firstIn->prev = blk;
-
- firstIn = blk;
-}
-
-// create and initialize a LIFO cache structure
-SplitLIFO::SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool two_Queue, int _part) :
- blkSize(_blkSize), size(_size), numBlks(_size/_blkSize), numSets((_size/_ways)/_blkSize), ways(_ways),
- hitLatency(_hit_latency), twoQueue(two_Queue), part(_part)
-{
- if (!isPowerOf2(blkSize))
- fatal("cache block size (in bytes) must be a power of 2");
- if (!(hitLatency > 0))
- fatal("access latency in cycles must be at least on cycle");
- if (_ways == 0)
- fatal("if instantiating a splitLIFO, needs non-zero size!");
-
-
- SplitBlk *blk;
- int i, j, blkIndex;
-
- setShift = floorLog2(blkSize);
- blkMask = blkSize - 1;
- setMask = numSets - 1;
- tagShift = setShift + floorLog2(numSets);
-
- warmedUp = false;
- /** @todo Make warmup percentage a parameter. */
- warmupBound = size/blkSize;
-
- // allocate data blocks
- blks = new SplitBlk[numBlks];
- sets = new LIFOSet[numSets];
- dataBlks = new uint8_t[size];
-
-/*
- // these start off point to same blk
- top = &(blks[0]);
- head = top;
-*/
-
- blkIndex = 0;
- for (i=0; i < numSets; ++i) {
- sets[i].ways = ways;
- sets[i].lastIn = &blks[blkIndex];
- sets[i].firstIn = &blks[blkIndex + ways - 1];
-
- /* 3 cases: if there is 1 way, if there are 2 ways, or if there are 3+.
- in the case of 1 way, last in and first out point to the same blocks,
- and the next and prev pointers need to be assigned specially. and so on
- */
- /* deal with the first way */
- blk = &blks[blkIndex];
- blk->prev = &blks[blkIndex + 1];
- blk->next = NULL;
- blk->data = &dataBlks[blkSize*blkIndex];
- blk->size = blkSize;
- blk->part = part;
- blk->set = i;
- ++blkIndex;
-
- /* if there are "middle" ways, do them here */
- if (ways > 2) {
- for (j=1; j < ways-1; ++j) {
- blk = &blks[blkIndex];
- blk->data = &dataBlks[blkSize*blkIndex];
- blk->prev = &blks[blkIndex+1];
- blk->next = &blks[blkIndex-1];
- blk->data = &(dataBlks[blkSize*blkIndex]);
- blk->size = blkSize;
- blk->part = part;
- blk->set = i;
- ++blkIndex;
- }
- }
-
- /* do the final way here, depending on whether the final way is the only
- way or not
- */
- if (ways > 1) {
- blk = &blks[blkIndex];
- blk->prev = NULL;
- blk->next = &blks[blkIndex - 1];
- blk->data = &dataBlks[blkSize*blkIndex];
- blk->size = blkSize;
- blk->part = part;
- blk->set = i;
- ++blkIndex;
- } else {
- blk->prev = NULL;
- }
- }
- assert(blkIndex == numBlks);
-}
-
-SplitLIFO::~SplitLIFO()
-{
- delete [] blks;
- delete [] sets;
- delete [] dataBlks;
-}
-
-void
-SplitLIFO::regStats(const std::string &name)
-{
- BaseTags::regStats(name);
-
- hits
- .name(name + ".hits")
- .desc("number of hits on this partition")
- .precision(0)
- ;
-
- misses
- .name(name + ".misses")
- .desc("number of misses in this partition")
- .precision(0)
- ;
-
- invalidations
- .name(name + ".invalidations")
- .desc("number of invalidations in this partition")
- .precision(0)
- ;
-}
-
-// probe cache for presence of given block.
-bool
-SplitLIFO::probe(Addr addr) const
-{
- Addr tag = extractTag(addr);
- unsigned myset = extractSet(addr);
-
- SplitBlk* blk = sets[myset].findBlk(tag);
- return (blk != NULL);
-}
-
-SplitBlk*
-SplitLIFO::findBlock(Addr addr, int &lat)
-{
- Addr tag = extractTag(addr);
- unsigned set = extractSet(addr);
- SplitBlk *blk = sets[set].findBlk(tag);
-
- lat = hitLatency;
-
- if (blk) {
- DPRINTF(Split, "Found LIFO blk %#x in set %d, with tag %#x\n",
- addr, set, tag);
- hits++;
-
- if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency)
- lat = blk->whenReady - curTick;
- blk->refCount +=1;
-
- if (twoQueue) {
- blk->isUsed = true;
- sets[set].moveToFirstIn(blk);
- } else {
- sets[set].moveToLastIn(blk);
- }
- }
-
- return blk;
-}
-
-
-SplitBlk*
-SplitLIFO::findBlock(Addr addr) const
-{
- Addr tag = extractTag(addr);
- unsigned set = extractSet(addr);
- SplitBlk *blk = sets[set].findBlk(tag);
-
- return blk;
-}
-
-SplitBlk*
-SplitLIFO::findReplacement(Addr addr, PacketList &writebacks)
-{
- unsigned set = extractSet(addr);
-
- SplitBlk *firstIn = sets[set].firstIn;
- SplitBlk *lastIn = sets[set].lastIn;
-
- SplitBlk *blk;
- if (twoQueue && firstIn->isUsed) {
- blk = firstIn;
- blk->isUsed = false;
- sets[set].moveToLastIn(blk);
- } else {
- int withValue = sets[set].withValue;
- if (withValue == ways) {
- blk = lastIn;
- } else {
- blk = &(sets[set].firstIn[ways - ++withValue]);
- }
- }
-
- DPRINTF(Split, "just assigned %#x addr into LIFO, replacing %#x status %#x\n",
- addr, regenerateBlkAddr(blk->tag, set), blk->status);
- if (blk->isValid()) {
- replacements[0]++;
- totalRefs += blk->refCount;
- ++sampledRefs;
- blk->refCount = 0;
- } else {
- tagsInUse++;
- blk->isTouched = true;
- if (!warmedUp && tagsInUse.value() >= warmupBound) {
- warmedUp = true;
- warmupCycle = curTick;
- }
- }
-
- misses++;
-
- return blk;
-}
-
-void
-SplitLIFO::invalidateBlk(SplitLIFO::BlkType *blk)
-{
- if (blk) {
- blk->status = 0;
- blk->isTouched = false;
- tagsInUse--;
- invalidations++;
- }
-}
-
-void
-SplitLIFO::cleanupRefs()
-{
- for (int i = 0; i < numBlks; ++i) {
- if (blks[i].isValid()) {
- totalRefs += blks[i].refCount;
- ++sampledRefs;
- }
- }
-}
diff --git a/src/mem/cache/tags/split_lifo.hh b/src/mem/cache/tags/split_lifo.hh
deleted file mode 100644
index 0fd5f5c3c..000000000
--- a/src/mem/cache/tags/split_lifo.hh
+++ /dev/null
@@ -1,312 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Declaration of a LIFO tag store usable in a partitioned cache.
- */
-
-#ifndef __SPLIT_LIFO_HH__
-#define __SPLIT_LIFO_HH__
-
-#include <cstring>
-#include <list>
-
-#include "mem/cache/blk.hh" // base class
-#include "mem/cache/tags/split_blk.hh"
-#include "mem/packet.hh" // for inlined functions
-#include "base/hashmap.hh"
-#include <assert.h>
-#include "mem/cache/tags/base.hh"
-
-class BaseCache;
-
-/**
- * A LIFO set of cache blks
- */
-class LIFOSet {
- public:
- /** the number of blocks in this set */
- int ways;
-
- /** Cache blocks in this set, maintained in LIFO order where
- 0 = Last in (head) */
- SplitBlk *lastIn;
- SplitBlk *firstIn;
-
- /** has the initial "filling" of this set finished? i.e., have you had
- * 'ways' number of compulsory misses in this set yet? if withValue == ways,
- * then yes. withValue is meant to be the number of blocks in the set that have
- * gone through their first compulsory miss.
- */
- int withValue;
-
- /**
- * Find a block matching the tag in this set.
- * @param asid The address space ID.
- * @param tag the Tag you are looking for
- * @return Pointer to the block, if found, NULL otherwise
- */
- SplitBlk* findBlk(Addr tag) const;
-
- void moveToLastIn(SplitBlk *blk);
- void moveToFirstIn(SplitBlk *blk);
-
- LIFOSet()
- : ways(-1), lastIn(NULL), firstIn(NULL), withValue(0)
- {}
-};
-
-/**
- * A LIFO cache tag store.
- */
-class SplitLIFO : public BaseTags
-{
- public:
- /** Typedef the block type used in this tag store. */
- typedef SplitBlk BlkType;
- /** Typedef for a list of pointers to the local block class. */
- typedef std::list<SplitBlk*> BlkList;
- protected:
- /** The number of bytes in a block. */
- const int blkSize;
- /** the size of the cache in bytes */
- const int size;
- /** the number of blocks in the cache */
- const int numBlks;
- /** the number of sets in the cache */
- const int numSets;
- /** the number of ways in the cache */
- const int ways;
- /** The hit latency. */
- const int hitLatency;
- /** whether this is a "2 queue" replacement @sa moveToLastIn @sa moveToFirstIn */
- const bool twoQueue;
- /** indicator for which partition this is */
- const int part;
-
- /** The cache blocks. */
- SplitBlk *blks;
- /** The Cache sets */
- LIFOSet *sets;
- /** The data blocks, 1 per cache block. */
- uint8_t *dataBlks;
-
- /** The amount to shift the address to get the set. */
- int setShift;
- /** The amount to shift the address to get the tag. */
- int tagShift;
- /** Mask out all bits that aren't part of the set index. */
- unsigned setMask;
- /** Mask out all bits that aren't part of the block offset. */
- unsigned blkMask;
-
-
- /** the number of hit in this partition */
- Stats::Scalar<> hits;
- /** the number of blocks brought into this partition (i.e. misses) */
- Stats::Scalar<> misses;
- /** the number of invalidations in this partition */
- Stats::Scalar<> invalidations;
-
-public:
- /**
- * Construct and initialize this tag store.
- * @param _numSets The number of sets in the cache.
- * @param _blkSize The number of bytes in a block.
- * @param _assoc The associativity of the cache.
- * @param _hit_latency The latency in cycles for a hit.
- */
- SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool twoQueue, int _part);
-
- /**
- * Destructor
- */
- virtual ~SplitLIFO();
-
- /**
- * Register the statistics for this object
- * @param name The name to precede the stat
- */
- void regStats(const std::string &name);
-
- /**
- * Return the block size.
- * @return the block size.
- */
- int getBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Return the subblock size. In the case of LIFO it is always the block
- * size.
- * @return The block size.
- */
- int getSubBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Search for the address in the cache.
- * @param asid The address space ID.
- * @param addr The address to find.
- * @return True if the address is in the cache.
- */
- bool probe( Addr addr) const;
-
- /**
- * Invalidate the given block.
- * @param blk The block to invalidate.
- */
- void invalidateBlk(BlkType *blk);
-
- /**
- * Finds the given address in the cache and update replacement data.
- * Returns the access latency as a side effect.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @param lat The access latency.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr, int &lat);
-
- /**
- * Finds the given address in the cache, do not update replacement data.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr) const;
-
- /**
- * Find a replacement block for the address provided.
- * @param pkt The request to a find a replacement candidate for.
- * @param writebacks List for any writebacks to be performed.
- * @return The block to place the replacement in.
- */
- SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
-
- /**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr) const
- {
- return (addr >> tagShift);
- }
-
- /**
- * Calculate the set index from the address.
- * @param addr The address to get the set from.
- * @return The set index of the address.
- */
- int extractSet(Addr addr) const
- {
- return ((addr >> setShift) & setMask);
- }
-
- /**
- * Get the block offset from an address.
- * @param addr The address to get the offset of.
- * @return The block offset.
- */
- int extractBlkOffset(Addr addr) const
- {
- return (addr & blkMask);
- }
-
- /**
- * Align an address to the block size.
- * @param addr the address to align.
- * @return The block address.
- */
- Addr blkAlign(Addr addr) const
- {
- return (addr & ~(Addr)blkMask);
- }
-
- /**
- * Regenerate the block address from the tag.
- * @param tag The tag of the block.
- * @param set The set of the block.
- * @return The block address.
- */
- Addr regenerateBlkAddr(Addr tag, unsigned set) const
- {
- return ((tag << tagShift) | ((Addr)set << setShift));
- }
-
- /**
- * Return the hit latency.
- * @return the hit latency.
- */
- int getHitLatency() const
- {
- return hitLatency;
- }
-
- /**
- * Read the data out of the internal storage of the given cache block.
- * @param blk The cache block to read.
- * @param data The buffer to read the data into.
- * @return The cache block's data.
- */
- void readData(SplitBlk *blk, uint8_t *data)
- {
- std::memcpy(data, blk->data, blk->size);
- }
-
- /**
- * Write data into the internal storage of the given cache block. Since in
- * LIFO does not store data differently this just needs to update the size.
- * @param blk The cache block to write.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(SplitBlk *blk, uint8_t *data, int size,
- PacketList & writebacks)
- {
- assert(size <= blkSize);
- blk->size = size;
- }
-
- /**
- * Called at end of simulation to complete average block reference stats.
- */
- virtual void cleanupRefs();
-};
-
-#endif
diff --git a/src/mem/cache/tags/split_lru.cc b/src/mem/cache/tags/split_lru.cc
deleted file mode 100644
index bcccdcb30..000000000
--- a/src/mem/cache/tags/split_lru.cc
+++ /dev/null
@@ -1,260 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Definitions of LRU tag store for a partitioned cache.
- */
-
-#include <string>
-
-#include "mem/cache/base.hh"
-#include "base/intmath.hh"
-#include "mem/cache/tags/split_lru.hh"
-#include "sim/core.hh"
-
-using namespace std;
-
-SplitBlk*
-SplitCacheSet::findBlk(Addr tag) const
-{
- for (int i = 0; i < assoc; ++i) {
- if (blks[i]->tag == tag && blks[i]->isValid()) {
- return blks[i];
- }
- }
- return 0;
-}
-
-
-void
-SplitCacheSet::moveToHead(SplitBlk *blk)
-{
- // nothing to do if blk is already head
- if (blks[0] == blk)
- return;
-
- // write 'next' block into blks[i], moving up from MRU toward LRU
- // until we overwrite the block we moved to head.
-
- // start by setting up to write 'blk' into blks[0]
- int i = 0;
- SplitBlk *next = blk;
-
- do {
- assert(i < assoc);
- // swap blks[i] and next
- SplitBlk *tmp = blks[i];
- blks[i] = next;
- next = tmp;
- ++i;
- } while (next != blk);
-}
-
-
-// create and initialize a LRU/MRU cache structure
-SplitLRU::SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part) :
- numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency), part(_part)
-{
- // Check parameters
- if (blkSize < 4 || !isPowerOf2(blkSize)) {
- fatal("Block size must be at least 4 and a power of 2");
- }
- if (numSets <= 0 || !isPowerOf2(numSets)) {
- fatal("# of sets must be non-zero and a power of 2");
- }
- if (assoc <= 0) {
- fatal("associativity must be greater than zero");
- }
- if (hitLatency <= 0) {
- fatal("access latency must be greater than zero");
- }
-
- SplitBlk *blk;
- int i, j, blkIndex;
-
- blkMask = blkSize - 1;
- setShift = floorLog2(blkSize);
- setMask = numSets - 1;
- tagShift = setShift + floorLog2(numSets);
- warmedUp = false;
- /** @todo Make warmup percentage a parameter. */
- warmupBound = numSets * assoc;
-
- sets = new SplitCacheSet[numSets];
- blks = new SplitBlk[numSets * assoc];
- // allocate data storage in one big chunk
- dataBlks = new uint8_t[numSets*assoc*blkSize];
-
- blkIndex = 0; // index into blks array
- for (i = 0; i < numSets; ++i) {
- sets[i].assoc = assoc;
-
- sets[i].blks = new SplitBlk*[assoc];
-
- // link in the data blocks
- for (j = 0; j < assoc; ++j) {
- // locate next cache block
- blk = &blks[blkIndex];
- blk->data = &dataBlks[blkSize*blkIndex];
- ++blkIndex;
-
- // invalidate new cache block
- blk->status = 0;
-
- //EGH Fix Me : do we need to initialize blk?
-
- // Setting the tag to j is just to prevent long chains in the hash
- // table; won't matter because the block is invalid
- blk->tag = j;
- blk->whenReady = 0;
- blk->isTouched = false;
- blk->size = blkSize;
- sets[i].blks[j]=blk;
- blk->set = i;
- blk->part = part;
- }
- }
-}
-
-SplitLRU::~SplitLRU()
-{
- delete [] dataBlks;
- delete [] blks;
- delete [] sets;
-}
-
-void
-SplitLRU::regStats(const std::string &name)
-{
- BaseTags::regStats(name);
-
- hits
- .name(name + ".hits")
- .desc("number of hits on this partition")
- .precision(0)
- ;
-
- misses
- .name(name + ".misses")
- .desc("number of misses in this partition")
- .precision(0)
- ;
-}
-
-// probe cache for presence of given block.
-bool
-SplitLRU::probe(Addr addr) const
-{
- // return(findBlock(Read, addr, asid) != 0);
- Addr tag = extractTag(addr);
- unsigned myset = extractSet(addr);
-
- SplitBlk *blk = sets[myset].findBlk(tag);
-
- return (blk != NULL); // true if in cache
-}
-
-SplitBlk*
-SplitLRU::findBlock(Addr addr, int &lat)
-{
- Addr tag = extractTag(addr);
- unsigned set = extractSet(addr);
- SplitBlk *blk = sets[set].findBlk(tag);
- lat = hitLatency;
- if (blk != NULL) {
- // move this block to head of the MRU list
- sets[set].moveToHead(blk);
- if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency){
- lat = blk->whenReady - curTick;
- }
- blk->refCount += 1;
- hits++;
- }
-
- return blk;
-}
-
-
-SplitBlk*
-SplitLRU::findBlock(Addr addr) const
-{
- Addr tag = extractTag(addr);
- unsigned set = extractSet(addr);
- SplitBlk *blk = sets[set].findBlk(tag);
- return blk;
-}
-
-SplitBlk*
-SplitLRU::findReplacement(Addr addr, PacketList &writebacks)
-{
- unsigned set = extractSet(addr);
- // grab a replacement candidate
- SplitBlk *blk = sets[set].blks[assoc-1];
- sets[set].moveToHead(blk);
- if (blk->isValid()) {
- replacements[0]++;
- totalRefs += blk->refCount;
- ++sampledRefs;
- blk->refCount = 0;
- } else if (!blk->isTouched) {
- tagsInUse++;
- blk->isTouched = true;
- if (!warmedUp && tagsInUse.value() >= warmupBound) {
- warmedUp = true;
- warmupCycle = curTick;
- }
- }
-
- misses++;
-
- return blk;
-}
-
-void
-SplitLRU::invalidateBlk(SplitLRU::BlkType *blk)
-{
- if (blk) {
- blk->status = 0;
- blk->isTouched = false;
- tagsInUse--;
- }
-}
-
-void
-SplitLRU::cleanupRefs()
-{
- for (int i = 0; i < numSets*assoc; ++i) {
- if (blks[i].isValid()) {
- totalRefs += blks[i].refCount;
- ++sampledRefs;
- }
- }
-}
diff --git a/src/mem/cache/tags/split_lru.hh b/src/mem/cache/tags/split_lru.hh
deleted file mode 100644
index d41b6efa7..000000000
--- a/src/mem/cache/tags/split_lru.hh
+++ /dev/null
@@ -1,295 +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.
- *
- * Authors: Lisa Hsu
- */
-
-/**
- * @file
- * Declaration of a LRU tag store for a partitioned cache.
- */
-
-#ifndef __SPLIT_LRU_HH__
-#define __SPLIT_LRU_HH__
-
-#include <cstring>
-#include <list>
-
-#include "mem/cache/blk.hh" // base class
-#include "mem/cache/tags/split_blk.hh"
-#include "mem/packet.hh" // for inlined functions
-#include <assert.h>
-#include "mem/cache/tags/base.hh"
-
-class BaseCache;
-
-/**
- * An associative set of cache blocks.
- */
-
-class SplitCacheSet
-{
- public:
- /** The associativity of this set. */
- int assoc;
-
- /** Cache blocks in this set, maintained in LRU order 0 = MRU. */
- SplitBlk **blks;
-
- /**
- * Find a block matching the tag in this set.
- * @param asid The address space ID.
- * @param tag The Tag to find.
- * @return Pointer to the block if found.
- */
- SplitBlk* findBlk(Addr tag) const;
-
- /**
- * Move the given block to the head of the list.
- * @param blk The block to move.
- */
- void moveToHead(SplitBlk *blk);
-};
-
-/**
- * A LRU cache tag store.
- */
-class SplitLRU : public BaseTags
-{
- public:
- /** Typedef the block type used in this tag store. */
- typedef SplitBlk BlkType;
- /** Typedef for a list of pointers to the local block class. */
- typedef std::list<SplitBlk*> BlkList;
- protected:
- /** The number of sets in the cache. */
- const int numSets;
- /** The number of bytes in a block. */
- const int blkSize;
- /** The associativity of the cache. */
- const int assoc;
- /** The hit latency. */
- const int hitLatency;
- /** indicator for which partition this is */
- const int part;
-
- /** The cache sets. */
- SplitCacheSet *sets;
-
- /** The cache blocks. */
- SplitBlk *blks;
- /** The data blocks, 1 per cache block. */
- uint8_t *dataBlks;
-
- /** The amount to shift the address to get the set. */
- int setShift;
- /** The amount to shift the address to get the tag. */
- int tagShift;
- /** Mask out all bits that aren't part of the set index. */
- unsigned setMask;
- /** Mask out all bits that aren't part of the block offset. */
- unsigned blkMask;
-
- /** number of hits in this partition */
- Stats::Scalar<> hits;
- /** number of blocks brought into this partition (i.e. misses) */
- Stats::Scalar<> misses;
-
-public:
- /**
- * Construct and initialize this tag store.
- * @param _numSets The number of sets in the cache.
- * @param _blkSize The number of bytes in a block.
- * @param _assoc The associativity of the cache.
- * @param _hit_latency The latency in cycles for a hit.
- */
- SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part);
-
- /**
- * Destructor
- */
- virtual ~SplitLRU();
-
- /**
- * Register the statistics for this object
- * @param name The name to precede the stat
- */
- void regStats(const std::string &name);
-
- /**
- * Return the block size.
- * @return the block size.
- */
- int getBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Return the subblock size. In the case of LRU it is always the block
- * size.
- * @return The block size.
- */
- int getSubBlockSize()
- {
- return blkSize;
- }
-
- /**
- * Search for the address in the cache.
- * @param asid The address space ID.
- * @param addr The address to find.
- * @return True if the address is in the cache.
- */
- bool probe(Addr addr) const;
-
- /**
- * Invalidate the given block.
- * @param blk The block to invalidate.
- */
- void invalidateBlk(BlkType *blk);
-
- /**
- * Finds the given address in the cache and update replacement data.
- * Returns the access latency as a side effect.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @param lat The access latency.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr, int &lat);
-
- /**
- * Finds the given address in the cache, do not update replacement data.
- * @param addr The address to find.
- * @param asid The address space ID.
- * @return Pointer to the cache block if found.
- */
- SplitBlk* findBlock(Addr addr) const;
-
- /**
- * Find a replacement block for the address provided.
- * @param pkt The request to a find a replacement candidate for.
- * @param writebacks List for any writebacks to be performed.
- * @return The block to place the replacement in.
- */
- SplitBlk* findReplacement(Addr addr, PacketList &writebacks);
-
- /**
- * Generate the tag from the given address.
- * @param addr The address to get the tag from.
- * @return The tag of the address.
- */
- Addr extractTag(Addr addr) const
- {
- return (addr >> tagShift);
- }
-
- /**
- * Calculate the set index from the address.
- * @param addr The address to get the set from.
- * @return The set index of the address.
- */
- int extractSet(Addr addr) const
- {
- return ((addr >> setShift) & setMask);
- }
-
- /**
- * Get the block offset from an address.
- * @param addr The address to get the offset of.
- * @return The block offset.
- */
- int extractBlkOffset(Addr addr) const
- {
- return (addr & blkMask);
- }
-
- /**
- * Align an address to the block size.
- * @param addr the address to align.
- * @return The block address.
- */
- Addr blkAlign(Addr addr) const
- {
- return (addr & ~(Addr)blkMask);
- }
-
- /**
- * Regenerate the block address from the tag.
- * @param tag The tag of the block.
- * @param set The set of the block.
- * @return The block address.
- */
- Addr regenerateBlkAddr(Addr tag, unsigned set) const
- {
- return ((tag << tagShift) | ((Addr)set << setShift));
- }
-
- /**
- * Return the hit latency.
- * @return the hit latency.
- */
- int getHitLatency() const
- {
- return hitLatency;
- }
-
- /**
- * Read the data out of the internal storage of the given cache block.
- * @param blk The cache block to read.
- * @param data The buffer to read the data into.
- * @return The cache block's data.
- */
- void readData(SplitBlk *blk, uint8_t *data)
- {
- std::memcpy(data, blk->data, blk->size);
- }
-
- /**
- * Write data into the internal storage of the given cache block. Since in
- * LRU does not store data differently this just needs to update the size.
- * @param blk The cache block to write.
- * @param data The data to write.
- * @param size The number of bytes to write.
- * @param writebacks A list for any writebacks to be performed. May be
- * needed when writing to a compressed block.
- */
- void writeData(SplitBlk *blk, uint8_t *data, int size,
- PacketList & writebacks)
- {
- assert(size <= blkSize);
- blk->size = size;
- }
-
- /**
- * Called at end of simulation to complete average block reference stats.
- */
- virtual void cleanupRefs();
-};
-
-#endif
diff --git a/src/mem/config/cache.hh b/src/mem/config/cache.hh
index 24da04021..946ed444f 100644
--- a/src/mem/config/cache.hh
+++ b/src/mem/config/cache.hh
@@ -36,7 +36,4 @@
*/
#define USE_CACHE_LRU 1
#define USE_CACHE_FALRU 1
-// #define USE_CACHE_SPLIT 1
-// #define USE_CACHE_SPLIT_LIFO 1
#define USE_CACHE_IIC 1
-
diff --git a/src/mem/dram.cc b/src/mem/dram.cc
index 75146f9ed..ff01ab1dc 100644
--- a/src/mem/dram.cc
+++ b/src/mem/dram.cc
@@ -366,7 +366,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
int lat=0, temp=0, current_bank=0;
int current_row=0, current_device=0;
- int was_miss = 0; // determines if there was an active row miss this access
+ int was_miss = 0; // determines if there was an active row miss this access
//md_addr_t physic_address; /* linear memory address to be accessed */
Addr physic_address; /* linear memory address to be accessed */
@@ -415,7 +415,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
int SD_BEST_T_WRITE_WRITE_OBANK = 0; /* WAW, row miss/hit, another bank */
Tick time_since_last_access = curTick-time_last_access;
- Tick time_last_miss = 0; // used for keeping track of times between activations (page misses)
+ Tick time_last_miss = 0; // used for keeping track of times between activations (page misses)
//int was_idle = (curTick > busy_until);
bool srow_flag = false;
int timing_correction = 0;
@@ -433,7 +433,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
// SDRAM does not use the active_row array in closed_page mode
// TODO: handle closed page operation
- } else { // DRDRAM uses the active_row array
+ } else { // DRDRAM uses the active_row array
for( int i = 0; i < bank_max; i++ ) {
if( (active_row[current_bank] != row_max)) all_precharged = 0;
}
@@ -923,7 +923,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
}
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2034,7 +2034,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2226,7 +2226,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
/*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)curTick, overlap, lat);debug*/
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2468,7 +2468,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2525,7 +2525,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2593,7 +2593,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
}
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return lat;
}
@@ -2608,7 +2608,7 @@ DRAMMemory::calculateLatency(PacketPtr pkt)
assert(chunks >0);
// if((_cpu_num < num_cpus) && (_cpu_num >= 0))
// cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
- // bank_access_profile[_cpu_num][current_bank]++;
+ // bank_access_profile[_cpu_num][current_bank]++;
return(/* first chunk latency */act_lat +
(/* remainder chunk latency */cas_lat * (chunks - 1)));
}
diff --git a/src/mem/dram.hh b/src/mem/dram.hh
index 352ca96ae..1745fa52b 100644
--- a/src/mem/dram.hh
+++ b/src/mem/dram.hh
@@ -117,27 +117,27 @@ class DRAMMemory : public PhysicalMemory
Tick time_last_access;
- Stats::Vector<> accesses;
- Stats::Vector<> bytesRequested;
- Stats::Vector<> bytesSent;
- Stats::Vector<> compressedAccesses;
-
- Stats::Vector<> cycles_nCKE;
- Stats::Vector<> cycles_all_precharge_CKE;
- Stats::Vector<> cycles_all_precharge_nCKE;
- Stats::Vector<> cycles_bank_active_nCKE;
- Stats::Vector<> cycles_avg_ACT;
- Stats::Vector<> cycles_read_out;
- Stats::Vector<> cycles_write_in;
- Stats::Vector<> cycles_between_misses;
- Stats::Vector<> other_bank_read_access_miss;
- Stats::Vector<> other_bank_write_access_miss;
- Stats::Scalar<> total_latency;
- Stats::Scalar<> total_icache_req;
- Stats::Scalar<> total_arb_latency;
+ Stats::Vector accesses;
+ Stats::Vector bytesRequested;
+ Stats::Vector bytesSent;
+ Stats::Vector compressedAccesses;
+
+ Stats::Vector cycles_nCKE;
+ Stats::Vector cycles_all_precharge_CKE;
+ Stats::Vector cycles_all_precharge_nCKE;
+ Stats::Vector cycles_bank_active_nCKE;
+ Stats::Vector cycles_avg_ACT;
+ Stats::Vector cycles_read_out;
+ Stats::Vector cycles_write_in;
+ Stats::Vector cycles_between_misses;
+ Stats::Vector other_bank_read_access_miss;
+ Stats::Vector other_bank_write_access_miss;
+ Stats::Scalar total_latency;
+ Stats::Scalar total_icache_req;
+ Stats::Scalar total_arb_latency;
Stats::Formula avg_latency;
Stats::Formula avg_arb_latency;
- Stats::Vector2d<> bank_access_profile;
+ Stats::Vector2d bank_access_profile;
protected:
diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc
index ce2a1107e..20a1b4cd8 100644
--- a/src/mem/mem_object.cc
+++ b/src/mem/mem_object.cc
@@ -35,14 +35,6 @@ MemObject::MemObject(const Params *params)
{
}
-MemObjectParams *
-MemObject::makeParams(const std::string &name)
-{
- MemObjectParams *params = new MemObjectParams;
- params->name = name;
- return params;
-}
-
void
MemObject::deletePortRefs(Port *p)
{
diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh
index 33b56dfd4..b8bf4b939 100644
--- a/src/mem/mem_object.hh
+++ b/src/mem/mem_object.hh
@@ -48,17 +48,10 @@ class MemObject : public SimObject
{
public:
typedef MemObjectParams Params;
- MemObject(const Params *params);
-
- const Params *
- params() const
- {
- return dynamic_cast<const Params *>(_params);
- }
+ const Params *params() const
+ { return dynamic_cast<const Params *>(_params); }
- protected:
- // static: support for old-style constructors (call manually)
- static Params *makeParams(const std::string &name);
+ MemObject(const Params *params);
public:
/** Additional function to return the Port of a memory object. */
diff --git a/src/mem/mport.cc b/src/mem/mport.cc
new file mode 100644
index 000000000..72bcfc7fd
--- /dev/null
+++ b/src/mem/mport.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include "mem/mport.hh"
+
+Tick
+MessagePort::recvAtomic(PacketPtr pkt)
+{
+ if (pkt->cmd == MemCmd::MessageReq) {
+ // We received a message.
+ return recvMessage(pkt);
+ } else if (pkt->cmd == MemCmd::MessageResp) {
+ return recvResponse(pkt);
+ } else if (pkt->wasNacked()) {
+ return recvNack(pkt);
+ } else if (pkt->isError()) {
+ panic("Packet is error.\n");
+ } else {
+ panic("Unexpected memory command %s.\n", pkt->cmd.toString());
+ }
+}
+
+void
+MessagePort::sendMessageTiming(PacketPtr pkt, Tick latency)
+{
+ schedSendTiming(pkt, curTick + latency);
+}
+
+Tick
+MessagePort::sendMessageAtomic(PacketPtr pkt)
+{
+ return sendAtomic(pkt);
+}
diff --git a/src/cpu/o3/mips/thread_context.hh b/src/mem/mport.hh
index 26b1e2e7f..5975f89f0 100644
--- a/src/cpu/o3/mips/thread_context.hh
+++ b/src/mem/mport.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,44 +25,56 @@
* (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: Kevin Lim
- * Korey Sewell
+ * Authors: Gabe Black
*/
-#include "arch/mips/types.hh"
-#include "cpu/o3/thread_context.hh"
+#ifndef __MEM_MPORT_HH__
+#define __MEM_MPORT_HH__
-template <class Impl>
-class MipsTC : public O3ThreadContext<Impl>
+#include "mem/tport.hh"
+
+/*
+ * This file defines a port class which is used for sending and receiving
+ * messages. These messages are atomic units which don't interact and
+ * should be smaller than a cache block. This class is based on
+ * the underpinnings of SimpleTimingPort, but it tweaks some of the external
+ * functions.
+ */
+
+class MessagePort : public SimpleTimingPort
{
public:
- virtual uint64_t readNextNPC()
- {
- return this->cpu->readNextNPC(this->thread->readTid());
- }
+ MessagePort(std::string pname, MemObject *_owner = NULL) :
+ SimpleTimingPort(pname, _owner)
+ {}
- virtual void setNextNPC(uint64_t val)
+ virtual ~MessagePort()
+ {}
+
+ void
+ recvFunctional(PacketPtr pkt)
{
- this->cpu->setNextNPC(val, this->thread->readTid());
+ recvAtomic(pkt);
}
- virtual void changeRegFileContext(TheISA::RegContextParam param,
- TheISA::RegContextVal val)
- { panic("Not supported on Mips!"); }
+ Tick recvAtomic(PacketPtr pkt);
+
+ virtual Tick recvMessage(PacketPtr pkt) = 0;
- /** This function exits the thread context in the CPU and returns
- * 1 if the CPU has no more active threads (meaning it's OK to exit);
- * Used in syscall-emulation mode when a thread executes the 'exit'
- * syscall.
- */
- virtual int exit()
+ // Accept and ignore responses.
+ virtual Tick recvResponse(PacketPtr pkt)
{
- this->deallocate();
+ return 0;
+ }
- // If there are still threads executing in the system
- if (this->cpu->numActiveThreads())
- return 0; // don't exit simulation
- else
- return 1; // exit simulation
+ // Since by default we're assuming everything we send is accepted, panic.
+ virtual Tick recvNack(PacketPtr pkt)
+ {
+ panic("Unhandled message nack.\n");
}
+
+ void sendMessageTiming(PacketPtr pkt, Tick latency);
+ Tick sendMessageAtomic(PacketPtr pkt);
};
+
+#endif
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index f3bd06f36..17e58859a 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -42,6 +42,8 @@
#include "base/trace.hh"
#include "mem/packet.hh"
+using namespace std;
+
// The one downside to bitsets is that static initializers can get ugly.
#define SET1(a1) (1 << (a1))
#define SET2(a1, a2) (SET1(a1) | SET1(a2))
@@ -101,12 +103,10 @@ MemCmd::commandInfo[] =
/* ReadExResp */
{ SET4(IsRead, NeedsExclusive, IsResponse, HasData),
InvalidCmd, "ReadExResp" },
- /* LoadLockedReq */
+ /* LoadLockedReq: note that we use plain ReadResp as response, so that
+ * we can also use ReadRespWithInvalidate when needed */
{ SET4(IsRead, IsLocked, IsRequest, NeedsResponse),
- LoadLockedResp, "LoadLockedReq" },
- /* LoadLockedResp */
- { SET4(IsRead, IsLocked, IsResponse, HasData),
- InvalidCmd, "LoadLockedResp" },
+ ReadResp, "LoadLockedReq" },
/* StoreCondReq */
{ SET6(IsWrite, NeedsExclusive, IsLocked,
IsRequest, NeedsResponse, HasData),
@@ -120,6 +120,11 @@ MemCmd::commandInfo[] =
/* SwapResp -- for Swap ldstub type operations */
{ SET5(IsRead, IsWrite, NeedsExclusive, IsResponse, HasData),
InvalidCmd, "SwapResp" },
+ /* IntReq -- for interrupts */
+ { SET4(IsWrite, IsRequest, NeedsResponse, HasData),
+ MessageReq, "MessageReq" },
+ /* IntResp -- for interrupts */
+ { SET2(IsWrite, IsResponse), MessageResp, "MessageResp" },
/* NetworkNackError -- nacked at network layer (not by protocol) */
{ SET2(IsResponse, IsError), InvalidCmd, "NetworkNackError" },
/* InvalidDestError -- packet dest field invalid */
@@ -130,35 +135,6 @@ MemCmd::commandInfo[] =
{ SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" }
};
-
-/** 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()];
-}
-
-
bool
Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
{
@@ -190,7 +166,7 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
if (isRead()) {
if (func_start >= val_start && func_end <= val_end) {
allocate();
- std::memcpy(getPtr<uint8_t>(), data + offset, getSize());
+ memcpy(getPtr<uint8_t>(), data + offset, getSize());
makeResponse();
return true;
} else {
@@ -205,11 +181,12 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
}
} else if (isWrite()) {
if (offset >= 0) {
- std::memcpy(data + offset, getPtr<uint8_t>(),
- (std::min(func_end, val_end) - func_start) + 1);
- } else { // val_start > func_start
- std::memcpy(data, getPtr<uint8_t>() - offset,
- (std::min(func_end, val_end) - val_start) + 1);
+ memcpy(data + offset, getPtr<uint8_t>(),
+ (min(func_end, val_end) - func_start) + 1);
+ } else {
+ // val_start > func_start
+ memcpy(data, getPtr<uint8_t>() - offset,
+ (min(func_end, val_end) - val_start) + 1);
}
} else {
panic("Don't know how to handle command %s\n", cmdString());
@@ -219,23 +196,19 @@ Packet::checkFunctional(Printable *obj, Addr addr, int size, uint8_t *data)
return false;
}
-
void
-Packet::print(std::ostream &o, const int verbosity,
- const std::string &prefix) const
+Packet::print(ostream &o, const int verbosity, const string &prefix) const
{
ccprintf(o, "%s[%x:%x] %s\n", prefix,
getAddr(), getAddr() + getSize() - 1, cmdString());
}
-
-Packet::PrintReqState::PrintReqState(std::ostream &_os, int _verbosity)
- : curPrefixPtr(new std::string("")), os(_os), verbosity(_verbosity)
+Packet::PrintReqState::PrintReqState(ostream &_os, int _verbosity)
+ : curPrefixPtr(new string("")), os(_os), verbosity(_verbosity)
{
labelStack.push_back(LabelStackEntry("", curPrefixPtr));
}
-
Packet::PrintReqState::~PrintReqState()
{
labelStack.pop_back();
@@ -243,21 +216,17 @@ Packet::PrintReqState::~PrintReqState()
delete curPrefixPtr;
}
-
Packet::PrintReqState::
-LabelStackEntry::LabelStackEntry(const std::string &_label,
- std::string *_prefix)
+LabelStackEntry::LabelStackEntry(const string &_label, string *_prefix)
: label(_label), prefix(_prefix), labelPrinted(false)
{
}
-
void
-Packet::PrintReqState::pushLabel(const std::string &lbl,
- const std::string &prefix)
+Packet::PrintReqState::pushLabel(const string &lbl, const string &prefix)
{
labelStack.push_back(LabelStackEntry(lbl, curPrefixPtr));
- curPrefixPtr = new std::string(*curPrefixPtr);
+ curPrefixPtr = new string(*curPrefixPtr);
*curPrefixPtr += prefix;
}
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 05442b369..41f599fa0 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -42,8 +42,10 @@
#include <list>
#include <bitset>
+#include "base/cast.hh"
#include "base/compiler.hh"
#include "base/fast_alloc.hh"
+#include "base/flags.hh"
#include "base/misc.hh"
#include "base/printable.hh"
#include "mem/request.hh"
@@ -58,9 +60,12 @@ typedef std::list<PacketPtr> PacketList;
class MemCmd
{
- public:
+ friend class Packet;
- /** List of all commands associated with a packet. */
+ public:
+ /**
+ * List of all commands associated with a packet.
+ */
enum Command
{
InvalidCmd,
@@ -81,11 +86,12 @@ class MemCmd
ReadExReq,
ReadExResp,
LoadLockedReq,
- LoadLockedResp,
StoreCondReq,
StoreCondResp,
SwapReq,
SwapResp,
+ MessageReq,
+ MessageResp,
// Error responses
// @TODO these should be classified as responses rather than
// requests; coding them as requests initially for backwards
@@ -99,7 +105,9 @@ class MemCmd
};
private:
- /** List of command attributes. */
+ /**
+ * List of command attributes.
+ */
enum Attribute
{
IsRead, //!< Data flows from responder to requester
@@ -119,26 +127,31 @@ class MemCmd
NUM_COMMAND_ATTRIBUTES
};
- /** Structure that defines attributes and other data associated
- * with a Command. */
- struct CommandInfo {
- /** Set of attribute flags. */
+ /**
+ * Structure that defines attributes and other data associated
+ * with a Command.
+ */
+ struct CommandInfo
+ {
+ /// Set of attribute flags.
const std::bitset<NUM_COMMAND_ATTRIBUTES> attributes;
- /** Corresponding response for requests; InvalidCmd if no
- * response is applicable. */
+ /// Corresponding response for requests; InvalidCmd if no
+ /// response is applicable.
const Command response;
- /** String representation (for printing) */
+ /// String representation (for printing)
const std::string str;
};
- /** Array to map Command enum to associated info. */
+ /// Array to map Command enum to associated info.
static const CommandInfo commandInfo[];
private:
Command cmd;
- bool testCmdAttrib(MemCmd::Attribute attrib) const {
+ bool
+ testCmdAttrib(MemCmd::Attribute attrib) const
+ {
return commandInfo[cmd].attributes[attrib] != 0;
}
@@ -157,33 +170,22 @@ class MemCmd
bool isError() const { return testCmdAttrib(IsError); }
bool isPrint() const { return testCmdAttrib(IsPrint); }
- const Command responseCommand() const {
+ const Command
+ responseCommand() const
+ {
return commandInfo[cmd].response;
}
- /** Return the string to a cmd given by idx. */
- const std::string &toString() const {
- return commandInfo[cmd].str;
- }
-
+ /// Return the string to a cmd given by idx.
+ const std::string &toString() const { return commandInfo[cmd].str; }
int toInt() const { return (int)cmd; }
- MemCmd(Command _cmd)
- : cmd(_cmd)
- { }
-
- MemCmd(int _cmd)
- : cmd((Command)_cmd)
- { }
-
- MemCmd()
- : cmd(InvalidCmd)
- { }
-
- bool operator==(MemCmd c2) { return (cmd == c2.cmd); }
- bool operator!=(MemCmd c2) { return (cmd != c2.cmd); }
+ MemCmd(Command _cmd) : cmd(_cmd) { }
+ MemCmd(int _cmd) : cmd((Command)_cmd) { }
+ MemCmd() : cmd(InvalidCmd) { }
- friend class Packet;
+ bool operator==(MemCmd c2) const { return (cmd == c2.cmd); }
+ bool operator!=(MemCmd c2) const { return (cmd != c2.cmd); }
};
/**
@@ -196,107 +198,118 @@ class MemCmd
class Packet : public FastAlloc, public Printable
{
public:
+ typedef uint32_t FlagsType;
+ typedef ::Flags<FlagsType> Flags;
+ typedef short NodeID;
+
+ private:
+ static const FlagsType PUBLIC_FLAGS = 0x00000000;
+ static const FlagsType PRIVATE_FLAGS = 0x00007F0F;
+ static const FlagsType COPY_FLAGS = 0x0000000F;
+ static const FlagsType SHARED = 0x00000001;
+ // Special control flags
+ /// Special timing-mode atomic snoop for multi-level coherence.
+ static const FlagsType EXPRESS_SNOOP = 0x00000002;
+ /// Does supplier have exclusive copy?
+ /// Useful for multi-level coherence.
+ static const FlagsType SUPPLY_EXCLUSIVE = 0x00000004;
+ // Snoop response flags
+ static const FlagsType MEM_INHIBIT = 0x00000008;
+ /// Are the 'addr' and 'size' fields valid?
+ static const FlagsType VALID_ADDR = 0x00000100;
+ static const FlagsType VALID_SIZE = 0x00000200;
+ /// Is the 'src' field valid?
+ static const FlagsType VALID_SRC = 0x00000400;
+ static const FlagsType VALID_DST = 0x00000800;
+ /// Is the data pointer set to a value that shouldn't be freed
+ /// when the packet is destroyed?
+ static const FlagsType STATIC_DATA = 0x00001000;
+ /// The data pointer points to a value that should be freed when
+ /// the packet is destroyed.
+ static const FlagsType DYNAMIC_DATA = 0x00002000;
+ /// the data pointer points to an array (thus delete []) needs to
+ /// be called on it rather than simply delete.
+ static const FlagsType ARRAY_DATA = 0x00004000;
+
+ Flags flags;
+
+ public:
typedef MemCmd::Command Command;
- /** The command field of the packet. */
+ /// The command field of the packet.
MemCmd cmd;
- /** A pointer to the original request. */
+ /// A pointer to the original request.
RequestPtr req;
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.
+ /**
+ * 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. This address could be virtual or
- * physical, depending on the system configuration. */
+ /// The address of the request. This address could be virtual or
+ /// physical, depending on the system configuration.
Addr addr;
- /** The size of the request or transfer. */
+ /// The size of the request or transfer.
int size;
- /** Device address (e.g., bus ID) of the source of the
- * transaction. The source is not responsible for setting this
- * field; it is set implicitly by the interconnect when the
- * packet is first sent. */
- short src;
+ /**
+ * Device address (e.g., bus ID) of the source of the
+ * transaction. The source is not responsible for setting this
+ * field; it is set implicitly by the interconnect when the packet
+ * is first sent.
+ */
+ NodeID src;
- /** Device address (e.g., bus ID) of the destination of the
- * transaction. The special value Broadcast indicates that the
- * packet should be routed based on its address. This field is
- * initialized in the constructor and is thus always valid
- * (unlike * addr, size, and src). */
- short dest;
+ /**
+ * Device address (e.g., bus ID) of the destination of the
+ * transaction. The special value Broadcast indicates that the
+ * packet should be routed based on its address. This field is
+ * initialized in the constructor and is thus always valid (unlike
+ * addr, size, and src).
+ */
+ NodeID dest;
- /** The original value of the command field. Only valid when the
+ /**
+ * The original value of the command field. Only valid when the
* current command field is an error condition; in that case, the
* previous contents of the command field are copied here. This
* field is *not* set on non-error responses.
*/
MemCmd origCmd;
- /** Are the 'addr' and 'size' fields valid? */
- bool addrSizeValid;
- /** Is the 'src' field valid? */
- bool srcValid;
- bool destValid;
-
- enum Flag {
- // Snoop response flags
- MemInhibit,
- Shared,
- // Special control flags
- /// Special timing-mode atomic snoop for multi-level coherence.
- ExpressSnoop,
- /// Does supplier have exclusive copy?
- /// Useful for multi-level coherence.
- SupplyExclusive,
- NUM_PACKET_FLAGS
- };
-
- /** Status flags */
- std::bitset<NUM_PACKET_FLAGS> flags;
-
public:
-
- /** Used to calculate latencies for each packet.*/
+ /// Used to calculate latencies for each packet.
Tick time;
- /** The time at which the packet will be fully transmitted */
+ /// The time at which the packet will be fully transmitted
Tick finishTime;
- /** The time at which the first chunk of the packet will be transmitted */
+ /// The time at which the first chunk of the packet will be transmitted
Tick firstWordTime;
- /** The special destination address indicating that the packet
- * should be routed based on its address. */
- static const short Broadcast = -1;
-
- /** A virtual base opaque structure used to hold state associated
- * with the packet but specific to the sending device (e.g., an
- * MSHR). A pointer to this state is returned in the packet's
- * response so that the sender can quickly look up the state
- * needed to process it. A specific subclass would be derived
- * from this to carry state specific to a particular sending
- * device. */
- class SenderState : public FastAlloc {
- public:
+ /// The special destination address indicating that the packet
+ /// should be routed based on its address.
+ static const NodeID Broadcast = -1;
+
+ /**
+ * A virtual base opaque structure used to hold state associated
+ * with the packet but specific to the sending device (e.g., an
+ * MSHR). A pointer to this state is returned in the packet's
+ * response so that the sender can quickly look up the state
+ * needed to process it. A specific subclass would be derived
+ * from this to carry state specific to a particular sending
+ * device.
+ */
+ struct SenderState
+ {
virtual ~SenderState() {}
};
@@ -304,15 +317,18 @@ class Packet : public FastAlloc, public Printable
* Object used to maintain state of a PrintReq. The senderState
* field of a PrintReq should always be of this type.
*/
- class PrintReqState : public SenderState {
- /** An entry in the label stack. */
- class LabelStackEntry {
- public:
+ class PrintReqState : public SenderState, public FastAlloc
+ {
+ private:
+ /**
+ * An entry in the label stack.
+ */
+ struct LabelStackEntry
+ {
const std::string label;
std::string *prefix;
bool labelPrinted;
- LabelStackEntry(const std::string &_label,
- std::string *_prefix);
+ LabelStackEntry(const std::string &_label, std::string *_prefix);
};
typedef std::list<LabelStackEntry> LabelStack;
@@ -327,35 +343,53 @@ class Packet : public FastAlloc, public Printable
PrintReqState(std::ostream &os, int verbosity = 0);
~PrintReqState();
- /** Returns the current line prefix. */
+ /**
+ * Returns the current line prefix.
+ */
const std::string &curPrefix() { return *curPrefixPtr; }
- /** Push a label onto the label stack, and prepend the given
+ /**
+ * Push a label onto the label stack, and prepend the given
* prefix string onto the current prefix. Labels will only be
- * printed if an object within the label's scope is
- * printed. */
+ * printed if an object within the label's scope is printed.
+ */
void pushLabel(const std::string &lbl,
const std::string &prefix = " ");
- /** Pop a label off the label stack. */
+
+ /**
+ * Pop a label off the label stack.
+ */
void popLabel();
- /** Print all of the pending unprinted labels on the
+
+ /**
+ * Print all of the pending unprinted labels on the
* stack. Called by printObj(), so normally not called by
- * users unless bypassing printObj(). */
+ * users unless bypassing printObj().
+ */
void printLabels();
- /** Print a Printable object to os, because it matched the
- * address on a PrintReq. */
+
+ /**
+ * Print a Printable object to os, because it matched the
+ * address on a PrintReq.
+ */
void printObj(Printable *obj);
};
- /** This packet's sender state. Devices should use dynamic_cast<>
- * to cast to the state appropriate to the sender. */
+ /**
+ * This packet's sender state. Devices should use dynamic_cast<>
+ * to cast to the state appropriate to the sender. The intent of
+ * this variable is to allow a device to attach extra information
+ * to a request. A response packet must return the sender state
+ * that was attached to the original request (even if a new packet
+ * is created).
+ */
SenderState *senderState;
- /** Return the string name of the cmd field (for debugging and
- * tracing). */
+ /// Return the string name of the cmd field (for debugging and
+ /// tracing).
const std::string &cmdString() const { return cmd.toString(); }
- /** Return the index of this command. */
+ /// Return the index of this command.
inline int cmdToIndex() const { return cmd.toInt(); }
bool isRead() const { return cmd.isRead(); }
@@ -372,108 +406,134 @@ class Packet : public FastAlloc, public Printable
bool isPrint() const { return cmd.isPrint(); }
// Snoop flags
- void assertMemInhibit() { flags[MemInhibit] = true; }
- bool memInhibitAsserted() { return flags[MemInhibit]; }
- void assertShared() { flags[Shared] = true; }
- bool sharedAsserted() { return flags[Shared]; }
+ void assertMemInhibit() { flags.set(MEM_INHIBIT); }
+ bool memInhibitAsserted() { return flags.isSet(MEM_INHIBIT); }
+ void assertShared() { flags.set(SHARED); }
+ bool sharedAsserted() { return flags.isSet(SHARED); }
// Special control flags
- void setExpressSnoop() { flags[ExpressSnoop] = true; }
- bool isExpressSnoop() { return flags[ExpressSnoop]; }
- void setSupplyExclusive() { flags[SupplyExclusive] = true; }
- bool isSupplyExclusive() { return flags[SupplyExclusive]; }
+ void setExpressSnoop() { flags.set(EXPRESS_SNOOP); }
+ bool isExpressSnoop() { return flags.isSet(EXPRESS_SNOOP); }
+ void setSupplyExclusive() { flags.set(SUPPLY_EXCLUSIVE); }
+ bool isSupplyExclusive() { return flags.isSet(SUPPLY_EXCLUSIVE); }
// Network error conditions... encapsulate them as methods since
// their encoding keeps changing (from result field to command
// field, etc.)
- void setNacked() { assert(isResponse()); cmd = MemCmd::NetworkNackError; }
- void setBadAddress() { assert(isResponse()); cmd = MemCmd::BadAddressError; }
- bool wasNacked() { return cmd == MemCmd::NetworkNackError; }
- bool hadBadAddress() { return cmd == MemCmd::BadAddressError; }
+ void
+ setNacked()
+ {
+ assert(isResponse());
+ cmd = MemCmd::NetworkNackError;
+ }
+
+ void
+ setBadAddress()
+ {
+ assert(isResponse());
+ cmd = MemCmd::BadAddressError;
+ }
+
+ bool wasNacked() const { return cmd == MemCmd::NetworkNackError; }
+ bool hadBadAddress() const { return cmd == MemCmd::BadAddressError; }
void copyError(Packet *pkt) { assert(pkt->isError()); cmd = pkt->cmd; }
- bool nic_pkt() { panic("Unimplemented"); M5_DUMMY_RETURN }
-
- /** 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; }
- /** Reset source field, e.g. to retransmit packet on different bus. */
- void clearSrc() { srcValid = false; }
-
- /** Accessor function that returns the destination index of
- the packet. */
- short getDest() const { assert(destValid); return dest; }
- void setDest(short _dest) { dest = _dest; destValid = true; }
-
- Addr getAddr() const { assert(addrSizeValid); return addr; }
- int getSize() const { assert(addrSizeValid); return size; }
- Addr getOffset(int blkSize) const { return addr & (Addr)(blkSize - 1); }
-
- /** Constructor. Note that a Request object must be constructed
- * first, but the Requests's physical address and size fields
- * need not be valid. The command and destination addresses
- * must be supplied. */
- Packet(Request *_req, MemCmd _cmd, short _dest)
- : cmd(_cmd), req(_req),
- data(NULL), staticData(false), dynamicData(false), arrayData(false),
- addr(_req->paddr), size(_req->size), dest(_dest),
- addrSizeValid(_req->validPaddr), srcValid(false), destValid(true),
- flags(0), time(curTick), senderState(NULL)
+ /// Accessor function to get the source index of the packet.
+ NodeID getSrc() const { assert(flags.isSet(VALID_SRC)); return src; }
+ /// Accessor function to set the source index of the packet.
+ void setSrc(NodeID _src) { src = _src; flags.set(VALID_SRC); }
+ /// Reset source field, e.g. to retransmit packet on different bus.
+ void clearSrc() { flags.clear(VALID_SRC); }
+
+ /// Accessor function for the destination index of the packet.
+ NodeID getDest() const { assert(flags.isSet(VALID_DST)); return dest; }
+ /// Accessor function to set the destination index of the packet.
+ void setDest(NodeID _dest) { dest = _dest; flags.set(VALID_DST); }
+
+ Addr getAddr() const { assert(flags.isSet(VALID_ADDR)); return addr; }
+ int getSize() const { assert(flags.isSet(VALID_SIZE)); return size; }
+ Addr getOffset(int blkSize) const { return getAddr() & (Addr)(blkSize - 1); }
+
+ /**
+ * Constructor. Note that a Request object must be constructed
+ * first, but the Requests's physical address and size fields need
+ * not be valid. The command and destination addresses must be
+ * supplied.
+ */
+ Packet(Request *_req, MemCmd _cmd, NodeID _dest)
+ : flags(VALID_DST), cmd(_cmd), req(_req), data(NULL),
+ addr(_req->paddr), size(_req->size), dest(_dest), time(curTick),
+ senderState(NULL)
{
+ if (req->flags.isSet(Request::VALID_PADDR))
+ flags.set(VALID_ADDR|VALID_SIZE);
}
- /** Alternate constructor if you are trying to create a packet with
- * a request that is for a whole block, not the address from the req.
- * this allows for overriding the size/addr of the req.*/
- Packet(Request *_req, MemCmd _cmd, short _dest, int _blkSize)
- : cmd(_cmd), req(_req),
- data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ /**
+ * Alternate constructor if you are trying to create a packet with
+ * a request that is for a whole block, not the address from the
+ * req. this allows for overriding the size/addr of the req.
+ */
+ Packet(Request *_req, MemCmd _cmd, NodeID _dest, int _blkSize)
+ : flags(VALID_DST), cmd(_cmd), req(_req), data(NULL),
addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize), dest(_dest),
- addrSizeValid(_req->validPaddr), srcValid(false), destValid(true),
- flags(0), time(curTick), senderState(NULL)
+ time(curTick), senderState(NULL)
{
+ if (req->flags.isSet(Request::VALID_PADDR))
+ flags.set(VALID_ADDR|VALID_SIZE);
}
- /** Alternate constructor for copying a packet. Copy all fields
+ /**
+ * Alternate constructor for copying a packet. Copy all fields
* *except* if the original packet's data was dynamic, don't copy
* that, as we can't guarantee that the new packet's lifetime is
* less than that of the original packet. In this case the new
- * packet should allocate its own data. */
- Packet(Packet *origPkt, bool clearFlags = false)
- : cmd(origPkt->cmd), req(origPkt->req),
- data(origPkt->staticData ? origPkt->data : NULL),
- staticData(origPkt->staticData),
- dynamicData(false), arrayData(false),
- addr(origPkt->addr), size(origPkt->size),
- src(origPkt->src), dest(origPkt->dest),
- addrSizeValid(origPkt->addrSizeValid),
- srcValid(origPkt->srcValid), destValid(origPkt->destValid),
- flags(clearFlags ? 0 : origPkt->flags),
- time(curTick), senderState(origPkt->senderState)
+ * packet should allocate its own data.
+ */
+ Packet(Packet *pkt, bool clearFlags = false)
+ : cmd(pkt->cmd), req(pkt->req),
+ data(pkt->flags.isSet(STATIC_DATA) ? pkt->data : NULL),
+ addr(pkt->addr), size(pkt->size), src(pkt->src), dest(pkt->dest),
+ time(curTick), senderState(pkt->senderState)
{
+ if (!clearFlags)
+ flags.set(pkt->flags & COPY_FLAGS);
+
+ flags.set(pkt->flags & (VALID_ADDR|VALID_SIZE|VALID_SRC|VALID_DST));
+ flags.set(pkt->flags & STATIC_DATA);
}
- /** Destructor. */
+ /**
+ * clean up packet variables
+ */
~Packet()
- { if (staticData || dynamicData) deleteData(); }
-
- /** Reinitialize packet address and size from the associated
- * Request object, and reset other fields that may have been
- * modified by a previous transaction. Typically called when a
- * statically allocated Request/Packet pair is reused for
- * multiple transactions. */
- void reinitFromRequest() {
- assert(req->validPaddr);
+ {
+ // If this is a request packet for which there's no response,
+ // delete the request object here, since the requester will
+ // never get the chance.
+ if (req && isRequest() && !needsResponse())
+ delete req;
+ deleteData();
+ }
+
+ /**
+ * Reinitialize packet address and size from the associated
+ * Request object, and reset other fields that may have been
+ * modified by a previous transaction. Typically called when a
+ * statically allocated Request/Packet pair is reused for multiple
+ * transactions.
+ */
+ void
+ reinitFromRequest()
+ {
+ assert(req->flags.isSet(Request::VALID_PADDR));
flags = 0;
addr = req->paddr;
size = req->size;
time = req->time;
- addrSizeValid = true;
- if (dynamicData) {
- deleteData();
- dynamicData = false;
- arrayData = false;
- }
+
+ flags.set(VALID_ADDR|VALID_SIZE);
+ deleteData();
}
/**
@@ -482,23 +542,27 @@ class Packet : public FastAlloc, public Printable
* destination fields are *not* modified, as is appropriate for
* atomic accesses.
*/
- void makeResponse()
+ void
+ makeResponse()
{
assert(needsResponse());
assert(isRequest());
origCmd = cmd;
cmd = cmd.responseCommand();
+
dest = src;
- destValid = srcValid;
- srcValid = false;
+ flags.set(VALID_DST, flags.isSet(VALID_SRC));
+ flags.clear(VALID_SRC);
}
- void makeAtomicResponse()
+ void
+ makeAtomicResponse()
{
makeResponse();
}
- void makeTimingResponse()
+ void
+ makeTimingResponse()
{
makeResponse();
}
@@ -526,10 +590,9 @@ class Packet : public FastAlloc, public Printable
void
dataStatic(T *p)
{
- if(dynamicData)
- dynamicData = false;
+ assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA));
data = (PacketDataPtr)p;
- staticData = true;
+ flags.set(STATIC_DATA);
}
/**
@@ -540,10 +603,9 @@ class Packet : public FastAlloc, public Printable
void
dataDynamicArray(T *p)
{
- assert(!staticData && !dynamicData);
+ assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA));
data = (PacketDataPtr)p;
- dynamicData = true;
- arrayData = true;
+ flags.set(DYNAMIC_DATA|ARRAY_DATA);
}
/**
@@ -554,33 +616,39 @@ class Packet : public FastAlloc, public Printable
void
dataDynamic(T *p)
{
- assert(!staticData && !dynamicData);
+ assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA));
data = (PacketDataPtr)p;
- dynamicData = true;
- arrayData = false;
+ flags.set(DYNAMIC_DATA);
}
- /** get a pointer to the data ptr. */
+ /**
+ * get a pointer to the data ptr.
+ */
template <typename T>
T*
getPtr()
{
- assert(staticData || dynamicData);
+ assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA));
return (T*)data;
}
- /** return the value of what is pointed to in the packet. */
+ /**
+ * return the value of what is pointed to in the packet.
+ */
template <typename T>
T get();
- /** set the value in the data pointer to v. */
+ /**
+ * set the value in the data pointer to v.
+ */
template <typename T>
void set(T v);
/**
* Copy data into the packet from the provided pointer.
*/
- void setData(uint8_t *p)
+ void
+ setData(uint8_t *p)
{
std::memcpy(getPtr<uint8_t>(), p, getSize());
}
@@ -589,7 +657,8 @@ class Packet : public FastAlloc, public Printable
* Copy data into the packet from the provided block pointer,
* which is aligned to the given block size.
*/
- void setDataFromBlock(uint8_t *blk_data, int blkSize)
+ void
+ setDataFromBlock(uint8_t *blk_data, int blkSize)
{
setData(blk_data + getOffset(blkSize));
}
@@ -598,7 +667,8 @@ class Packet : public FastAlloc, public Printable
* Copy data from the packet to the provided block pointer, which
* is aligned to the given block size.
*/
- void writeData(uint8_t *p)
+ void
+ writeData(uint8_t *p)
{
std::memcpy(p, getPtr<uint8_t>(), getSize());
}
@@ -606,7 +676,8 @@ class Packet : public FastAlloc, public Printable
/**
* Copy data from the packet to the memory at the provided pointer.
*/
- void writeDataToBlock(uint8_t *blk_data, int blkSize)
+ void
+ writeDataToBlock(uint8_t *blk_data, int blkSize)
{
writeData(blk_data + getOffset(blkSize));
}
@@ -615,10 +686,32 @@ class Packet : public FastAlloc, public Printable
* delete the data pointed to in the data pointer. Ok to call to
* matter how data was allocted.
*/
- void deleteData();
+ void
+ deleteData()
+ {
+ if (flags.isSet(ARRAY_DATA))
+ delete [] data;
+ else if (flags.isSet(DYNAMIC_DATA))
+ delete data;
+
+ flags.clear(STATIC_DATA|DYNAMIC_DATA|ARRAY_DATA);
+ data = NULL;
+ }
/** If there isn't data in the packet, allocate some. */
- void allocate();
+ void
+ allocate()
+ {
+ if (data) {
+ assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA));
+ return;
+ }
+
+ assert(flags.noneSet(STATIC_DATA|DYNAMIC_DATA));
+ flags.set(DYNAMIC_DATA|ARRAY_DATA);
+ data = new uint8_t[getSize()];
+ }
+
/**
* Check a functional request against a memory value represented
@@ -633,29 +726,32 @@ class Packet : public FastAlloc, public Printable
* Check a functional request against a memory value stored in
* another packet (i.e. an in-transit request or response).
*/
- bool checkFunctional(PacketPtr otherPkt) {
- return checkFunctional(otherPkt,
- otherPkt->getAddr(), otherPkt->getSize(),
- otherPkt->hasData() ?
- otherPkt->getPtr<uint8_t>() : NULL);
+ bool
+ checkFunctional(PacketPtr other)
+ {
+ uint8_t *data = other->hasData() ? other->getPtr<uint8_t>() : NULL;
+ return checkFunctional(other, other->getAddr(), other->getSize(),
+ data);
}
/**
* Push label for PrintReq (safe to call unconditionally).
*/
- void pushLabel(const std::string &lbl) {
- if (isPrint()) {
- dynamic_cast<PrintReqState*>(senderState)->pushLabel(lbl);
- }
+ void
+ pushLabel(const std::string &lbl)
+ {
+ if (isPrint())
+ safe_cast<PrintReqState*>(senderState)->pushLabel(lbl);
}
/**
* Pop label for PrintReq (safe to call unconditionally).
*/
- void popLabel() {
- if (isPrint()) {
- dynamic_cast<PrintReqState*>(senderState)->popLabel();
- }
+ void
+ popLabel()
+ {
+ if (isPrint())
+ safe_cast<PrintReqState*>(senderState)->popLabel();
}
void print(std::ostream &o, int verbosity = 0,
diff --git a/src/mem/packet_access.hh b/src/mem/packet_access.hh
index d1edd00aa..f70d508b2 100644
--- a/src/mem/packet_access.hh
+++ b/src/mem/packet_access.hh
@@ -46,7 +46,7 @@ template <typename T>
inline T
Packet::get()
{
- assert(staticData || dynamicData);
+ assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA));
assert(sizeof(T) <= size);
return TheISA::gtoh(*(T*)data);
}
@@ -56,6 +56,7 @@ template <typename T>
inline void
Packet::set(T v)
{
+ assert(flags.isSet(STATIC_DATA|DYNAMIC_DATA));
assert(sizeof(T) <= size);
*(T*)data = TheISA::htog(v);
}
diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc
index 54165f293..bdcbbfec3 100644
--- a/src/mem/page_table.cc
+++ b/src/mem/page_table.cc
@@ -87,6 +87,44 @@ PageTable::allocate(Addr vaddr, int64_t size)
}
}
+void
+PageTable::remap(Addr vaddr, int64_t size, Addr new_vaddr)
+{
+ assert(pageOffset(vaddr) == 0);
+ assert(pageOffset(new_vaddr) == 0);
+
+ DPRINTF(MMU, "moving pages from vaddr %08p to %08p, size = %d\n", vaddr,
+ new_vaddr, size);
+
+ for (; size > 0; size -= pageSize, vaddr += pageSize, new_vaddr += pageSize) {
+ PTableItr iter = pTable.find(vaddr);
+
+ assert(iter != pTable.end());
+
+ pTable[new_vaddr] = pTable[vaddr];
+ pTable.erase(vaddr);
+ pTable[new_vaddr].updateVaddr(new_vaddr);
+ updateCache(new_vaddr, pTable[new_vaddr]);
+ }
+}
+
+void
+PageTable::deallocate(Addr vaddr, int64_t size)
+{
+ assert(pageOffset(vaddr) == 0);
+
+ DPRINTF(MMU, "Deallocating page: %#x-%#x\n", vaddr, vaddr+ size);
+
+ for (; size > 0; size -= pageSize, vaddr += pageSize) {
+ PTableItr iter = pTable.find(vaddr);
+
+ assert(iter != pTable.end());
+
+ pTable.erase(vaddr);
+ }
+
+}
+
bool
PageTable::lookup(Addr vaddr, TheISA::TlbEntry &entry)
{
diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh
index b8b52174c..d4101c6bf 100644
--- a/src/mem/page_table.hh
+++ b/src/mem/page_table.hh
@@ -80,6 +80,8 @@ class PageTable
Addr pageOffset(Addr a) { return (a & offsetMask); }
void allocate(Addr vaddr, int64_t size);
+ void remap(Addr vaddr, int64_t size, Addr new_vaddr);
+ void deallocate(Addr vaddr, int64_t size);
/**
* Lookup function
@@ -91,11 +93,19 @@ class PageTable
/**
* Translate function
* @param vaddr The virtual address.
- * @return Physical address from translation.
+ * @param paddr Physical address from translation.
+ * @return True if translation exists
*/
bool translate(Addr vaddr, Addr &paddr);
/**
+ * Simplified translate function (just check for translation)
+ * @param vaddr The virtual address.
+ * @return True if translation exists
+ */
+ bool translate(Addr vaddr) { Addr dummy; return translate(vaddr, dummy); }
+
+ /**
* Perform a translation on the memory request, fills in paddr
* field of req.
* @param req The memory request.
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index 3560fc670..16ff3de6d 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -41,6 +41,7 @@
#include "arch/isa_traits.hh"
#include "base/misc.hh"
+#include "base/random.hh"
#include "config/full_system.hh"
#include "mem/packet_access.hh"
#include "mem/physical.hh"
@@ -51,11 +52,16 @@ using namespace std;
using namespace TheISA;
PhysicalMemory::PhysicalMemory(const Params *p)
- : MemObject(p), pmemAddr(NULL), lat(p->latency)
+ : MemObject(p), pmemAddr(NULL), pagePtr(0),
+ lat(p->latency), lat_var(p->latency_var),
+ cachedSize(params()->range.size()), cachedStart(params()->range.start)
{
if (params()->range.size() % TheISA::PageBytes != 0)
panic("Memory Size not divisible by page size\n");
+ if (params()->null)
+ return;
+
int map_flags = MAP_ANON | MAP_PRIVATE;
pmemAddr = (uint8_t *)mmap(NULL, params()->range.size(),
PROT_READ | PROT_WRITE, map_flags, -1, 0);
@@ -68,12 +74,6 @@ PhysicalMemory::PhysicalMemory(const Params *p)
//If requested, initialize all the memory to 0
if (p->zero)
memset(pmemAddr, 0, p->range.size());
-
- pagePtr = 0;
-
- cachedSize = params()->range.size();
- cachedStart = params()->range.start;
-
}
void
@@ -116,7 +116,10 @@ PhysicalMemory::deviceBlockSize()
Tick
PhysicalMemory::calculateLatency(PacketPtr pkt)
{
- return lat;
+ Tick latency = lat;
+ if (lat_var != 0)
+ latency += random_mt.random<Tick>(0, lat_var);
+ return latency;
}
@@ -136,16 +139,16 @@ PhysicalMemory::trackLoadLocked(PacketPtr pkt)
for (i = lockedAddrList.begin(); i != lockedAddrList.end(); ++i) {
if (i->matchesContext(req)) {
- DPRINTF(LLSC, "Modifying lock record: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "Modifying lock record: context %d addr %#x\n",
+ req->contextId(), paddr);
i->addr = paddr;
return;
}
}
// no record for this xc: need to allocate a new one
- DPRINTF(LLSC, "Adding lock record: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "Adding lock record: context %d addr %#x\n",
+ req->contextId(), paddr);
lockedAddrList.push_front(LockedAddr(req));
}
@@ -180,14 +183,14 @@ PhysicalMemory::checkLockedAddrList(PacketPtr pkt)
// it's a store conditional, and as far as the memory
// system can tell, the requesting context's lock is
// still valid.
- DPRINTF(LLSC, "StCond success: cpu %d thread %d addr %#x\n",
- req->getCpuNum(), req->getThreadNum(), paddr);
+ DPRINTF(LLSC, "StCond success: context %d addr %#x\n",
+ req->contextId(), paddr);
success = true;
}
// Get rid of our record of this lock and advance to next
- DPRINTF(LLSC, "Erasing lock record: cpu %d thread %d addr %#x\n",
- i->cpuNum, i->threadNum, paddr);
+ DPRINTF(LLSC, "Erasing lock record: context %d addr %#x\n",
+ i->contextId, paddr);
i = lockedAddrList.erase(i);
}
else {
@@ -252,6 +255,8 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt)
uint64_t condition_val64;
uint32_t condition_val32;
+ if (!pmemAddr)
+ panic("Swap only works if there is real memory (i.e. null=False)");
assert(sizeof(IntReg) >= pkt->getSize());
overwrite_mem = true;
@@ -282,11 +287,13 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt)
if (pkt->isLocked()) {
trackLoadLocked(pkt);
}
- memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ if (pmemAddr)
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
TRACE_PACKET("Read");
} else if (pkt->isWrite()) {
if (writeOK(pkt)) {
- memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ if (pmemAddr)
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
TRACE_PACKET("Write");
}
} else if (pkt->isInvalidate()) {
@@ -315,11 +322,13 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
uint8_t *hostAddr = pmemAddr + pkt->getAddr() - start();
if (pkt->isRead()) {
- memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
+ if (pmemAddr)
+ memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
TRACE_PACKET("Read");
pkt->makeAtomicResponse();
} else if (pkt->isWrite()) {
- memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
+ if (pmemAddr)
+ memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
TRACE_PACKET("Write");
pkt->makeAtomicResponse();
} else if (pkt->isPrint()) {
@@ -374,7 +383,7 @@ PhysicalMemory::recvStatusChange(Port::Status status)
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
PhysicalMemory *_memory)
- : SimpleTimingPort(_name), memory(_memory)
+ : SimpleTimingPort(_name, _memory), memory(_memory)
{ }
void
@@ -443,6 +452,9 @@ PhysicalMemory::drain(Event *de)
void
PhysicalMemory::serialize(ostream &os)
{
+ if (!pmemAddr)
+ return;
+
gzFile compressedMem;
string filename = name() + ".physmem";
@@ -475,6 +487,9 @@ PhysicalMemory::serialize(ostream &os)
void
PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
{
+ if (!pmemAddr)
+ return;
+
gzFile compressedMem;
long *tempPage;
long *pmem_current;
@@ -482,7 +497,6 @@ PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
uint32_t bytesRead;
const int chunkSize = 16384;
-
string filename;
UNSERIALIZE_SCALAR(filename);
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index c3749bd5b..d18138ecd 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -89,21 +89,18 @@ class PhysicalMemory : public MemObject
static Addr mask(Addr paddr) { return (paddr & ~Addr_Mask); }
- Addr addr; // locked address
- int cpuNum; // locking CPU
- int threadNum; // locking thread ID within CPU
+ Addr addr; // locked address
+ int contextId; // locking hw context
// check for matching execution context
bool matchesContext(Request *req)
{
- return (cpuNum == req->getCpuNum() &&
- threadNum == req->getThreadNum());
+ return (contextId == req->contextId());
}
LockedAddr(Request *req)
: addr(mask(req->getPaddr())),
- cpuNum(req->getCpuNum()),
- threadNum(req->getThreadNum())
+ contextId(req->contextId())
{
}
};
@@ -146,6 +143,7 @@ class PhysicalMemory : public MemObject
uint8_t *pmemAddr;
int pagePtr;
Tick lat;
+ Tick lat_var;
std::vector<MemoryPort*> ports;
typedef std::vector<MemoryPort*>::iterator PortIterator;
diff --git a/src/mem/port.cc b/src/mem/port.cc
index ce3f6c74b..a666c968b 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -39,17 +39,18 @@
#include "mem/mem_object.hh"
#include "mem/port.hh"
-class defaultPeerPortClass: public Port
+class DefaultPeerPort : public Port
{
protected:
void blowUp()
{
- fatal("Unconnected port!");
+ fatal("%s: Unconnected port!", peer->name());
}
public:
- defaultPeerPortClass() : Port("default_port")
- {}
+ DefaultPeerPort()
+ : Port("default_port", NULL)
+ { }
bool recvTiming(PacketPtr)
{
@@ -84,16 +85,18 @@ class defaultPeerPortClass: public Port
blowUp();
}
- bool isDefaultPort() { return true; }
+ bool isDefaultPort() const { return true; }
+};
-} defaultPeerPort;
+DefaultPeerPort defaultPeerPort;
-Port::Port() : peer(&defaultPeerPort), owner(NULL)
+Port::Port(const std::string &_name, MemObject *_owner)
+ : EventManager(_owner), portName(_name), peer(&defaultPeerPort),
+ owner(_owner)
{
}
-Port::Port(const std::string &_name, MemObject *_owner) :
- portName(_name), peer(&defaultPeerPort), owner(_owner)
+Port::~Port()
{
}
@@ -101,10 +104,18 @@ void
Port::setPeer(Port *port)
{
DPRINTF(Config, "setting peer to %s\n", port->name());
+
peer = port;
}
void
+Port::setOwner(MemObject *_owner)
+{
+ eventq = _owner->queue();
+ owner = _owner;
+}
+
+void
Port::removeConn()
{
if (peer->getOwner())
diff --git a/src/mem/port.hh b/src/mem/port.hh
index f66b566ea..1d9135ae6 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -47,6 +47,7 @@
#include "base/range.hh"
#include "mem/packet.hh"
#include "mem/request.hh"
+#include "sim/eventq.hh"
/** This typedef is used to clean up the parameter list of
* getDeviceAddressRanges() and getPeerAddressRanges(). It's declared
@@ -58,6 +59,7 @@
typedef std::list<Range<Addr> > AddrRangeList;
typedef std::list<Range<Addr> >::iterator AddrRangeIter;
+class EventQueue;
class MemObject;
/**
@@ -71,10 +73,9 @@ class MemObject;
* 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
+class Port : public EventManager
{
- private:
-
+ protected:
/** Descriptive name (for DPRINTF output) */
mutable std::string portName;
@@ -87,9 +88,6 @@ class Port
MemObject *owner;
public:
-
- Port();
-
/**
* Constructor.
*
@@ -98,12 +96,12 @@ class Port
* @param _owner Pointer to the MemObject that owns this port.
* Will not necessarily be set.
*/
- Port(const std::string &_name, MemObject *_owner = NULL);
+ Port(const std::string &_name, MemObject *_owner);
/** Return port name (for DPRINTF). */
const std::string &name() const { return portName; }
- virtual ~Port() {};
+ virtual ~Port();
// mey be better to use subclasses & RTTI?
/** Holds the ports status. Currently just that a range recomputation needs
@@ -122,7 +120,7 @@ class Port
Port *getPeer() { return peer; }
/** Function to set the owner of this port. */
- void setOwner(MemObject *_owner) { owner = _owner; }
+ void setOwner(MemObject *_owner);
/** Function to return the owner of this port. */
MemObject *getOwner() { return owner; }
@@ -131,7 +129,9 @@ class Port
* demise. */
void removeConn();
- virtual bool isDefaultPort() { return false; }
+ virtual bool isDefaultPort() const { return false; }
+
+ bool isConnected() { return peer && !peer->isDefaultPort(); }
protected:
diff --git a/src/mem/request.hh b/src/mem/request.hh
index cc9c6b8bf..ee62ce771 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -39,247 +39,436 @@
#ifndef __MEM_REQUEST_HH__
#define __MEM_REQUEST_HH__
+#include <cassert>
+
#include "base/fast_alloc.hh"
+#include "base/flags.hh"
+#include "base/misc.hh"
#include "sim/host.hh"
#include "sim/core.hh"
-#include <cassert>
-
class Request;
typedef Request* RequestPtr;
+class Request : public FastAlloc
+{
+ friend class Packet;
-/** ASI information for this request if it exsits. */
-const uint32_t ASI_BITS = 0x000FF;
-/** The request is a Load locked/store conditional. */
-const uint32_t LOCKED = 0x00100;
-/** The virtual address is also the physical address. */
-const uint32_t PHYSICAL = 0x00200;
-/** The request is an ALPHA VPTE pal access (hw_ld). */
-const uint32_t VPTE = 0x00400;
-/** Use the alternate mode bits in ALPHA. */
-const uint32_t ALTMODE = 0x00800;
-/** The request is to an uncacheable address. */
-const uint32_t UNCACHEABLE = 0x01000;
-/** The request should not cause a page fault. */
-const uint32_t NO_FAULT = 0x02000;
-/** The request should be prefetched into the exclusive state. */
-const uint32_t PF_EXCLUSIVE = 0x10000;
-/** The request should be marked as LRU. */
-const uint32_t EVICT_NEXT = 0x20000;
-/** The request should ignore unaligned access faults */
-const uint32_t NO_ALIGN_FAULT = 0x40000;
-/** The request was an instruction read. */
-const uint32_t INST_READ = 0x80000;
-/** This request is for a memory swap. */
-const uint32_t MEM_SWAP = 0x100000;
-const uint32_t MEM_SWAP_COND = 0x200000;
-/** The request should ignore unaligned access faults */
-const uint32_t NO_HALF_WORD_ALIGN_FAULT = 0x400000;
+ public:
+ typedef uint32_t FlagsType;
+ typedef ::Flags<FlagsType> Flags;
+
+ /** ASI information for this request if it exists. */
+ static const FlagsType ASI_BITS = 0x000000FF;
+ /** The request is a Load locked/store conditional. */
+ static const FlagsType LOCKED = 0x00000100;
+ /** The virtual address is also the physical address. */
+ static const FlagsType PHYSICAL = 0x00000200;
+ /** The request is an ALPHA VPTE pal access (hw_ld). */
+ static const FlagsType VPTE = 0x00000400;
+ /** Use the alternate mode bits in ALPHA. */
+ static const FlagsType ALTMODE = 0x00000800;
+ /** The request is to an uncacheable address. */
+ static const FlagsType UNCACHEABLE = 0x00001000;
+ /** The request should not cause a page fault. */
+ static const FlagsType NO_FAULT = 0x00002000;
+ /** The request should not cause a memory access. */
+ static const FlagsType NO_ACCESS = 0x00004000;
+ /** The request should be prefetched into the exclusive state. */
+ static const FlagsType PF_EXCLUSIVE = 0x00010000;
+ /** The request should be marked as LRU. */
+ static const FlagsType EVICT_NEXT = 0x00020000;
+ /** The request should ignore unaligned access faults */
+ static const FlagsType NO_ALIGN_FAULT = 0x00040000;
+ /** The request was an instruction read. */
+ static const FlagsType INST_READ = 0x00080000;
+ /** This request is for a memory swap. */
+ static const FlagsType MEM_SWAP = 0x00100000;
+ static const FlagsType MEM_SWAP_COND = 0x00200000;
+ /** The request should ignore unaligned access faults */
+ static const FlagsType NO_HALF_WORD_ALIGN_FAULT = 0x00400000;
+ /** This request is to a memory mapped register. */
+ static const FlagsType MMAPED_IPR = 0x00800000;
+ private:
+ static const FlagsType PUBLIC_FLAGS = 0x00FF3FFF;
+ static const FlagsType PRIVATE_FLAGS = 0xFF000000;
+
+ /** Whether or not the size is valid. */
+ static const FlagsType VALID_SIZE = 0x01000000;
+ /** Whether or not paddr is valid (has been written yet). */
+ static const FlagsType VALID_PADDR = 0x02000000;
+ /** Whether or not the vaddr & asid are valid. */
+ static const FlagsType VALID_VADDR = 0x04000000;
+ /** Whether or not the pc is valid. */
+ static const FlagsType VALID_PC = 0x10000000;
+ /** Whether or not the context ID is valid. */
+ static const FlagsType VALID_CONTEXT_ID = 0x20000000;
+ static const FlagsType VALID_THREAD_ID = 0x40000000;
+ /** Whether or not the sc result is valid. */
+ static const FlagsType VALID_EXTRA_DATA = 0x80000000;
-class Request : public FastAlloc
-{
private:
/**
* The physical address of the request. Valid only if validPaddr
- * is set. */
+ * is set.
+ */
Addr paddr;
/**
* The size of the request. This field must be set when vaddr or
* paddr is written via setVirt() or setPhys(), so it is always
- * valid as long as one of the address fields is valid. */
+ * valid as long as one of the address fields is valid.
+ */
int size;
/** Flag structure for the request. */
- uint32_t flags;
+ Flags flags;
/**
* The time this request was started. Used to calculate
* latencies. This field is set to curTick any time paddr or vaddr
- * is written. */
+ * is written.
+ */
Tick time;
/** The address space ID. */
int asid;
- /** This request is to a memory mapped register. */
- bool mmapedIpr;
-
/** The virtual address of the request. */
Addr vaddr;
- /** Extra data for the request, such as the return value of
+ /**
+ * Extra data for the request, such as the return value of
* store conditional or the compare value for a CAS. */
uint64_t extraData;
- /** The cpu number (for statistics, typically). */
- int cpuNum;
- /** The requesting thread id (for statistics, typically). */
- int threadNum;
+ /** The context ID (for statistics, typically). */
+ int _contextId;
+ /** The thread ID (id within this CPU) */
+ int _threadId;
/** program counter of initiating access; for tracing/debugging */
Addr pc;
- /** Whether or not paddr is valid (has been written yet). */
- bool validPaddr;
- /** Whether or not the asid & vaddr are valid. */
- bool validAsidVaddr;
- /** Whether or not the sc result is valid. */
- bool validExData;
- /** Whether or not the cpu number & thread ID are valid. */
- bool validCpuAndThreadNums;
- /** Whether or not the pc is valid. */
- bool validPC;
-
public:
/** Minimal constructor. No fields are initialized. */
Request()
- : validPaddr(false), validAsidVaddr(false),
- validExData(false), validCpuAndThreadNums(false), validPC(false)
{}
/**
* Constructor for physical (e.g. device) requests. Initializes
* just physical address, size, flags, and timestamp (to curTick).
- * These fields are adequate to perform a request. */
- Request(Addr _paddr, int _size, int _flags)
- : validCpuAndThreadNums(false)
- { setPhys(_paddr, _size, _flags); }
+ * These fields are adequate to perform a request.
+ */
+ Request(Addr paddr, int size, Flags flags)
+ {
+ setPhys(paddr, size, flags);
+ }
- Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc,
- int _cpuNum, int _threadNum)
+ Request(int asid, Addr vaddr, int size, Flags flags, Addr pc,
+ int cid, int tid)
{
- setThreadContext(_cpuNum, _threadNum);
- setVirt(_asid, _vaddr, _size, _flags, _pc);
+ setThreadContext(cid, tid);
+ setVirt(asid, vaddr, size, flags, pc);
}
~Request() {} // for FastAlloc
/**
- * Set up CPU and thread numbers. */
- void setThreadContext(int _cpuNum, int _threadNum)
+ * Set up CPU and thread numbers.
+ */
+ void
+ setThreadContext(int context_id, int thread_id)
{
- cpuNum = _cpuNum;
- threadNum = _threadNum;
- validCpuAndThreadNums = true;
+ _contextId = context_id;
+ _threadId = thread_id;
+ flags.set(VALID_CONTEXT_ID|VALID_THREAD_ID);
}
/**
* Set up a physical (e.g. device) request in a previously
- * allocated Request object. */
- void setPhys(Addr _paddr, int _size, int _flags)
+ * allocated Request object.
+ */
+ void
+ setPhys(Addr _paddr, int _size, Flags _flags)
{
+ assert(_size >= 0);
paddr = _paddr;
size = _size;
- flags = _flags;
time = curTick;
- validPaddr = true;
- validAsidVaddr = false;
- validPC = false;
- validExData = false;
- mmapedIpr = false;
+
+ flags.set(VALID_PADDR|VALID_SIZE);
+ flags.clear(VALID_VADDR|VALID_PC|VALID_EXTRA_DATA|MMAPED_IPR);
+ flags.update(_flags, PUBLIC_FLAGS);
}
/**
* Set up a virtual (e.g., CPU) request in a previously
- * allocated Request object. */
- void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc)
+ * allocated Request object.
+ */
+ void
+ setVirt(int _asid, Addr _vaddr, int _size, Flags _flags, Addr _pc)
{
+ assert(_size >= 0);
asid = _asid;
vaddr = _vaddr;
size = _size;
- flags = _flags;
pc = _pc;
time = curTick;
- validPaddr = false;
- validAsidVaddr = true;
- validPC = true;
- validExData = false;
- mmapedIpr = false;
+
+ flags.set(VALID_VADDR|VALID_SIZE|VALID_PC);
+ flags.clear(VALID_PADDR|VALID_EXTRA_DATA|MMAPED_IPR);
+ flags.update(_flags, PUBLIC_FLAGS);
}
- /** Set just the physical address. This should only be used to
+ /**
+ * Set just the physical address. This should only be used to
* record the result of a translation, and thus the vaddr must be
* valid before this method is called. Otherwise, use setPhys()
* to guarantee that the size and flags are also set.
*/
- void setPaddr(Addr _paddr)
+ void
+ setPaddr(Addr _paddr)
{
- assert(validAsidVaddr);
+ assert(flags.isSet(VALID_VADDR));
paddr = _paddr;
- validPaddr = true;
+ flags.set(VALID_PADDR);
}
- /** Accessor for paddr. */
- Addr getPaddr() { assert(validPaddr); return paddr; }
+ /**
+ * Generate two requests as if this request had been split into two
+ * pieces. The original request can't have been translated already.
+ */
+ void splitOnVaddr(Addr split_addr, RequestPtr &req1, RequestPtr &req2)
+ {
+ assert(flags.isSet(VALID_VADDR));
+ assert(flags.noneSet(VALID_PADDR));
+ assert(split_addr > vaddr && split_addr < vaddr + size);
+ req1 = new Request;
+ *req1 = *this;
+ req2 = new Request;
+ *req2 = *this;
+ req1->size = split_addr - vaddr;
+ req2->vaddr = split_addr;
+ req2->size = size - req1->size;
+ }
+
+ /**
+ * Accessor for paddr.
+ */
+ Addr
+ getPaddr()
+ {
+ assert(flags.isSet(VALID_PADDR));
+ return paddr;
+ }
+
+ /**
+ * Accessor for size.
+ */
+ int
+ getSize()
+ {
+ assert(flags.isSet(VALID_SIZE));
+ return size;
+ }
- /** Accessor for size. */
- int getSize() { assert(validPaddr || validAsidVaddr); return size; }
/** Accessor for time. */
- Tick getTime() { assert(validPaddr || validAsidVaddr); return time; }
+ Tick
+ getTime()
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ return time;
+ }
+
+ void
+ setTime(Tick when)
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ time = when;
+ }
+
+ /** Accessor for flags. */
+ Flags
+ getFlags()
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ return flags & PUBLIC_FLAGS;
+ }
+
+ Flags
+ anyFlags(Flags _flags)
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ assert(_flags.noneSet(~PUBLIC_FLAGS));
+ return flags.isSet(_flags);
+ }
+
+ Flags
+ allFlags(Flags _flags)
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ assert(_flags.noneSet(~PUBLIC_FLAGS));
+ return flags.allSet(_flags);
+ }
/** Accessor for flags. */
- uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; }
- /** Accessor for paddr. */
- void setFlags(uint32_t _flags)
- { assert(validPaddr || validAsidVaddr); flags = _flags; }
+ void
+ setFlags(Flags _flags)
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ assert(_flags.noneSet(~PUBLIC_FLAGS));
+ flags.set(_flags);
+ }
+
+ void
+ clearFlags(Flags _flags)
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ assert(_flags.noneSet(~PUBLIC_FLAGS));
+ flags.clear(_flags);
+ }
+
+ void
+ clearFlags()
+ {
+ assert(flags.isSet(VALID_PADDR|VALID_VADDR));
+ flags.clear(PUBLIC_FLAGS);
+ }
/** Accessor function for vaddr.*/
- Addr getVaddr() { assert(validAsidVaddr); return vaddr; }
+ Addr
+ getVaddr()
+ {
+ assert(flags.isSet(VALID_VADDR));
+ return vaddr;
+ }
/** Accessor function for asid.*/
- int getAsid() { assert(validAsidVaddr); return asid; }
+ int
+ getAsid()
+ {
+ assert(flags.isSet(VALID_VADDR));
+ return asid;
+ }
/** Accessor function for asi.*/
- uint8_t getAsi() { assert(validAsidVaddr); return flags & ASI_BITS; }
+ uint8_t
+ getAsi()
+ {
+ assert(flags.isSet(VALID_VADDR));
+ return flags & ASI_BITS;
+ }
/** Accessor function for asi.*/
- void setAsi(uint8_t a)
- { assert(validAsidVaddr); flags = (flags & ~ASI_BITS) | a; }
+ void
+ setAsi(uint8_t a)
+ {
+ assert(flags.isSet(VALID_VADDR));
+ flags.update(a, ASI_BITS);
+ }
/** Accessor function for asi.*/
- bool isMmapedIpr() { assert(validPaddr); return mmapedIpr; }
+ bool
+ isMmapedIpr()
+ {
+ assert(flags.isSet(VALID_PADDR));
+ return flags.isSet(MMAPED_IPR);
+ }
/** Accessor function for asi.*/
- void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; }
+ void
+ setMmapedIpr(bool r)
+ {
+ assert(VALID_VADDR);
+ flags.set(MMAPED_IPR);
+ }
/** Accessor function to check if sc result is valid. */
- bool extraDataValid() { return validExData; }
+ bool
+ extraDataValid()
+ {
+ return flags.isSet(VALID_EXTRA_DATA);
+ }
+
/** Accessor function for store conditional return value.*/
- uint64_t getExtraData() { assert(validExData); return extraData; }
+ uint64_t
+ getExtraData() const
+ {
+ assert(flags.isSet(VALID_EXTRA_DATA));
+ return extraData;
+ }
+
/** Accessor function for store conditional return value.*/
- void setExtraData(uint64_t _extraData)
- { extraData = _extraData; validExData = true; }
+ void
+ setExtraData(uint64_t _extraData)
+ {
+ extraData = _extraData;
+ flags.set(VALID_EXTRA_DATA);
+ }
- /** Accessor function for cpu number.*/
- int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
- /** Accessor function for thread number.*/
- int getThreadNum() { assert(validCpuAndThreadNums); return threadNum; }
+ bool
+ hasContextId() const
+ {
+ return flags.isSet(VALID_CONTEXT_ID);
+ }
- /** Accessor function for pc.*/
- Addr getPC() { assert(validPC); return pc; }
+ /** Accessor function for context ID.*/
+ int
+ contextId() const
+ {
+ assert(flags.isSet(VALID_CONTEXT_ID));
+ return _contextId;
+ }
- /** Accessor Function to Check Cacheability. */
- bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; }
+ /** Accessor function for thread ID. */
+ int
+ threadId() const
+ {
+ assert(flags.isSet(VALID_THREAD_ID));
+ return _threadId;
+ }
- bool isInstRead() { return (getFlags() & INST_READ) != 0; }
+ bool
+ hasPC() const
+ {
+ return flags.isSet(VALID_PC);
+ }
- bool isLocked() { return (getFlags() & LOCKED) != 0; }
+ /** Accessor function for pc.*/
+ Addr
+ getPC() const
+ {
+ assert(flags.isSet(VALID_PC));
+ return pc;
+ }
+
+ /** Accessor Function to Check Cacheability. */
+ bool isUncacheable() const { return flags.isSet(UNCACHEABLE); }
+ bool isInstRead() const { return flags.isSet(INST_READ); }
+ bool isLocked() const { return flags.isSet(LOCKED); }
+ bool isSwap() const { return flags.isSet(MEM_SWAP|MEM_SWAP_COND); }
+ bool isCondSwap() const { return flags.isSet(MEM_SWAP_COND); }
+
+ bool
+ isMisaligned() const
+ {
+ if (flags.isSet(NO_ALIGN_FAULT))
+ return false;
- bool isSwap() { return (getFlags() & MEM_SWAP ||
- getFlags() & MEM_SWAP_COND); }
+ if ((vaddr & 0x1))
+ return true;
- bool isCondSwap() { return (getFlags() & MEM_SWAP_COND) != 0; }
+ if (flags.isSet(NO_HALF_WORD_ALIGN_FAULT))
+ return false;
- bool inline isMisaligned() {return (!(getFlags() & NO_ALIGN_FAULT) &&
- ((vaddr & 1) ||
- (!(getFlags() & NO_HALF_WORD_ALIGN_FAULT)
- && (vaddr & 0x2))));}
+ if ((vaddr & 0x2))
+ return true;
- friend class Packet;
+ return false;
+ }
};
#endif // __MEM_REQUEST_HH__
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
index 9fa27046b..f937eeb32 100644
--- a/src/mem/tport.cc
+++ b/src/mem/tport.cc
@@ -30,6 +30,21 @@
#include "mem/tport.hh"
+using namespace std;
+
+SimpleTimingPort::SimpleTimingPort(string pname, MemObject *_owner)
+ : Port(pname, _owner), sendEvent(0), drainEvent(NULL),
+ waitingOnRetry(false)
+{
+ sendEvent = new EventWrapper<SimpleTimingPort,
+ &SimpleTimingPort::processSendEvent>(this);
+}
+
+SimpleTimingPort::~SimpleTimingPort()
+{
+ delete sendEvent;
+}
+
bool
SimpleTimingPort::checkFunctional(PacketPtr pkt)
{
@@ -65,7 +80,6 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
// code to hanldle nacks here, but I'm pretty sure it didn't work
// correctly with the drain code, so that would need to be fixed
// if we ever added it back.
- assert(pkt->isRequest());
if (pkt->memInhibitAsserted()) {
// snooper will supply based on copy of packet
@@ -83,7 +97,6 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
assert(pkt->isResponse());
schedSendTiming(pkt, curTick + latency);
} else {
- delete pkt->req;
delete pkt;
}
@@ -104,11 +117,6 @@ SimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when)
return;
}
- // list is non-empty and this is not the head, so event should
- // already be scheduled
- assert(waitingOnRetry ||
- (sendEvent->scheduled() && sendEvent->when() <= when));
-
// list is non-empty & this belongs at the end
if (when >= transmitList.back().tick) {
transmitList.push_back(DeferredPacket(when, pkt));
@@ -144,7 +152,7 @@ SimpleTimingPort::sendDeferredPacket()
if (success) {
if (!transmitList.empty() && !sendEvent->scheduled()) {
Tick time = transmitList.front().tick;
- sendEvent->schedule(time <= curTick ? curTick+1 : time);
+ schedule(sendEvent, time <= curTick ? curTick+1 : time);
}
if (transmitList.empty() && drainEvent) {
diff --git a/src/mem/tport.hh b/src/mem/tport.hh
index d0f1be425..7dfe60b72 100644
--- a/src/mem/tport.hh
+++ b/src/mem/tport.hh
@@ -85,9 +85,6 @@ class SimpleTimingPort : public Port
* When the event time expires it attempts to send the packet.
* If it cannot, the packet sent when recvRetry() is called.
**/
- typedef EventWrapper<SimpleTimingPort, &SimpleTimingPort::processSendEvent>
- SendEvent;
-
Event *sendEvent;
/** If we need to drain, keep the drain event around until we're done
@@ -108,7 +105,8 @@ class SimpleTimingPort : public Port
Tick deferredPacketReadyTime()
{ return transmitList.empty() ? MaxTick : transmitList.front().tick; }
- void schedSendEvent(Tick when)
+ void
+ schedSendEvent(Tick when)
{
if (waitingOnRetry) {
assert(!sendEvent->scheduled());
@@ -116,9 +114,9 @@ class SimpleTimingPort : public Port
}
if (!sendEvent->scheduled()) {
- sendEvent->schedule(when);
+ schedule(sendEvent, when);
} else if (sendEvent->when() > when) {
- sendEvent->reschedule(when);
+ reschedule(sendEvent, when);
}
}
@@ -154,15 +152,8 @@ class SimpleTimingPort : public Port
public:
-
- SimpleTimingPort(std::string pname, MemObject *_owner = NULL)
- : Port(pname, _owner),
- sendEvent(new SendEvent(this)),
- drainEvent(NULL),
- waitingOnRetry(false)
- {}
-
- ~SimpleTimingPort() { delete sendEvent; }
+ SimpleTimingPort(std::string pname, MemObject *_owner);
+ ~SimpleTimingPort();
/** Hook for draining timing accesses from the system. The
* associated SimObject's drain() functions should be implemented
diff --git a/src/mem/vport.cc b/src/mem/vport.cc
index 6cc4d9ca9..15be45c2a 100644
--- a/src/mem/vport.cc
+++ b/src/mem/vport.cc
@@ -75,23 +75,18 @@ void
CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen)
{
uint8_t *dst = (uint8_t *)dest;
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
vp->readBlob(src, dst, cplen);
-
- tc->delVirtPort(vp);
-
}
void
CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen)
{
uint8_t *src = (uint8_t *)source;
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
vp->writeBlob(dest, src, cplen);
-
- tc->delVirtPort(vp);
}
void
@@ -99,25 +94,23 @@ CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen)
{
int len = 0;
char *start = dst;
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
do {
vp->readBlob(vaddr++, (uint8_t*)dst++, 1);
} while (len < maxlen && start[len++] != 0 );
- tc->delVirtPort(vp);
dst[len] = 0;
}
void
CopyStringIn(ThreadContext *tc, char *src, Addr vaddr)
{
- VirtualPort *vp = tc->getVirtPort(tc);
+ VirtualPort *vp = tc->getVirtPort();
for (ChunkGenerator gen(vaddr, strlen(src), TheISA::PageBytes); !gen.done();
gen.next())
{
vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size());
src += gen.size();
}
- tc->delVirtPort(vp);
}
diff --git a/src/python/SConscript b/src/python/SConscript
index b39c9ea9c..a767545ec 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -34,20 +34,28 @@ Import('*')
Source('swig/pyevent.cc')
Source('swig/pyobject.cc')
+PySource('', 'importer.py')
PySource('m5', 'm5/__init__.py')
PySource('m5', 'm5/SimObject.py')
-PySource('m5', 'm5/attrdict.py')
+PySource('m5', 'm5/config.py')
PySource('m5', 'm5/convert.py')
+PySource('m5', 'm5/core.py')
+PySource('m5', 'm5/debug.py')
PySource('m5', 'm5/event.py')
PySource('m5', 'm5/main.py')
-PySource('m5', 'm5/multidict.py')
+PySource('m5', 'm5/options.py')
PySource('m5', 'm5/params.py')
PySource('m5', 'm5/proxy.py')
PySource('m5', 'm5/simulate.py')
PySource('m5', 'm5/smartdict.py')
PySource('m5', 'm5/stats.py')
PySource('m5', 'm5/ticks.py')
-PySource('m5', 'm5/util.py')
+PySource('m5', 'm5/trace.py')
+PySource('m5.util', 'm5/util/__init__.py')
+PySource('m5.util', 'm5/util/attrdict.py')
+PySource('m5.util', 'm5/util/jobfile.py')
+PySource('m5.util', 'm5/util/misc.py')
+PySource('m5.util', 'm5/util/multidict.py')
SwigSource('m5.internal', 'swig/core.i')
SwigSource('m5.internal', 'swig/debug.i')
diff --git a/src/python/generate.py b/src/python/generate.py
deleted file mode 100644
index eead6ff5d..000000000
--- a/src/python/generate.py
+++ /dev/null
@@ -1,529 +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.
-#
-# Authors: Nathan Binkert
-
-import imp
-import py_compile
-import sys
-import zipfile
-
-from os.path import basename
-from os.path import exists
-
-class DictImporter(object):
- '''This importer takes a dictionary of arbitrary module names that
- map to arbitrary filenames.'''
- def __init__(self, modules, build_env):
- self.modules = modules
- self.installed = set()
- self.build_env = build_env
-
- def __del__(self):
- self.unload()
-
- def unload(self):
- import sys
- for module in self.installed:
- del sys.modules[module]
- self.installed = set()
-
- def find_module(self, fullname, path):
- if fullname == '__scons':
- return self
-
- if fullname == 'm5.objects':
- return self
-
- if fullname.startswith('m5.internal'):
- return None
-
- if fullname in self.modules and exists(self.modules[fullname]):
- return self
-
- return None
-
- def load_module(self, fullname):
- mod = imp.new_module(fullname)
- sys.modules[fullname] = mod
- self.installed.add(fullname)
-
- mod.__loader__ = self
- if fullname == 'm5.objects':
- mod.__path__ = fullname.split('.')
- return mod
-
- if fullname == '__scons':
- mod.__dict__['m5_build_env'] = self.build_env
- return mod
-
- srcfile = self.modules[fullname]
- if basename(srcfile) == '__init__.py':
- mod.__path__ = fullname.split('.')
- mod.__file__ = srcfile
-
- exec file(srcfile, 'r') in mod.__dict__
-
- return mod
-
-class ordered_dict(dict):
- def keys(self):
- keys = super(ordered_dict, self).keys()
- keys.sort()
- return keys
-
- def values(self):
- return [ self[key] for key in self.keys() ]
-
- def items(self):
- return [ (key,self[key]) for key in self.keys() ]
-
- def iterkeys(self):
- for key in self.keys():
- yield key
-
- def itervalues(self):
- for value in self.values():
- yield value
-
- def iteritems(self):
- for key,value in self.items():
- yield key, value
-
-class Generate(object):
- def __init__(self, py_sources, sim_objects, build_env):
- self.py_sources = py_sources
- self.py_modules = {}
- for source in py_sources:
- self.py_modules[source.modpath] = source.srcpath
-
- importer = DictImporter(self.py_modules, build_env)
-
- # install the python importer so we can grab stuff from the source
- # tree itself.
- sys.meta_path[0:0] = [ importer ]
-
- import m5
- self.m5 = m5
-
- # import all sim objects so we can populate the all_objects list
- # make sure that we're working with a list, then let's sort it
- sim_objects = list(sim_objects)
- sim_objects.sort()
- for simobj in sim_objects:
- exec('from m5.objects import %s' % simobj)
-
- # we need to unload all of the currently imported modules so that they
- # will be re-imported the next time the sconscript is run
- importer.unload()
- sys.meta_path.remove(importer)
-
- self.sim_objects = m5.SimObject.allClasses
- self.enums = m5.params.allEnums
-
- self.params = {}
- for name,obj in self.sim_objects.iteritems():
- for param in obj._params.local.values():
- if not hasattr(param, 'swig_decl'):
- continue
- pname = param.ptype_str
- if pname not in self.params:
- self.params[pname] = param
-
- def createSimObjectParam(self, target, source, env):
- assert len(target) == 1 and len(source) == 1
-
- hh_file = file(target[0].abspath, 'w')
- name = str(source[0].get_contents())
- obj = self.sim_objects[name]
-
- print >>hh_file, obj.cxx_decl()
-
- # Generate Python file containing a dict specifying the current
- # build_env flags.
- def makeDefinesPyFile(self, target, source, env):
- f = file(str(target[0]), 'w')
- print >>f, "m5_build_env = ", source[0]
- f.close()
-
- # Generate python file containing info about the M5 source code
- def makeInfoPyFile(self, target, source, env):
- f = file(str(target[0]), 'w')
- for src in source:
- data = ''.join(file(src.srcnode().abspath, 'r').xreadlines())
- print >>f, "%s = %s" % (src, repr(data))
- f.close()
-
- # Generate the __init__.py file for m5.objects
- def makeObjectsInitFile(self, target, source, env):
- f = file(str(target[0]), 'w')
- print >>f, 'from params import *'
- print >>f, 'from m5.SimObject import *'
- for module in source:
- print >>f, 'from %s import *' % module.get_contents()
- f.close()
-
- def createSwigParam(self, target, source, env):
- assert len(target) == 1 and len(source) == 1
-
- i_file = file(target[0].abspath, 'w')
- name = str(source[0].get_contents())
- param = self.params[name]
-
- for line in param.swig_decl():
- print >>i_file, line
-
- def createEnumStrings(self, target, source, env):
- assert len(target) == 1 and len(source) == 1
-
- cc_file = file(target[0].abspath, 'w')
- name = str(source[0].get_contents())
- obj = self.enums[name]
-
- print >>cc_file, obj.cxx_def()
- cc_file.close()
-
- def createEnumParam(self, target, source, env):
- assert len(target) == 1 and len(source) == 1
-
- hh_file = file(target[0].abspath, 'w')
- name = str(source[0].get_contents())
- obj = self.enums[name]
-
- print >>hh_file, obj.cxx_decl()
-
- def buildParams(self, target, source, env):
- names = [ s.get_contents() for s in source ]
- objs = [ self.sim_objects[name] for name in names ]
- out = file(target[0].abspath, 'w')
-
- ordered_objs = []
- obj_seen = set()
- def order_obj(obj):
- name = str(obj)
- if name in obj_seen:
- return
-
- obj_seen.add(name)
- if str(obj) != 'SimObject':
- order_obj(obj.__bases__[0])
-
- ordered_objs.append(obj)
-
- for obj in objs:
- order_obj(obj)
-
- enums = set()
- predecls = []
- pd_seen = set()
-
- def add_pds(*pds):
- for pd in pds:
- if pd not in pd_seen:
- predecls.append(pd)
- pd_seen.add(pd)
-
- for obj in ordered_objs:
- params = obj._params.local.values()
- for param in params:
- ptype = param.ptype
- if issubclass(ptype, self.m5.params.Enum):
- if ptype not in enums:
- enums.add(ptype)
- pds = param.swig_predecls()
- if isinstance(pds, (list, tuple)):
- add_pds(*pds)
- else:
- add_pds(pds)
-
- print >>out, '%module params'
-
- print >>out, '%{'
- for obj in ordered_objs:
- print >>out, '#include "params/%s.hh"' % obj
- print >>out, '%}'
-
- for pd in predecls:
- print >>out, pd
-
- enums = list(enums)
- enums.sort()
- for enum in enums:
- print >>out, '%%include "enums/%s.hh"' % enum.__name__
- print >>out
-
- for obj in ordered_objs:
- if obj.swig_objdecls:
- for decl in obj.swig_objdecls:
- print >>out, decl
- continue
-
- code = ''
- base = obj.get_base()
-
- code += '// stop swig from creating/wrapping default ctor/dtor\n'
- code += '%%nodefault %s;\n' % obj.cxx_class
- code += 'class %s ' % obj.cxx_class
- if base:
- code += ': public %s' % base
- code += ' {};\n'
-
- klass = obj.cxx_class;
- if hasattr(obj, 'cxx_namespace'):
- new_code = 'namespace %s {\n' % obj.cxx_namespace
- new_code += code
- new_code += '}\n'
- code = new_code
- klass = '%s::%s' % (obj.cxx_namespace, klass)
-
- print >>out, code
-
- for obj in ordered_objs:
- print >>out, '%%include "params/%s.hh"' % obj
-
- def makeSwigInit(self, target, source, env):
- f = file(str(target[0]), 'w')
- print >>f, 'extern "C" {'
- for module in source:
- print >>f, ' void init_%s();' % module.get_contents()
- print >>f, '}'
- print >>f, 'void init_swig() {'
- for module in source:
- print >>f, ' init_%s();' % module.get_contents()
- print >>f, '}'
- f.close()
-
- def compilePyFile(self, target, source, env):
- '''Action function to compile a .py into a .pyc'''
- py_compile.compile(str(source[0]), str(target[0]))
-
- def buildPyZip(self, target, source, env):
- '''Action function to build the zip archive. Uses the
- PyZipFile module included in the standard Python library.'''
-
- py_compiled = {}
- for s in self.py_sources:
- compname = str(s.compiled)
- assert compname not in py_compiled
- py_compiled[compname] = s
-
- zf = zipfile.ZipFile(str(target[0]), 'w')
- for s in source:
- zipname = str(s)
- arcname = py_compiled[zipname].arcname
- zf.write(zipname, arcname)
- zf.close()
-
- def traceFlagsPy(self, target, source, env):
- assert(len(target) == 1)
-
- f = file(str(target[0]), 'w')
-
- allFlags = []
- for s in source:
- val = eval(s.get_contents())
- allFlags.append(val)
-
- print >>f, 'baseFlags = ['
- for flag, compound, desc in allFlags:
- if not compound:
- print >>f, " '%s'," % flag
- print >>f, " ]"
- print >>f
-
- print >>f, 'compoundFlags = ['
- print >>f, " 'All',"
- for flag, compound, desc in allFlags:
- if compound:
- print >>f, " '%s'," % flag
- print >>f, " ]"
- print >>f
-
- print >>f, "allFlags = frozenset(baseFlags + compoundFlags)"
- print >>f
-
- print >>f, 'compoundFlagMap = {'
- all = tuple([flag for flag,compound,desc in allFlags if not compound])
- print >>f, " 'All' : %s," % (all, )
- for flag, compound, desc in allFlags:
- if compound:
- print >>f, " '%s' : %s," % (flag, compound)
- print >>f, " }"
- print >>f
-
- print >>f, 'flagDescriptions = {'
- print >>f, " 'All' : 'All flags',"
- for flag, compound, desc in allFlags:
- print >>f, " '%s' : '%s'," % (flag, desc)
- print >>f, " }"
-
- f.close()
-
- def traceFlagsCC(self, target, source, env):
- assert(len(target) == 1)
-
- f = file(str(target[0]), 'w')
-
- allFlags = []
- for s in source:
- val = eval(s.get_contents())
- allFlags.append(val)
-
- # file header
- print >>f, '''
-/*
- * DO NOT EDIT THIS FILE! Automatically generated
- */
-
-#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, compound, desc in allFlags:
- if not compound:
- print >>f, ' "%s",' % flag
-
- print >>f, ' "All",'
- for flag, compound, desc in allFlags:
- if compound:
- print >>f, ' "%s",' % flag
-
- print >>f, '};'
- print >>f
- print >>f, 'const int Trace::numFlagStrings = %d;' % (len(allFlags) + 1)
- print >>f
-
- #
- # Now define the individual compound flag arrays. There is an array
- # for each compound flag listing the component base flags.
- #
- all = tuple([flag for flag,compound,desc in allFlags if not compound])
- print >>f, 'static const Flags AllMap[] = {'
- for flag, compound, desc in allFlags:
- if not compound:
- print >>f, " %s," % flag
- print >>f, '};'
- print >>f
-
- for flag, compound, desc in allFlags:
- if not compound:
- continue
- print >>f, 'static const Flags %sMap[] = {' % flag
- for flag in compound:
- print >>f, " %s," % flag
- print >>f, " (Flags)-1"
- print >>f, '};'
- print >>f
-
- #
- # Finally the compoundFlags[] array maps the compound flags
- # to their individual arrays/
- #
- print >>f, 'const Flags *Trace::compoundFlags[] ='
- print >>f, '{'
- print >>f, ' AllMap,'
- for flag, compound, desc in allFlags:
- if compound:
- print >>f, ' %sMap,' % flag
- # file trailer
- print >>f, '};'
-
- f.close()
-
- def traceFlagsHH(self, target, source, env):
- assert(len(target) == 1)
-
- f = file(str(target[0]), 'w')
-
- allFlags = []
- for s in source:
- val = eval(s.get_contents())
- allFlags.append(val)
-
- # file header boilerplate
- print >>f, '''
-/*
- * 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, compound, desc in allFlags:
- if not compound:
- print >>f, ' %s = %d,' % (flag, idx)
- idx += 1
-
- numBaseFlags = idx
- print >>f, ' NumFlags = %d,' % idx
-
- # put a comment in here to separate base from compound flags
- print >>f, '''
-// 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 by changeFlag.'''
-
- print >>f, ' All = %d,' % idx
- idx += 1
- for flag, compound, desc in allFlags:
- if compound:
- print >>f, ' %s = %d,' % (flag, idx)
- idx += 1
-
- numCompoundFlags = idx - numBaseFlags
- print >>f, ' NumCompoundFlags = %d' % numCompoundFlags
-
- # trailer boilerplate
- print >>f, '''\
-}; // 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__
-'''
-
- f.close()
diff --git a/src/python/importer.py b/src/python/importer.py
new file mode 100644
index 000000000..fe099fdb8
--- /dev/null
+++ b/src/python/importer.py
@@ -0,0 +1,80 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+# Simple importer that allows python to import data from a dict of
+# code objects. The keys are the module path, and the items are the
+# filename and bytecode of the file.
+class CodeImporter(object):
+ def __init__(self):
+ self.modules = {}
+
+ def add_module(self, filename, modpath, code):
+ if modpath in self.modules:
+ raise AttributeError, "%s already found in importer"
+
+ self.modules[modpath] = (filename, code)
+
+ def find_module(self, fullname, path):
+ if fullname in self.modules:
+ return self
+
+ return None
+
+ def load_module(self, fullname):
+ # Because the importer is created and initialized in its own
+ # little sandbox (in init.cc), the globals that were available
+ # when the importer module was loaded and CodeImporter was
+ # defined are not available when load_module is actually
+ # called. Soooo, the imports must live here.
+ import imp
+ import os
+ import sys
+ mod = imp.new_module(fullname)
+ sys.modules[fullname] = mod
+
+ try:
+ mod.__loader__ = self
+ srcfile,code = self.modules[fullname]
+ if os.path.basename(srcfile) == '__init__.py':
+ mod.__path__ = fullname.split('.')
+ mod.__file__ = srcfile
+
+ exec code in mod.__dict__
+ except Exception:
+ del sys.modules[fullname]
+ raise
+
+ return mod
+
+# Create an importer and add it to the meta_path so future imports can
+# use it. There's currently nothing in the importer, but calls to
+# add_module can be used to add code.
+import sys
+importer = CodeImporter()
+add_module = importer.add_module
+sys.meta_path.append(importer)
diff --git a/src/python/m5/SimObject.py b/src/python/m5/SimObject.py
index 78df6bef1..8ef22be4e 100644
--- a/src/python/m5/SimObject.py
+++ b/src/python/m5/SimObject.py
@@ -27,12 +27,13 @@
# Authors: Steve Reinhardt
# Nathan Binkert
-import sys, types
+import math
+import sys
+import types
import proxy
import m5
from util import *
-from multidict import multidict
# These utility functions have to come first because they're
# referenced in params.py... otherwise they won't be defined when we
@@ -64,6 +65,7 @@ from params import *
# There are a few things we need that aren't in params.__all__ since
# normal users don't need them
from params import ParamDesc, VectorParamDesc, isNullPointer, SimObjVector
+from proxy import *
noDot = False
try:
@@ -124,7 +126,6 @@ instanceDict = {}
class MetaSimObject(type):
# Attributes that can be set only at initialization time
init_keywords = { 'abstract' : types.BooleanType,
- 'cxx_namespace' : types.StringType,
'cxx_class' : types.StringType,
'cxx_type' : types.StringType,
'cxx_predecls' : types.ListType,
@@ -191,33 +192,31 @@ class MetaSimObject(type):
# the following is not true is when we define the SimObject
# class itself (in which case the multidicts have no parent).
if isinstance(base, MetaSimObject):
+ cls._base = base
cls._params.parent = base._params
cls._ports.parent = base._ports
cls._values.parent = base._values
cls._port_refs.parent = base._port_refs
# mark base as having been subclassed
base._instantiated = True
+ else:
+ cls._base = None
# default keyword values
if 'type' in cls._value_dict:
- _type = cls._value_dict['type']
if 'cxx_class' not in cls._value_dict:
- cls._value_dict['cxx_class'] = _type
+ cls._value_dict['cxx_class'] = cls._value_dict['type']
- namespace = cls._value_dict.get('cxx_namespace', None)
-
- _cxx_class = cls._value_dict['cxx_class']
- if 'cxx_type' not in cls._value_dict:
- t = _cxx_class + '*'
- if namespace:
- t = '%s::%s' % (namespace, t)
- cls._value_dict['cxx_type'] = t
+ cls._value_dict['cxx_type'] = '%s *' % cls._value_dict['cxx_class']
+
if 'cxx_predecls' not in cls._value_dict:
# A forward class declaration is sufficient since we are
# just declaring a pointer.
- decl = 'class %s;' % _cxx_class
- if namespace:
- decl = 'namespace %s { %s }' % (namespace, decl)
+ class_path = cls._value_dict['cxx_class'].split('::')
+ class_path.reverse()
+ decl = 'class %s;' % class_path[0]
+ for ns in class_path[1:]:
+ decl = 'namespace %s { %s }' % (ns, decl)
cls._value_dict['cxx_predecls'] = [decl]
if 'swig_predecls' not in cls._value_dict:
@@ -349,12 +348,6 @@ class MetaSimObject(type):
def __str__(cls):
return cls.__name__
- def get_base(cls):
- if str(cls) == 'SimObject':
- return None
-
- return cls.__bases__[0].type
-
def cxx_decl(cls):
code = "#ifndef __PARAMS__%s\n" % cls
code += "#define __PARAMS__%s\n\n" % cls
@@ -385,22 +378,29 @@ class MetaSimObject(type):
code += "\n".join(predecls2)
code += "\n\n";
- base = cls.get_base()
- if base:
- code += '#include "params/%s.hh"\n\n' % base
+ if cls._base:
+ code += '#include "params/%s.hh"\n\n' % cls._base.type
for ptype in ptypes:
if issubclass(ptype, Enum):
code += '#include "enums/%s.hh"\n' % ptype.__name__
code += "\n\n"
+ code += cls.cxx_struct(cls._base, params)
+
+ # close #ifndef __PARAMS__* guard
+ code += "\n#endif\n"
+ return code
+
+ def cxx_struct(cls, base, params):
+ if cls == SimObject:
+ return '#include "sim/sim_object_params.hh"\n'
+
# now generate the actual param struct
- code += "struct %sParams" % cls
+ code = "struct %sParams" % cls
if base:
- code += " : public %sParams" % base
+ code += " : public %sParams" % base.type
code += "\n{\n"
- if cls == SimObject:
- code += " virtual ~%sParams() {}\n" % cls
if not hasattr(cls, 'abstract') or not cls.abstract:
if 'type' in cls.__dict__:
code += " %s create();\n" % cls.cxx_type
@@ -409,28 +409,9 @@ class MetaSimObject(type):
code += "".join([" %s\n" % d for d in decls])
code += "};\n"
- # close #ifndef __PARAMS__* guard
- code += "\n#endif\n"
- return code
-
- def cxx_type_decl(cls):
- base = cls.get_base()
- code = ''
-
- if base:
- code += '#include "%s_type.h"\n' % base
-
- # now generate dummy code for inheritance
- code += "struct %s" % cls.cxx_class
- if base:
- code += " : public %s" % base.cxx_class
- code += "\n{};\n"
-
return code
def swig_decl(cls):
- base = cls.get_base()
-
code = '%%module %s\n' % cls
code += '%{\n'
@@ -458,8 +439,8 @@ class MetaSimObject(type):
code += "\n".join(predecls2)
code += "\n\n";
- if base:
- code += '%%import "params/%s.i"\n\n' % base
+ if cls._base:
+ code += '%%import "params/%s.i"\n\n' % cls._base.type
for ptype in ptypes:
if issubclass(ptype, Enum):
@@ -481,7 +462,6 @@ class SimObject(object):
type = 'SimObject'
abstract = True
- name = Param.String("Object name")
swig_objdecls = [ '%include "python/swig/sim_object.i"' ]
# Initialize new instance. For objects with SimObject-valued
@@ -650,8 +630,9 @@ class SimObject(object):
if len(value) == 1:
value[0]._maybe_set_parent(self, attr)
else:
+ width = int(math.ceil(math.log(len(value))/math.log(10)))
for i,v in enumerate(value):
- v._maybe_set_parent(self, "%s%d" % (attr, i))
+ v._maybe_set_parent(self, "%s%0*d" % (attr, width, i))
self._values[attr] = value
@@ -687,7 +668,7 @@ class SimObject(object):
match_obj = self._values[pname]
if found_obj != None and found_obj != match_obj:
raise AttributeError, \
- 'parent.any matched more than one: %s' % obj.path
+ 'parent.any matched more than one: %s and %s' % (found_obj.path, match_obj.path)
found_obj = match_obj
return found_obj, found_obj != None
@@ -722,7 +703,7 @@ class SimObject(object):
self._children[child].unproxy_all()
def print_ini(self, ini_file):
- print >>ini_file, '[' + self.path() + ']' # .ini section header
+ print >>ini_file, '[' + self.path() + ']' # .ini section header
instanceDict[self.path()] = self
@@ -749,7 +730,7 @@ class SimObject(object):
if port != None:
print >>ini_file, '%s=%s' % (port_name, port.ini_str())
- print >>ini_file # blank line between objects
+ print >>ini_file # blank line between objects
for child in child_names:
self._children[child].print_ini(ini_file)
@@ -760,7 +741,7 @@ class SimObject(object):
cc_params_struct = getattr(m5.objects.params, '%sParams' % self.type)
cc_params = cc_params_struct()
- cc_params.object = self
+ cc_params.pyobj = self
cc_params.name = str(self)
param_names = self._params.keys()
@@ -768,7 +749,8 @@ class SimObject(object):
for param in param_names:
value = self._values.get(param)
if value is None:
- continue
+ m5.fatal("%s.%s without default or user set value",
+ self.path(), param)
value = value.getValue()
if isinstance(self._params[param], VectorParamDesc):
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
index f21bb362e..733258acf 100644
--- a/src/python/m5/__init__.py
+++ b/src/python/m5/__init__.py
@@ -36,8 +36,31 @@ import smartdict
MaxTick = 2**63 - 1
# define this here so we can use it right away if necessary
-def panic(string):
- print >>sys.stderr, 'panic:', string
+
+def errorURL(prefix, s):
+ try:
+ import zlib
+ hashstr = "%x" % zlib.crc32(s)
+ except:
+ hashstr = "UnableToHash"
+ return "For more information see: http://www.m5sim.org/%s/%s" % \
+ (prefix, hashstr)
+
+
+# panic() should be called when something happens that should never
+# ever happen regardless of what the user does (i.e., an acutal m5
+# bug).
+def panic(fmt, *args):
+ print >>sys.stderr, 'panic:', fmt % args
+ print >>sys.stderr, errorURL('panic',fmt)
+ sys.exit(1)
+
+# fatal() should be called when the simulation cannot continue due to
+# some condition that is the user's fault (bad configuration, invalid
+# arguments, etc.) and not a simulator bug.
+def fatal(fmt, *args):
+ print >>sys.stderr, 'fatal:', fmt % args
+ print >>sys.stderr, errorURL('fatal',fmt)
sys.exit(1)
# force scalars to one-element lists for uniformity
@@ -77,22 +100,23 @@ env.update(os.environ)
# importing *you*).
try:
import internal
- running_m5 = True
except ImportError:
- running_m5 = False
+ internal = None
+
+import defines
+build_env.update(defines.buildEnv)
-if running_m5:
- import defines
- build_env.update(defines.m5_build_env)
-else:
- import __scons
- build_env.update(__scons.m5_build_env)
+if internal:
+ defines.compileDate = internal.core.compileDate
+ for k,v in internal.core.__dict__.iteritems():
+ if k.startswith('flag_'):
+ setattr(defines, k[5:], v)
-if running_m5:
from event import *
from simulate import *
- from main import options
+ from main import options, main
import stats
+ import core
import SimObject
import params
diff --git a/src/python/m5/config.py b/src/python/m5/config.py
new file mode 100644
index 000000000..c28f6675a
--- /dev/null
+++ b/src/python/m5/config.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+import os
+from os.path import isdir, isfile, join as joinpath
+
+
+confdir = os.environ.get('M5_CONFIG')
+
+if not confdir:
+ # HOME is not set when running regressions, due to use of scons
+ # Execute() function.
+ homedir = os.environ.get('HOME')
+ if homedir and isdir(joinpath(homedir, '.m5')):
+ confdir = joinpath(homedir, '.m5')
+
+def get(name):
+ if not confdir:
+ return None
+ conffile = joinpath(confdir, name)
+ if not isfile(conffile):
+ return None
+
+ return conffile
+
diff --git a/src/python/m5/core.py b/src/python/m5/core.py
new file mode 100644
index 000000000..1d7985be6
--- /dev/null
+++ b/src/python/m5/core.py
@@ -0,0 +1,40 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+import internal
+from internal.core import initAll, regAllStats
+
+def setOutputDir(dir):
+ internal.core.setOutputDir(dir)
+
+def initAll():
+ internal.core.initAll()
+
+def regAllStats():
+ internal.core.regAllStats()
+
diff --git a/src/python/m5/debug.py b/src/python/m5/debug.py
new file mode 100644
index 000000000..cd40b8fa3
--- /dev/null
+++ b/src/python/m5/debug.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+import internal
+
+from internal.debug import schedBreakCycle, setRemoteGDBPort
diff --git a/src/python/m5/event.py b/src/python/m5/event.py
index 2d6497464..35095599d 100644
--- a/src/python/m5/event.py
+++ b/src/python/m5/event.py
@@ -26,17 +26,36 @@
#
# Authors: Nathan Binkert
-from internal.event import create
-from internal.event import SimLoopExitEvent as SimExit
+import m5
+import internal.event
+
+from internal.event import PythonEvent, SimLoopExitEvent as SimExit
+
+mainq = internal.event.cvar.mainEventQueue
+
+def create(obj, priority=None):
+ if priority is None:
+ priority = Event.Default_Pri
+ return PythonEvent(obj, priority)
-class ProgressEvent(object):
- def __init__(self, period):
- self.period = int(period)
- self.schedule()
- def schedule(self):
- create(self, m5.curTick() + self.period)
+# As a reminder, priorities found in sim/eventq.hh are stuck into the
+# Event class by swig
+class Event(PythonEvent):
+ def __init__(self, priority=None):
+ if priority is None:
+ priority = Event.Default_Pri
+ super(Event, self).__init__(self, priority)
+
+class ProgressEvent(Event):
+ def __init__(self, eventq, period):
+ super(ProgressEvent, self).__init__()
+ self.period = int(period)
+ self.eventq = eventq
+ self.eventq.schedule(self, m5.curTick() + self.period)
def __call__(self):
print "Progress! Time now %fs" % (m5.curTick()/1e12)
- self.schedule()
+ self.eventq.schedule(self, m5.curTick() + self.period)
+
+__all__ = [ 'create', 'Event', 'ProgressEvent', 'SimExit', 'mainq' ]
diff --git a/src/python/m5/main.py b/src/python/m5/main.py
index 4bcca46d2..98019b197 100644
--- a/src/python/m5/main.py
+++ b/src/python/m5/main.py
@@ -28,14 +28,13 @@
import code
import datetime
-import optparse
import os
import socket
import sys
-from attrdict import attrdict
-import defines
-import traceflags
+from util import attrdict
+import config
+from options import OptionParser
__all__ = [ 'options', 'arguments', 'main' ]
@@ -47,77 +46,11 @@ The Regents of The University of Michigan
All Rights Reserved
'''
-def print_list(items, indent=4):
- line = ' ' * indent
- for i,item in enumerate(items):
- if len(line) + len(item) > 76:
- print line
- line = ' ' * indent
-
- if i < len(items) - 1:
- line += '%s, ' % item
- else:
- line += item
- print line
-
-# there's only one option parsing done, so make it global and add some
-# helper functions to make it work well.
-parser = optparse.OptionParser(usage=usage, version=version,
- description=brief_copyright,
- formatter=optparse.TitledHelpFormatter())
-parser.disable_interspersed_args()
-
-# current option group
-group = None
-
-def set_group(*args, **kwargs):
- '''set the current option group'''
- global group
- if not args and not kwargs:
- group = None
- else:
- group = parser.add_option_group(*args, **kwargs)
-
-class splitter(object):
- def __init__(self, split):
- self.split = split
- def __call__(self, option, opt_str, value, parser):
- getattr(parser.values, option.dest).extend(value.split(self.split))
-
-def add_option(*args, **kwargs):
- '''add an option to the current option group, or global none set'''
-
- # if action=split, but allows the option arguments
- # themselves to be lists separated by the split variable'''
-
- if kwargs.get('action', None) == 'append' and 'split' in kwargs:
- split = kwargs.pop('split')
- kwargs['default'] = []
- kwargs['type'] = 'string'
- kwargs['action'] = 'callback'
- kwargs['callback'] = splitter(split)
-
- if group:
- return group.add_option(*args, **kwargs)
-
- return parser.add_option(*args, **kwargs)
-
-def bool_option(name, default, help):
- '''add a boolean option called --name and --no-name.
- Display help depending on which is the default'''
-
- tname = '--%s' % name
- fname = '--no-%s' % name
- dest = name.replace('-', '_')
- if default:
- thelp = optparse.SUPPRESS_HELP
- fhelp = help
- else:
- thelp = help
- fhelp = optparse.SUPPRESS_HELP
-
- add_option(tname, action="store_true", default=default, help=thelp)
- add_option(fname, action="store_false", dest=dest, help=fhelp)
+options = OptionParser(usage=usage, version=version,
+ description=brief_copyright)
+add_option = options.add_option
+set_group = options.set_group
+usage = options.usage
# Help options
add_option('-A', "--authors", action="store_true", default=False,
@@ -132,8 +65,16 @@ add_option('-N', "--release-notes", action="store_true", default=False,
help="Show the release notes")
# Options for configuring the base simulator
-add_option('-d', "--outdir", metavar="DIR", default=".",
+add_option('-d', "--outdir", metavar="DIR", default="m5out",
help="Set the output directory to DIR [Default: %default]")
+add_option('-r', "--redirect-stdout", action="store_true", default=False,
+ help="Redirect stdout (& stderr, without -e) to file")
+add_option('-e', "--redirect-stderr", action="store_true", default=False,
+ help="Redirect stderr to file")
+add_option("--stdout-file", metavar="FILE", default="simout",
+ help="Filename for -r redirection [Default: %default]")
+add_option("--stderr-file", metavar="FILE", default="simerr",
+ help="Filename for -e redirection [Default: %default]")
add_option('-i', "--interactive", action="store_true", default=False,
help="Invoke the interactive interpreter after running the script")
add_option("--pdb", action="store_true", default=False,
@@ -147,13 +88,20 @@ add_option('-v', "--verbose", action="count", default=0,
# Statistics options
set_group("Statistics Options")
-add_option("--stats-file", metavar="FILE", default="m5stats.txt",
+add_option("--stats-file", metavar="FILE", default="stats.txt",
help="Sets the output file for statistics [Default: %default]")
+# Configuration Options
+set_group("Configuration Options")
+add_option("--dump-config", metavar="FILE", default="config.ini",
+ help="Dump configuration output file [Default: %default]")
+
# Debugging options
set_group("Debugging Options")
add_option("--debug-break", metavar="TIME[,TIME]", action='append', split=',',
help="Cycle to create a breakpoint")
+add_option("--remote-gdb-port", type='int', default=7000,
+ help="Remote gdb base port")
# Tracing options
set_group("Trace Options")
@@ -168,39 +116,61 @@ add_option("--trace-file", metavar="FILE", default="cout",
add_option("--trace-ignore", metavar="EXPR", action='append', split=':',
help="Ignore EXPR sim objects")
-options = attrdict()
-arguments = []
+# Help options
+set_group("Help Options")
+add_option("--list-sim-objects", action='store_true', default=False,
+ help="List all built-in SimObjects, their parameters and default values")
-def usage(exitcode=None):
- parser.print_help()
- if exitcode is not None:
- sys.exit(exitcode)
+def main():
+ import core
+ import debug
+ import defines
+ import event
+ import info
+ import stats
+ import trace
-def parse_args():
- _opts,args = parser.parse_args()
- opts = attrdict(_opts.__dict__)
+ def check_tracing():
+ if defines.TRACING_ON:
+ return
- # setting verbose and quiet at the same time doesn't make sense
- if opts.verbose > 0 and opts.quiet > 0:
- usage(2)
+ fatal("Tracing is not enabled. Compile with TRACING_ON")
- # store the verbosity in a single variable. 0 is default,
- # negative numbers represent quiet and positive values indicate verbose
- opts.verbose -= opts.quiet
+ # load the options.py config file to allow people to set their own
+ # default options
+ options_file = config.get('options.py')
+ if options_file:
+ scope = { 'options' : options }
+ execfile(options_file, scope)
- del opts.quiet
+ arguments = options.parse_args()
- options.update(opts)
- arguments.extend(args)
- return opts,args
+ if not os.path.isdir(options.outdir):
+ os.makedirs(options.outdir)
-def main():
- import defines
- import event
- import info
- import internal
+ # These filenames are used only if the redirect_std* options are set
+ stdout_file = os.path.join(options.outdir, options.stdout_file)
+ stderr_file = os.path.join(options.outdir, options.stderr_file)
- parse_args()
+ # Print redirection notices here before doing any redirection
+ if options.redirect_stdout and not options.redirect_stderr:
+ print "Redirecting stdout and stderr to", stdout_file
+ else:
+ if options.redirect_stdout:
+ print "Redirecting stdout to", stdout_file
+ if options.redirect_stderr:
+ print "Redirecting stderr to", stderr_file
+
+ # Now redirect stdout/stderr as desired
+ if options.redirect_stdout:
+ redir_fd = os.open(stdout_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
+ os.dup2(redir_fd, sys.stdout.fileno())
+ if not options.redirect_stderr:
+ os.dup2(redir_fd, sys.stderr.fileno())
+
+ if options.redirect_stderr:
+ redir_fd = os.open(stderr_file, os. O_WRONLY | os.O_CREAT | os.O_TRUNC)
+ os.dup2(redir_fd, sys.stderr.fileno())
done = False
@@ -208,14 +178,13 @@ def main():
done = True
print 'Build information:'
print
- print 'compiled %s' % internal.core.cvar.compileDate;
- print 'started %s' % datetime.datetime.now().ctime()
- print 'executing on %s' % socket.gethostname()
+ print 'compiled %s' % defines.compileDate;
+ print "revision %s" % defines.hgRev
print 'build options:'
- keys = defines.m5_build_env.keys()
+ keys = defines.buildEnv.keys()
keys.sort()
for key in keys:
- val = defines.m5_build_env[key]
+ val = defines.buildEnv[key]
print ' %s = %s' % (key, val)
print
@@ -247,27 +216,49 @@ def main():
if options.trace_help:
done = True
- print "Base Flags:"
- print_list(traceflags.baseFlags, indent=4)
- print
- print "Compound Flags:"
- for flag in traceflags.compoundFlags:
- if flag == 'All':
- continue
- print " %s:" % flag
- print_list(traceflags.compoundFlagMap[flag], indent=8)
+ check_tracing()
+ trace.help()
+
+ if options.list_sim_objects:
+ import SimObject
+ done = True
+ print "SimObjects:"
+ objects = SimObject.allClasses.keys()
+ objects.sort()
+ for name in objects:
+ obj = SimObject.allClasses[name]
+ print " %s" % obj
+ params = obj._params.keys()
+ params.sort()
+ for pname in params:
+ param = obj._params[pname]
+ default = getattr(param, 'default', '')
+ print " %s" % pname
+ if default:
+ print " default: %s" % default
+ print " desc: %s" % param.desc
+ print
print
if done:
sys.exit(0)
+ # setting verbose and quiet at the same time doesn't make sense
+ if options.verbose > 0 and options.quiet > 0:
+ options.usage(2)
+
+ verbose = options.verbose - options.quiet
if options.verbose >= 0:
print "M5 Simulator System"
print brief_copyright
print
- print "M5 compiled %s" % internal.core.cvar.compileDate;
- print "M5 started %s" % datetime.datetime.now().ctime()
+
+ print "M5 compiled %s" % defines.compileDate;
+ print "M5 revision %s" % defines.hgRev
+
+ print "M5 started %s" % datetime.datetime.now().strftime("%b %e %Y %X")
print "M5 executing on %s" % socket.gethostname()
+
print "command line:",
for argv in sys.argv:
print argv,
@@ -278,61 +269,67 @@ def main():
if arguments and not os.path.isfile(arguments[0]):
print "Script %s not found" % arguments[0]
- usage(2)
+ options.usage(2)
# tell C++ about output directory
- internal.core.setOutputDir(options.outdir)
+ core.setOutputDir(options.outdir)
# update the system path with elements from the -p option
sys.path[0:0] = options.path
- import objects
-
# set stats options
- internal.stats.initText(options.stats_file)
+ stats.initText(options.stats_file)
# set debugging options
+ debug.setRemoteGDBPort(options.remote_gdb_port)
for when in options.debug_break:
- internal.debug.schedBreakCycle(int(when))
-
- on_flags = []
- off_flags = []
- for flag in options.trace_flags:
- off = False
- if flag.startswith('-'):
- flag = flag[1:]
- off = True
- if flag not in traceflags.allFlags:
- print >>sys.stderr, "invalid trace flag '%s'" % flag
- sys.exit(1)
-
- if off:
- off_flags.append(flag)
- else:
- on_flags.append(flag)
-
- for flag in on_flags:
- internal.trace.set(flag)
-
- for flag in off_flags:
- internal.trace.clear(flag)
+ debug.schedBreakCycle(int(when))
+
+ if options.trace_flags:
+ check_tracing()
+
+ on_flags = []
+ off_flags = []
+ for flag in options.trace_flags:
+ off = False
+ if flag.startswith('-'):
+ flag = flag[1:]
+ off = True
+ if flag not in trace.flags.all and flag != "All":
+ print >>sys.stderr, "invalid trace flag '%s'" % flag
+ sys.exit(1)
+
+ if off:
+ off_flags.append(flag)
+ else:
+ on_flags.append(flag)
+
+ for flag in on_flags:
+ trace.set(flag)
+
+ for flag in off_flags:
+ trace.clear(flag)
if options.trace_start:
- def enable_trace():
- internal.trace.cvar.enabled = True
- event.create(enable_trace, int(options.trace_start))
+ check_tracing()
+ e = event.create(trace.enable, event.Event.Trace_Enable_Pri)
+ event.mainq.schedule(e, options.trace_start)
else:
- internal.trace.cvar.enabled = True
+ trace.enable()
- internal.trace.output(options.trace_file)
+ trace.output(options.trace_file)
for ignore in options.trace_ignore:
- internal.trace.ignore(ignore)
+ check_tracing()
+ trace.ignore(ignore)
sys.argv = arguments
sys.path = [ os.path.dirname(sys.argv[0]) ] + sys.path
- scope = { '__file__' : sys.argv[0],
+ filename = sys.argv[0]
+ filedata = file(filename, 'r').read()
+ filecode = compile(filedata, filename, 'exec')
+ scope = { '__file__' : filename,
'__name__' : '__m5_main__' }
# we want readline if we're doing anything interactive
@@ -342,11 +339,24 @@ def main():
# if pdb was requested, execfile the thing under pdb, otherwise,
# just do the execfile normally
if options.pdb:
- from pdb import Pdb
- debugger = Pdb()
- debugger.run('execfile("%s")' % sys.argv[0], scope)
+ import pdb
+ import traceback
+
+ pdb = pdb.Pdb()
+ try:
+ pdb.run(filecode, scope)
+ except SystemExit:
+ print "The program exited via sys.exit(). Exit status: ",
+ print sys.exc_info()[1]
+ except:
+ traceback.print_exc()
+ print "Uncaught exception. Entering post mortem debugging"
+ t = sys.exc_info()[2]
+ while t.tb_next is not None:
+ t = t.tb_next
+ pdb.interaction(t.tb_frame,t)
else:
- execfile(sys.argv[0], scope)
+ exec filecode in scope
# once the script is done
if options.interactive:
@@ -356,7 +366,14 @@ def main():
if __name__ == '__main__':
from pprint import pprint
- parse_args()
+ # load the options.py config file to allow people to set their own
+ # default options
+ options_file = config.get('options.py')
+ if options_file:
+ scope = { 'options' : options }
+ execfile(options_file, scope)
+
+ arguments = options.parse_args()
print 'opts:'
pprint(options, indent=4)
diff --git a/src/python/m5/options.py b/src/python/m5/options.py
new file mode 100644
index 000000000..1f534a314
--- /dev/null
+++ b/src/python/m5/options.py
@@ -0,0 +1,142 @@
+# 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.
+#
+# Authors: Nathan Binkert
+
+import optparse
+import sys
+
+from optparse import *
+
+class nodefault(object): pass
+
+class splitter(object):
+ def __init__(self, split):
+ self.split = split
+ def __call__(self, option, opt_str, value, parser):
+ values = value.split(self.split)
+ dest = getattr(parser.values, option.dest)
+ if dest is None:
+ setattr(parser.values, option.dest, values)
+ else:
+ dest.extend(values)
+
+class OptionParser(dict):
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('formatter', optparse.TitledHelpFormatter())
+ self._optparse = optparse.OptionParser(*args, **kwargs)
+ self._optparse.disable_interspersed_args()
+
+ self._allopts = {}
+
+ # current option group
+ self._group = self._optparse
+
+ def set_defaults(self, *args, **kwargs):
+ return self._optparse.set_defaults(*args, **kwargs)
+
+ def set_group(self, *args, **kwargs):
+ '''set the current option group'''
+ if not args and not kwargs:
+ self._group = self._optparse
+ else:
+ self._group = self._optparse.add_option_group(*args, **kwargs)
+
+ def add_option(self, *args, **kwargs):
+ '''add an option to the current option group, or global none set'''
+
+ # if action=split, but allows the option arguments
+ # themselves to be lists separated by the split variable'''
+
+ if kwargs.get('action', None) == 'append' and 'split' in kwargs:
+ split = kwargs.pop('split')
+ kwargs['default'] = []
+ kwargs['type'] = 'string'
+ kwargs['action'] = 'callback'
+ kwargs['callback'] = splitter(split)
+
+ option = self._group.add_option(*args, **kwargs)
+ dest = option.dest
+ if dest not in self._allopts:
+ self._allopts[dest] = option
+
+ return option
+
+ def bool_option(self, name, default, help):
+ '''add a boolean option called --name and --no-name.
+ Display help depending on which is the default'''
+
+ tname = '--%s' % name
+ fname = '--no-%s' % name
+ dest = name.replace('-', '_')
+ if default:
+ thelp = optparse.SUPPRESS_HELP
+ fhelp = help
+ else:
+ thelp = help
+ fhelp = optparse.SUPPRESS_HELP
+
+ topt = self.add_option(tname, action="store_true", default=default,
+ help=thelp)
+ fopt = self.add_option(fname, action="store_false", dest=dest,
+ help=fhelp)
+
+ return topt,fopt
+
+ def __getattr__(self, attr):
+ if attr.startswith('_'):
+ return super(OptionParser, self).__getattribute__(attr)
+
+ if attr in self:
+ return self[attr]
+
+ return super(OptionParser, self).__getattribute__(attr)
+
+ def __setattr__(self, attr, value):
+ if attr.startswith('_'):
+ super(OptionParser, self).__setattr__(attr, value)
+ elif attr in self._allopts:
+ defaults = { attr : value }
+ self.set_defaults(**defaults)
+ if attr in self:
+ self[attr] = value
+ else:
+ super(OptionParser, self).__setattr__(attr, value)
+
+ def parse_args(self):
+ opts,args = self._optparse.parse_args()
+
+ for key,val in opts.__dict__.iteritems():
+ if val is not None or key not in self:
+ self[key] = val
+
+ return args
+
+ def usage(self, exitcode=None):
+ self._optparse.print_help()
+ if exitcode is not None:
+ sys.exit(exitcode)
+
diff --git a/src/python/m5/params.py b/src/python/m5/params.py
index 241d4ceaf..18eeac0d1 100644
--- a/src/python/m5/params.py
+++ b/src/python/m5/params.py
@@ -166,6 +166,10 @@ class ParamDesc(object):
class VectorParamValue(list):
__metaclass__ = MetaParamValue
+ def __setattr__(self, attr, value):
+ raise AttributeError, \
+ "Not allowed to set %s on '%s'" % (attr, type(self).__name__)
+
def ini_str(self):
return ' '.join([v.ini_str() for v in self])
@@ -323,8 +327,8 @@ class CheckedIntType(MetaParamValue):
if not (hasattr(cls, 'min') and hasattr(cls, 'max')):
if not (hasattr(cls, 'size') and hasattr(cls, 'unsigned')):
panic("CheckedInt subclass %s must define either\n" \
- " 'min' and 'max' or 'size' and 'unsigned'\n" \
- % name);
+ " 'min' and 'max' or 'size' and 'unsigned'\n",
+ name);
if cls.unsigned:
cls.min = 0
cls.max = 2 ** cls.size - 1
@@ -379,6 +383,13 @@ class Percent(CheckedInt): cxx_type = 'int'; min = 0; max = 100
class Float(ParamValue, float):
cxx_type = 'double'
+ def __init__(self, value):
+ if isinstance(value, (int, long, float, NumericParamValue, Float)):
+ self.value = float(value)
+ else:
+ raise TypeError, "Can't convert object of type %s to Float" \
+ % type(value).__name__
+
def getValue(self):
return float(self.value)
@@ -406,7 +417,6 @@ class MemorySize32(CheckedInt):
class Addr(CheckedInt):
cxx_type = 'Addr'
- cxx_predecls = ['#include "arch/isa_traits.hh"']
size = 64
unsigned = True
def __init__(self, value):
@@ -886,7 +896,7 @@ class NetworkBandwidth(float,ParamValue):
class MemoryBandwidth(float,ParamValue):
cxx_type = 'float'
- def __new__(self, value):
+ def __new__(cls, value):
# we want the number of ticks per byte of data
val = convert.toMemoryBandwidth(value)
return super(cls, MemoryBandwidth).__new__(cls, val)
@@ -896,7 +906,9 @@ class MemoryBandwidth(float,ParamValue):
def getValue(self):
# convert to seconds per byte
- value = 1.0 / float(self)
+ value = float(self)
+ if value:
+ value = 1.0 / float(self)
# convert to ticks per byte
value = ticks.fromSeconds(value)
return float(value)
@@ -992,6 +1004,7 @@ class PortRef(object):
if self.peer and not proxy.isproxy(self.peer):
print "warning: overwriting port", self, \
"value", self.peer, "with", other
+ self.peer.peer = None
self.peer = other
if proxy.isproxy(other):
other.set_param_desc(PortParamDesc())
@@ -1034,6 +1047,8 @@ class PortRef(object):
if self.ccConnected: # already done this
return
peer = self.peer
+ if not self.peer: # nothing to connect to
+ return
connectPorts(self.simobj.getCCObject(), self.name, self.index,
peer.simobj.getCCObject(), peer.name, peer.index)
self.ccConnected = True
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
index 3d91da368..45992fe85 100644
--- a/src/python/m5/simulate.py
+++ b/src/python/m5/simulate.py
@@ -33,6 +33,8 @@ import sys
# import the SWIG-wrapped main C++ functions
import internal
+import core
+import stats
from main import options
import SimObject
import ticks
@@ -46,28 +48,29 @@ def instantiate(root):
root.unproxy_all()
- ini_file = file(os.path.join(options.outdir, 'config.ini'), 'w')
- root.print_ini(ini_file)
- ini_file.close() # close config.ini
+ if options.dump_config:
+ ini_file = file(os.path.join(options.outdir, options.dump_config), 'w')
+ root.print_ini(ini_file)
+ ini_file.close()
# Initialize the global statistics
- internal.stats.initSimStats()
+ stats.initSimStats()
# Create the C++ sim objects and connect ports
root.createCCObject()
root.connectPorts()
# Do a second pass to finish initializing the sim objects
- internal.core.initAll()
+ core.initAll()
# Do a third pass to initialize statistics
- internal.core.regAllStats()
+ core.regAllStats()
- # Check to make sure that the stats package is properly initialized
- internal.stats.check()
+ # We're done registering statistics. Enable the stats package now.
+ stats.enable()
# Reset to put the stats in a consistent state.
- internal.stats.reset()
+ stats.reset()
def doDot(root):
dot = pydot.Dot()
@@ -182,3 +185,5 @@ def switchCpus(cpuList):
for old_cpu, new_cpu in cpuList:
new_cpu.takeOverFrom(old_cpu)
+
+from internal.core import disableAllListeners
diff --git a/src/python/m5/stats.py b/src/python/m5/stats.py
index 041a3f58d..5bd9d5f6a 100644
--- a/src/python/m5/stats.py
+++ b/src/python/m5/stats.py
@@ -28,9 +28,6 @@
import internal
-from internal.stats import dump
-from internal.stats import initSimStats
-from internal.stats import reset
from internal.stats import StatEvent as event
def initText(filename, desc=True, compat=True):
@@ -44,3 +41,19 @@ def initMySQL(host, database, user='', passwd='', project='test', name='test',
internal.stats.initMySQL(host, database, user, passwd, project, name,
sample)
+
+def initSimStats():
+ internal.stats.initSimStats()
+
+def enable():
+ internal.stats.enable()
+
+def dump():
+ # Currently prepare happens in the dump, but we should maybe move
+ # that out.
+
+ #internal.stats.prepare()
+ internal.stats.dump()
+
+def reset():
+ internal.stats.reset()
diff --git a/src/python/m5/trace.py b/src/python/m5/trace.py
new file mode 100644
index 000000000..17aa6196c
--- /dev/null
+++ b/src/python/m5/trace.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+import internal
+import traceflags as flags
+import util
+
+from internal.trace import clear, output, set, ignore
+
+def disable():
+ internal.trace.cvar.enabled = False
+
+def enable():
+ internal.trace.cvar.enabled = True
+
+def help():
+ print "Base Flags:"
+ for flag in flags.basic:
+ print " %s: %s" % (flag, flags.descriptions[flag])
+ print
+ print "Compound Flags:"
+ for flag in flags.compound:
+ if flag == 'All':
+ continue
+ print " %s: %s" % (flag, flags.descriptions[flag])
+ util.print_list(flags.compoundMap[flag], indent=8)
+ print
diff --git a/src/python/m5/util/__init__.py b/src/python/m5/util/__init__.py
new file mode 100644
index 000000000..5c4a066c6
--- /dev/null
+++ b/src/python/m5/util/__init__.py
@@ -0,0 +1,45 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from attrdict import attrdict, optiondict
+from misc import *
+from multidict import multidict
+import jobfile
+
+def print_list(items, indent=4):
+ line = ' ' * indent
+ for i,item in enumerate(items):
+ if len(line) + len(item) > 76:
+ print line
+ line = ' ' * indent
+
+ if i < len(items) - 1:
+ line += '%s, ' % item
+ else:
+ line += item
+ print line
diff --git a/src/python/m5/attrdict.py b/src/python/m5/util/attrdict.py
index 4ee7f1b8c..56f67217b 100644
--- a/src/python/m5/attrdict.py
+++ b/src/python/m5/util/attrdict.py
@@ -26,16 +26,17 @@
#
# Authors: Nathan Binkert
-__all__ = [ 'attrdict' ]
+__all__ = [ 'attrdict', 'multiattrdict', 'optiondict' ]
class attrdict(dict):
+ """Wrap dict, so you can use attribute access to get/set elements"""
def __getattr__(self, attr):
if attr in self:
return self.__getitem__(attr)
return super(attrdict, self).__getattribute__(attr)
def __setattr__(self, attr, value):
- if attr in dir(self):
+ if attr in dir(self) or attr.startswith('_'):
return super(attrdict, self).__setattr__(attr, value)
return self.__setitem__(attr, value)
@@ -44,6 +45,25 @@ class attrdict(dict):
return self.__delitem__(attr)
return super(attrdict, self).__delattr__(attr, value)
+class multiattrdict(attrdict):
+ """Wrap attrdict so that nested attribute accesses automatically create
+ nested dictionaries."""
+ def __getattr__(self, attr):
+ try:
+ return super(multiattrdict, self).__getattr__(attr)
+ except AttributeError:
+ d = optiondict()
+ setattr(self, attr, d)
+ return d
+
+class optiondict(attrdict):
+ """Modify attrdict so that a missing attribute just returns None"""
+ def __getattr__(self, attr):
+ try:
+ return super(optiondict, self).__getattr__(attr)
+ except AttributeError:
+ return None
+
if __name__ == '__main__':
x = attrdict()
x.y = 1
@@ -59,3 +79,9 @@ if __name__ == '__main__':
del x.z
print dir(x)
print(x)
+
+ x = multiattrdict()
+ x.y.z = 9
+ print x
+ print x.y
+ print x.y.z
diff --git a/src/python/m5/util/jobfile.py b/src/python/m5/util/jobfile.py
new file mode 100644
index 000000000..c830895f6
--- /dev/null
+++ b/src/python/m5/util/jobfile.py
@@ -0,0 +1,472 @@
+# Copyright (c) 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: Nathan Binkert
+
+import sys
+
+from attrdict import optiondict
+from misc import crossproduct
+
+class Data(object):
+ def __init__(self, name, desc, **kwargs):
+ self.name = name
+ self.desc = desc
+ self.__dict__.update(kwargs)
+
+ def update(self, obj):
+ if not isinstance(obj, Data):
+ raise AttributeError, "can only update from Data object"
+
+ for key,val in obj.__dict__.iteritems():
+ if key.startswith('_') or key in ('name', 'desc'):
+ continue
+
+ if key not in self.__dict__:
+ self.__dict__[key] = val
+ continue
+
+ if not isinstance(val, dict):
+ if self.__dict__[key] == val:
+ continue
+
+ raise AttributeError, \
+ "%s specified more than once old: %s new: %s" % \
+ (key, self.__dict__[key], val)
+
+ d = self.__dict__[key]
+ for k,v in val.iteritems():
+ if k in d:
+ raise AttributeError, \
+ "%s specified more than once in %s" % (k, key)
+ d[k] = v
+
+ if hasattr(self, 'system') and hasattr(obj, 'system'):
+ if self.system != obj.system:
+ raise AttributeError, \
+ "conflicting values for system: '%s'/'%s'" % \
+ (self.system, obj.system)
+
+ def printinfo(self):
+ if self.name:
+ print 'name: %s' % self.name
+ if self.desc:
+ print 'desc: %s' % self.desc
+ try:
+ if self.system:
+ print 'system: %s' % self.system
+ except AttributeError:
+ pass
+
+ def printverbose(self):
+ for key in self:
+ val = self[key]
+ if isinstance(val, dict):
+ import pprint
+ val = pprint.pformat(val)
+ print '%-20s = %s' % (key, val)
+ print
+
+ def __contains__(self, attr):
+ if attr.startswith('_'):
+ return False
+ return attr in self.__dict__
+
+ def __getitem__(self, key):
+ if key.startswith('_'):
+ raise KeyError, "Key '%s' not found" % attr
+ return self.__dict__[key]
+
+ def __iter__(self):
+ keys = self.__dict__.keys()
+ keys.sort()
+ for key in keys:
+ if not key.startswith('_'):
+ yield key
+
+ def optiondict(self):
+ result = optiondict()
+ for key in self:
+ result[key] = self[key]
+ return result
+
+ def __repr__(self):
+ d = {}
+ for key,value in self.__dict__.iteritems():
+ if not key.startswith('_'):
+ d[key] = value
+
+ return "<%s: %s>" % (type(self).__name__, d)
+
+ def __str__(self):
+ return self.name
+
+class Job(Data):
+ def __init__(self, options):
+ super(Job, self).__init__('', '')
+
+ config = options[0]._config
+ for opt in options:
+ if opt._config != config:
+ raise AttributeError, \
+ "All options are not from the same Configuration"
+
+ self._config = config
+ self._groups = [ opt._group for opt in options ]
+ self._options = options
+
+ self.update(self._config)
+ for group in self._groups:
+ self.update(group)
+
+ self._is_checkpoint = True
+
+ for option in self._options:
+ self.update(option)
+ if not option._group._checkpoint:
+ self._is_checkpoint = False
+
+ if option._suboption:
+ self.update(option._suboption)
+ self._is_checkpoint = False
+
+ names = [ ]
+ for opt in self._options:
+ if opt.name:
+ names.append(opt.name)
+ self.name = ':'.join(names)
+
+ descs = [ ]
+ for opt in self._options:
+ if opt.desc:
+ descs.append(opt.desc)
+ self.desc = ', '.join(descs)
+
+ self._checkpoint = None
+ if not self._is_checkpoint:
+ opts = []
+ for opt in options:
+ cpt = opt._group._checkpoint
+ if not cpt:
+ continue
+ if isinstance(cpt, Option):
+ opt = cpt.clone(suboptions=False)
+ else:
+ opt = opt.clone(suboptions=False)
+
+ opts.append(opt)
+
+ if opts:
+ self._checkpoint = Job(opts)
+
+ def clone(self):
+ return Job(self._options)
+
+ def printinfo(self):
+ super(Job, self).printinfo()
+ if self._checkpoint:
+ print 'checkpoint: %s' % self._checkpoint.name
+ print 'config: %s' % self._config.name
+ print 'groups: %s' % [ g.name for g in self._groups ]
+ print 'options: %s' % [ o.name for o in self._options ]
+ super(Job, self).printverbose()
+
+class SubOption(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(SubOption, self).__init__(name, desc, **kwargs)
+ self._number = None
+
+class Option(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Option, self).__init__(name, desc, **kwargs)
+ self._suboptions = []
+ self._suboption = None
+ self._number = None
+
+ def __getattribute__(self, attr):
+ if attr == 'name':
+ name = self.__dict__[attr]
+ if self._suboption is not None:
+ name = '%s:%s' % (name, self._suboption.name)
+ return name
+
+ if attr == 'desc':
+ desc = [ self.__dict__[attr] ]
+ if self._suboption is not None and self._suboption.desc:
+ desc.append(self._suboption.desc)
+ return ', '.join(desc)
+
+ return super(Option, self).__getattribute__(attr)
+
+ def suboption(self, name, desc, **kwargs):
+ subo = SubOption(name, desc, **kwargs)
+ subo._config = self._config
+ subo._group = self._group
+ subo._option = self
+ subo._number = len(self._suboptions)
+ self._suboptions.append(subo)
+ return subo
+
+ def clone(self, suboptions=True):
+ option = Option(self.__dict__['name'], self.__dict__['desc'])
+ option.update(self)
+ option._group = self._group
+ option._config = self._config
+ option._number = self._number
+ if suboptions:
+ option._suboptions.extend(self._suboptions)
+ option._suboption = self._suboption
+ return option
+
+ def subopts(self):
+ if not self._suboptions:
+ return [ self ]
+
+ subopts = []
+ for subo in self._suboptions:
+ option = self.clone()
+ option._suboption = subo
+ subopts.append(option)
+
+ return subopts
+
+ def printinfo(self):
+ super(Option, self).printinfo()
+ print 'config: %s' % self._config.name
+ super(Option, self).printverbose()
+
+class Group(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Group, self).__init__(name, desc, **kwargs)
+ self._options = []
+ self._number = None
+ self._checkpoint = False
+
+ def option(self, name, desc, **kwargs):
+ opt = Option(name, desc, **kwargs)
+ opt._config = self._config
+ opt._group = self
+ opt._number = len(self._options)
+ self._options.append(opt)
+ return opt
+
+ def options(self):
+ return self._options
+
+ def subopts(self):
+ subopts = []
+ for opt in self._options:
+ for subo in opt.subopts():
+ subopts.append(subo)
+ return subopts
+
+ def printinfo(self):
+ super(Group, self).printinfo()
+ print 'config: %s' % self._config.name
+ print 'options: %s' % [ o.name for o in self._options ]
+ super(Group, self).printverbose()
+
+class Configuration(Data):
+ def __init__(self, name, desc, **kwargs):
+ super(Configuration, self).__init__(name, desc, **kwargs)
+ self._groups = []
+ self._posfilters = []
+ self._negfilters = []
+
+ def group(self, name, desc, **kwargs):
+ grp = Group(name, desc, **kwargs)
+ grp._config = self
+ grp._number = len(self._groups)
+ self._groups.append(grp)
+ return grp
+
+ def groups(self):
+ return self._groups
+
+ def checkchildren(self, kids):
+ for kid in kids:
+ if kid._config != self:
+ raise AttributeError, "child from the wrong configuration"
+
+ def sortgroups(self, groups):
+ groups = [ (grp._number, grp) for grp in groups ]
+ groups.sort()
+ return [ grp[1] for grp in groups ]
+
+ def options(self, groups=None, checkpoint=False):
+ if groups is None:
+ groups = self._groups
+ self.checkchildren(groups)
+ groups = self.sortgroups(groups)
+ if checkpoint:
+ groups = [ grp for grp in groups if grp._checkpoint ]
+ optgroups = [ g.options() for g in groups ]
+ else:
+ optgroups = [ g.subopts() for g in groups ]
+ if not optgroups:
+ return
+ for options in crossproduct(optgroups):
+ for opt in options:
+ cpt = opt._group._checkpoint
+ if not isinstance(cpt, bool) and cpt != opt:
+ if checkpoint:
+ break
+ else:
+ yield options
+ else:
+ if checkpoint:
+ yield options
+
+ def addfilter(self, filt, pos=True):
+ import re
+ filt = re.compile(filt)
+ if pos:
+ self._posfilters.append(filt)
+ else:
+ self._negfilters.append(filt)
+
+ def jobfilter(self, job):
+ for filt in self._negfilters:
+ if filt.match(job.name):
+ return False
+
+ if not self._posfilters:
+ return True
+
+ for filt in self._posfilters:
+ if filt.match(job.name):
+ return True
+
+ return False
+
+ def checkpoints(self, groups=None):
+ for options in self.options(groups, True):
+ job = Job(options)
+ if self.jobfilter(job):
+ yield job
+
+ def jobs(self, groups=None):
+ for options in self.options(groups, False):
+ job = Job(options)
+ if self.jobfilter(job):
+ yield job
+
+ def alljobs(self, groups=None):
+ for options in self.options(groups, True):
+ yield Job(options)
+ for options in self.options(groups, False):
+ yield Job(options)
+
+ def find(self, jobname):
+ for job in self.alljobs():
+ if job.name == jobname:
+ return job
+ else:
+ raise AttributeError, "job '%s' not found" % jobname
+
+ def job(self, options):
+ self.checkchildren(options)
+ options = [ (opt._group._number, opt) for opt in options ]
+ options.sort()
+ options = [ opt[1] for opt in options ]
+ job = Job(options)
+ return job
+
+ def printinfo(self):
+ super(Configuration, self).printinfo()
+ print 'groups: %s' % [ g.name for g in self._groups ]
+ super(Configuration, self).printverbose()
+
+def JobFile(jobfile):
+ from os.path import expanduser, isfile, join as joinpath
+ filename = expanduser(jobfile)
+
+ # Can't find filename in the current path, search sys.path
+ if not isfile(filename):
+ for path in sys.path:
+ testname = joinpath(path, filename)
+ if isfile(testname):
+ filename = testname
+ break
+ else:
+ raise AttributeError, \
+ "Could not find file '%s'" % jobfile
+
+ data = {}
+ execfile(filename, data)
+ if 'conf' not in data:
+ raise ImportError, 'cannot import name conf from %s' % jobfile
+ return data['conf']
+
+def main(conf=None):
+ usage = 'Usage: %s [-b] [-c] [-v]' % sys.argv[0]
+ if conf is None:
+ usage += ' <jobfile>'
+
+ try:
+ import getopt
+ opts, args = getopt.getopt(sys.argv[1:], '-bcv')
+ except getopt.GetoptError:
+ sys.exit(usage)
+
+ both = False
+ checkpoint = False
+ verbose = False
+ for opt,arg in opts:
+ if opt == '-b':
+ both = True
+ checkpoint = True
+ if opt == '-c':
+ checkpoint = True
+ if opt == '-v':
+ verbose = True
+
+ if conf is None:
+ if len(args) != 1:
+ raise AttributeError, usage
+ conf = JobFile(args[0])
+ else:
+ if len(args) != 0:
+ raise AttributeError, usage
+
+ if both:
+ jobs = conf.alljobs()
+ elif checkpoint:
+ jobs = conf.checkpoints()
+ else:
+ jobs = conf.jobs()
+
+ for job in jobs:
+ if verbose:
+ job.printinfo()
+ else:
+ cpt = ''
+ if job._checkpoint:
+ cpt = job._checkpoint.name
+ print job.name, cpt
+
+if __name__ == '__main__':
+ main()
diff --git a/src/python/m5/util.py b/src/python/m5/util/misc.py
index 28b8b1b94..094e3ed9a 100644
--- a/src/python/m5/util.py
+++ b/src/python/m5/util/misc.py
@@ -56,4 +56,32 @@ def applyOrMap(objOrSeq, meth, *args, **kwargs):
else:
return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq]
+def crossproduct(items):
+ if not isinstance(items, (list, tuple)):
+ raise AttributeError, 'crossproduct works only on sequences'
+ if not items:
+ yield None
+ return
+
+ current = items[0]
+ remainder = items[1:]
+
+ if not hasattr(current, '__iter__'):
+ current = [ current ]
+
+ for item in current:
+ for rem in crossproduct(remainder):
+ data = [ item ]
+ if rem:
+ data += rem
+ yield data
+
+def flatten(items):
+ if not isinstance(items, (list, tuple)):
+ yield items
+ return
+
+ for item in items:
+ for flat in flatten(item):
+ yield flat
diff --git a/src/python/m5/multidict.py b/src/python/m5/util/multidict.py
index b5cd700ef..b5cd700ef 100644
--- a/src/python/m5/multidict.py
+++ b/src/python/m5/util/multidict.py
diff --git a/src/python/m5/util/orderdict.py b/src/python/m5/util/orderdict.py
new file mode 100644
index 000000000..3f755d299
--- /dev/null
+++ b/src/python/m5/util/orderdict.py
@@ -0,0 +1,80 @@
+# 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.
+#
+# Authors: Nathan Binkert
+
+__all__ = [ 'orderdict' ]
+
+class orderdict(dict):
+ def __init__(self, d = {}):
+ self._keys = d.keys()
+ super(orderdict, self).__init__(d)
+
+ def __setitem__(self, key, item):
+ super(orderdict, self).__setitem__(key, item)
+ if not hasattr(self, '_keys'):
+ self._keys = [key,]
+ if key not in self._keys:
+ self._keys.append(key)
+
+ def __delitem__(self, key):
+ super(orderdict, self).__delitem__(key)
+ self._keys.remove(key)
+
+ def clear(self):
+ super(orderdict, self).clear()
+ self._keys = []
+
+ def items(self):
+ for i in self._keys:
+ yield i, self[i]
+
+ def keys(self):
+ return self._keys
+
+ def popitem(self):
+ if len(self._keys) == 0:
+ raise KeyError('dictionary is empty')
+ else:
+ key = self._keys[-1]
+ val = self[key]
+ del self[key]
+ return key, val
+
+ def setdefault(self, key, failobj = None):
+ super(orderdict, self).setdefault(key, failobj)
+ if key not in self._keys:
+ self._keys.append(key)
+
+ def update(self, d):
+ for key in d.keys():
+ if not self.has_key(key):
+ self._keys.append(key)
+ super(orderdict, self).update(d)
+
+ def values(self):
+ for i in self._keys:
+ yield self[i]
diff --git a/src/python/swig/core.i b/src/python/swig/core.i
index 770765ca4..c567bea4d 100644
--- a/src/python/swig/core.i
+++ b/src/python/swig/core.i
@@ -34,11 +34,27 @@
%{
#include "python/swig/pyobject.hh"
+#include "base/misc.hh"
+#include "base/socket.hh"
#include "sim/core.hh"
#include "sim/host.hh"
#include "sim/startup.hh"
extern const char *compileDate;
+
+#ifdef DEBUG
+const bool flag_DEBUG = true;
+#else
+const bool flag_DEBUG = false;
+#endif
+#ifdef NDEBUG
+const bool flag_NDEBUG = true;
+#else
+const bool flag_NDEBUG = false;
+#endif
+const bool flag_TRACING_ON = TRACING_ON;
+
+inline void disableAllListeners() { ListenSocket::disableAll(); }
%}
%include "stdint.i"
@@ -46,11 +62,15 @@ extern const char *compileDate;
%include "sim/host.hh"
void setOutputDir(const std::string &dir);
-void setOutputFile(const std::string &file);
void SimStartup();
void doExitCleanup();
+void disableAllListeners();
+%immutable compileDate;
char *compileDate;
+const bool flag_DEBUG;
+const bool flag_NDEBUG;
+const bool flag_TRACING_ON;
void setClockFrequency(Tick ticksPerSecond);
@@ -63,6 +83,10 @@ void unserializeAll(const std::string &cpt_dir);
void initAll();
void regAllStats();
+bool want_warn, warn_verbose;
+bool want_info, info_verbose;
+bool want_hack, hack_verbose;
+
%wrapper %{
// fix up module name to reflect the fact that it's inside the m5 package
#undef SWIG_name
diff --git a/src/python/swig/debug.i b/src/python/swig/debug.i
index b542e9f82..1084d6936 100644
--- a/src/python/swig/debug.i
+++ b/src/python/swig/debug.i
@@ -31,16 +31,13 @@
%module debug
%{
-// include these files when compiling debug_wrap.cc
#include "sim/host.hh"
+#include "sim/debug.hh"
%}
%include "stdint.i"
%include "sim/host.hh"
-
-%inline %{
-extern void schedBreakCycle(Tick when);
-%}
+%include "sim/debug.hh"
%wrapper %{
// fix up module name to reflect the fact that it's inside the m5 package
diff --git a/src/python/swig/event.i b/src/python/swig/event.i
index 9a2093c99..b40e59a4b 100644
--- a/src/python/swig/event.i
+++ b/src/python/swig/event.i
@@ -32,34 +32,65 @@
%{
#include "python/swig/pyevent.hh"
-
+#include "sim/host.hh"
+#include "sim/eventq.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/simulate.hh"
%}
+#pragma SWIG nowarn=350,351
+
+%extend EventQueue {
+ void
+ schedule(Event *event, Tick when)
+ {
+ // Any python event that are scheduled must have their
+ // internal object's refcount incremented so that the object
+ // sticks around while it is in the event queue.
+ PythonEvent *pyevent = dynamic_cast<PythonEvent *>(event);
+ if (pyevent)
+ pyevent->incref();
+ $self->schedule(event, when);
+ }
+
+ void
+ deschedule(Event *event)
+ {
+ $self->deschedule(event);
+
+ // Now that we're removing the python object from the event
+ // queue, we need to decrement its reference count.
+ PythonEvent *pyevent = dynamic_cast<PythonEvent *>(event);
+ if (pyevent)
+ pyevent->decref();
+ }
+}
+
+%ignore EventQueue::schedule;
+%ignore EventQueue::deschedule;
+
+%import "base/fast_alloc.hh"
+%import "sim/serialize.hh"
+
%include "stdint.i"
%include "std_string.i"
%include "sim/host.hh"
+%include "sim/eventq.hh"
+%include "python/swig/pyevent.hh"
-void create(PyObject *object, Tick when);
-
-class Event;
-class CountedDrainEvent : public Event {
- public:
+struct CountedDrainEvent : public Event
+{
void setCount(int _count);
};
-CountedDrainEvent *createCountedDrain();
-void cleanupCountedDrain(Event *drain_event);
-
// minimal definition of SimExitEvent interface to wrap
-class SimLoopExitEvent {
+class SimLoopExitEvent : public Event
+{
public:
std::string getCause();
int getCode();
- SimLoopExitEvent(EventQueue *q, Tick _when, Tick _repeat,
- const std::string &_cause, int c = 0);
+ SimLoopExitEvent(const std::string &_cause, int c, Tick _repeat = 0);
};
%exception simulate {
diff --git a/src/python/swig/pyevent.cc b/src/python/swig/pyevent.cc
index 7f23b8874..0695ed2d3 100644
--- a/src/python/swig/pyevent.cc
+++ b/src/python/swig/pyevent.cc
@@ -33,21 +33,15 @@
#include "python/swig/pyevent.hh"
#include "sim/async.hh"
-PythonEvent::PythonEvent(PyObject *obj, Tick when, Priority priority)
- : Event(&mainEventQueue, priority), object(obj)
+PythonEvent::PythonEvent(PyObject *obj, Priority priority)
+ : Event(priority), object(obj)
{
if (object == NULL)
panic("Passed in invalid object");
-
- Py_INCREF(object);
-
- setFlags(AutoDelete);
- schedule(when);
}
PythonEvent::~PythonEvent()
{
- Py_DECREF(object);
}
void
@@ -66,4 +60,27 @@ PythonEvent::process()
async_event = true;
async_exception = true;
}
+
+ // Since the object has been removed from the event queue, its
+ // reference count must be decremented.
+ Py_DECREF(object);
+}
+
+CountedDrainEvent *
+createCountedDrain()
+{
+ return new CountedDrainEvent();
+}
+
+void
+cleanupCountedDrain(Event *counted_drain)
+{
+ CountedDrainEvent *event =
+ dynamic_cast<CountedDrainEvent *>(counted_drain);
+ if (event == NULL) {
+ fatal("Called cleanupCountedDrain() on an event that was not "
+ "a CountedDrainEvent.");
+ }
+ assert(event->getCount() == 0);
+ delete event;
}
diff --git a/src/python/swig/pyevent.hh b/src/python/swig/pyevent.hh
index 65e80e9e4..9006a0404 100644
--- a/src/python/swig/pyevent.hh
+++ b/src/python/swig/pyevent.hh
@@ -40,35 +40,16 @@ class PythonEvent : public Event
PyObject *object;
public:
- PythonEvent(PyObject *obj, Tick when, Priority priority = Default_Pri);
+ PythonEvent(PyObject *obj, Event::Priority priority);
~PythonEvent();
+ void incref() { Py_INCREF(object); }
+ void decref() { Py_DECREF(object); }
+
virtual void process();
};
-inline void
-create(PyObject *object, Tick when)
-{
- new PythonEvent(object, when);
-}
-
-inline Event *
-createCountedDrain()
-{
- return new CountedDrainEvent();
-}
-
-inline void
-cleanupCountedDrain(Event *counted_drain)
-{
- CountedDrainEvent *event =
- dynamic_cast<CountedDrainEvent *>(counted_drain);
- if (event == NULL) {
- fatal("Called cleanupCountedDrain() on an event that was not "
- "a CountedDrainEvent.");
- }
- assert(event->getCount() == 0);
- delete event;
-}
+CountedDrainEvent *createCountedDrain();
+void cleanupCountedDrain(Event *counted_drain);
#endif // __PYTHON_SWIG_PYEVENT_HH__
diff --git a/src/python/swig/range.i b/src/python/swig/range.i
index 40809dae4..309e6a8ba 100644
--- a/src/python/swig/range.i
+++ b/src/python/swig/range.i
@@ -28,6 +28,8 @@
* Authors: Nathan Binkert
*/
+%rename(assign) *::operator=;
+
%include "base/range.hh"
%include "sim/host.hh"
diff --git a/src/python/swig/stats.i b/src/python/swig/stats.i
index d36f82dbc..284df8ff8 100644
--- a/src/python/swig/stats.i
+++ b/src/python/swig/stats.i
@@ -48,7 +48,8 @@ void initMySQL(std::string host, std::string database, std::string user,
void StatEvent(bool dump, bool reset, Tick when = curTick, Tick repeat = 0);
-void check();
+void enable();
+void prepare();
void dump();
void reset();
diff --git a/src/sim/BaseTLB.py b/src/sim/BaseTLB.py
new file mode 100644
index 000000000..9aca4a97c
--- /dev/null
+++ b/src/sim/BaseTLB.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2008 The Hewlett-Packard Development Company
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (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
+
+from m5.SimObject import SimObject
+
+class BaseTLB(SimObject):
+ type = 'BaseTLB'
+ abstract = True
diff --git a/src/sim/InstTracer.py b/src/sim/InstTracer.py
index f7500f1e8..9ba91a019 100644
--- a/src/sim/InstTracer.py
+++ b/src/sim/InstTracer.py
@@ -31,5 +31,5 @@ from m5.params import *
class InstTracer(SimObject):
type = 'InstTracer'
- cxx_namespace = 'Trace'
+ cxx_class = 'Trace::InstTracer'
abstract = True
diff --git a/src/sim/Process.py b/src/sim/Process.py
index 37a27bf3b..81108dd70 100644
--- a/src/sim/Process.py
+++ b/src/sim/Process.py
@@ -34,7 +34,8 @@ class Process(SimObject):
type = 'Process'
abstract = True
input = Param.String('cin', "filename for stdin")
- output = Param.String('cout', 'filename for stdout/stderr')
+ output = Param.String('cout', 'filename for stdout')
+ errout = Param.String('cerr', 'filename for stderr')
system = Param.System(Parent.any, "system process will run on")
max_stack_size = Param.MemorySize('64MB', 'maximum size of the stack')
diff --git a/src/sim/SConscript b/src/sim/SConscript
index 0b39ab8e8..750007947 100644
--- a/src/sim/SConscript
+++ b/src/sim/SConscript
@@ -30,6 +30,7 @@
Import('*')
+SimObject('BaseTLB.py')
SimObject('Root.py')
SimObject('System.py')
SimObject('InstTracer.py')
@@ -39,7 +40,9 @@ Source('core.cc')
Source('debug.cc')
Source('eventq.cc')
Source('faults.cc')
-Source('main.cc')
+Source('init.cc')
+BinSource('main.cc')
+Source('pseudo_inst.cc')
Source('root.cc')
Source('serialize.cc')
Source('sim_events.cc')
@@ -51,7 +54,6 @@ Source('system.cc')
if env['FULL_SYSTEM']:
Source('arguments.cc')
- Source('pseudo_inst.cc')
else:
Source('tlb.cc')
SimObject('Process.py')
diff --git a/src/sim/System.py b/src/sim/System.py
index 5712a5c03..3b0bc1e46 100644
--- a/src/sim/System.py
+++ b/src/sim/System.py
@@ -38,7 +38,7 @@ class System(SimObject):
type = 'System'
swig_objdecls = [ '%include "python/swig/system.i"' ]
- physmem = Param.PhysicalMemory(Parent.any, "phsyical memory")
+ physmem = Param.PhysicalMemory(Parent.any, "physical memory")
mem_mode = Param.MemoryMode('atomic', "The mode the memory system is in")
if build_env['FULL_SYSTEM']:
abstract = True
diff --git a/src/sim/async.hh b/src/sim/async.hh
index 932f975d2..6dd5b8a0d 100644
--- a/src/sim/async.hh
+++ b/src/sim/async.hh
@@ -42,12 +42,12 @@
/// then checked in the main event loop. Defined in main.cc.
/// @note See the PollQueue object (in pollevent.hh) for the use of async_io and async_alarm.
//@{
-extern volatile bool async_event; ///< Some asynchronous event has happened.
-extern volatile bool async_statdump; ///< Async request to dump stats.
-extern volatile bool async_statreset; ///< Async request to reset stats.
-extern volatile bool async_exit; ///< Async request to exit simulator.
-extern volatile bool async_io; ///< Async I/O request (SIGIO).
-extern volatile bool async_alarm; ///< Async alarm event (SIGALRM).
+extern volatile bool async_event; ///< Some asynchronous event has happened.
+extern volatile bool async_statdump; ///< Async request to dump stats.
+extern volatile bool async_statreset; ///< Async request to reset stats.
+extern volatile bool async_exit; ///< Async request to exit simulator.
+extern volatile bool async_io; ///< Async I/O request (SIGIO).
+extern volatile bool async_alarm; ///< Async alarm event (SIGALRM).
extern volatile bool async_exception; ///< Python exception.
//@}
diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh
index 062fc4513..2519e552b 100644
--- a/src/sim/byteswap.hh
+++ b/src/sim/byteswap.hh
@@ -62,7 +62,7 @@ enum ByteOrder {BigEndianByteOrder, LittleEndianByteOrder};
//These functions actually perform the swapping for parameters
//of various bit lengths
-static inline uint64_t
+inline uint64_t
swap_byte64(uint64_t x)
{
#if defined(linux)
@@ -81,7 +81,7 @@ swap_byte64(uint64_t x)
#endif
}
-static inline uint32_t
+inline uint32_t
swap_byte32(uint32_t x)
{
#if defined(linux)
@@ -95,7 +95,7 @@ swap_byte32(uint32_t x)
#endif
}
-static inline uint16_t
+inline uint16_t
swap_byte16(uint16_t x)
{
#if defined(linux)
@@ -113,7 +113,7 @@ swap_byte16(uint16_t x)
// sizeof() values are known at compile time, it should inline to a
// direct call to the right swap_byteNN() function.
template <typename T>
-static inline T swap_byte(T x) {
+inline T swap_byte(T x) {
if (sizeof(T) == 8)
return swap_byte64((uint64_t)x);
else if (sizeof(T) == 4)
@@ -127,7 +127,7 @@ static inline T swap_byte(T x) {
}
template<>
-static inline Twin64_t swap_byte<Twin64_t>(Twin64_t x)
+inline Twin64_t swap_byte<Twin64_t>(Twin64_t x)
{
x.a = swap_byte(x.a);
x.b = swap_byte(x.b);
@@ -135,7 +135,7 @@ static inline Twin64_t swap_byte<Twin64_t>(Twin64_t x)
}
template<>
-static inline Twin32_t swap_byte<Twin32_t>(Twin32_t x)
+inline Twin32_t swap_byte<Twin32_t>(Twin32_t x)
{
x.a = swap_byte(x.a);
x.b = swap_byte(x.b);
@@ -144,23 +144,23 @@ static inline Twin32_t swap_byte<Twin32_t>(Twin32_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);}
+template <typename T> inline T betole(T value) {return swap_byte(value);}
+template <typename T> 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 defined(_BIG_ENDIAN) || !defined(_LITTLE_ENDIAN) && BYTE_ORDER == BIG_ENDIAN
const ByteOrder HostByteOrder = BigEndianByteOrder;
-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;}
+template <typename T> inline T htole(T value) {return swap_byte(value);}
+template <typename T> inline T letoh(T value) {return swap_byte(value);}
+template <typename T> inline T htobe(T value) {return value;}
+template <typename T> inline T betoh(T value) {return value;}
#elif defined(_LITTLE_ENDIAN) || BYTE_ORDER == LITTLE_ENDIAN
const ByteOrder HostByteOrder = LittleEndianByteOrder;
-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);}
+template <typename T> inline T htole(T value) {return value;}
+template <typename T> inline T letoh(T value) {return value;}
+template <typename T> inline T htobe(T value) {return swap_byte(value);}
+template <typename T> inline T betoh(T value) {return swap_byte(value);}
#else
#error Invalid Endianess
#endif
@@ -169,33 +169,33 @@ namespace BigEndianGuest
{
const bool ByteOrderDiffers = (HostByteOrder != BigEndianByteOrder);
template <typename T>
- static inline T gtole(T value) {return betole(value);}
+ inline T gtole(T value) {return betole(value);}
template <typename T>
- static inline T letog(T value) {return letobe(value);}
+ inline T letog(T value) {return letobe(value);}
template <typename T>
- static inline T gtobe(T value) {return value;}
+ inline T gtobe(T value) {return value;}
template <typename T>
- static inline T betog(T value) {return value;}
+ inline T betog(T value) {return value;}
template <typename T>
- static inline T htog(T value) {return htobe(value);}
+ inline T htog(T value) {return htobe(value);}
template <typename T>
- static inline T gtoh(T value) {return betoh(value);}
+ inline T gtoh(T value) {return betoh(value);}
}
namespace LittleEndianGuest
{
const bool ByteOrderDiffers = (HostByteOrder != LittleEndianByteOrder);
template <typename T>
- static inline T gtole(T value) {return value;}
+ inline T gtole(T value) {return value;}
template <typename T>
- static inline T letog(T value) {return value;}
+ inline T letog(T value) {return value;}
template <typename T>
- static inline T gtobe(T value) {return letobe(value);}
+ inline T gtobe(T value) {return letobe(value);}
template <typename T>
- static inline T betog(T value) {return betole(value);}
+ inline T betog(T value) {return betole(value);}
template <typename T>
- static inline T htog(T value) {return htole(value);}
+ inline T htog(T value) {return htole(value);}
template <typename T>
- static inline T gtoh(T value) {return letoh(value);}
+ inline T gtoh(T value) {return letoh(value);}
}
#endif // __SIM_BYTE_SWAP_HH__
diff --git a/src/sim/core.cc b/src/sim/core.cc
index 75f1f384c..8342b6740 100644
--- a/src/sim/core.cc
+++ b/src/sim/core.cc
@@ -97,14 +97,6 @@ setOutputDir(const string &dir)
simout.setDirectory(dir);
}
-ostream *outputStream;
-
-void
-setOutputFile(const string &file)
-{
- outputStream = simout.find(file);
-}
-
/**
* Queue of C++ callbacks to invoke on simulator exit.
*/
diff --git a/src/sim/core.hh b/src/sim/core.hh
index fb7f921f4..50cb2ef59 100644
--- a/src/sim/core.hh
+++ b/src/sim/core.hh
@@ -68,11 +68,6 @@ extern Tick ps;
void setClockFrequency(Tick ticksPerSecond);
-/// Output stream for simulator messages (e.g., cprintf()). Also used
-/// as default stream for tracing and DPRINTF() messages (unless
-/// overridden with trace:file option).
-extern std::ostream *outputStream;
-void setOutputFile(const std::string &file);
void setOutputDir(const std::string &dir);
struct Callback;
diff --git a/src/sim/debug.cc b/src/sim/debug.cc
index b4f4cd9dc..f8a3215d0 100644
--- a/src/sim/debug.cc
+++ b/src/sim/debug.cc
@@ -29,51 +29,36 @@
* Steve Reinhardt
*/
-#include <sys/types.h>
-#include <signal.h>
-#include <unistd.h>
+#include <Python.h>
#include <string>
#include <vector>
+#include "base/debug.hh"
#include "sim/debug.hh"
#include "sim/eventq.hh"
#include "sim/sim_events.hh"
using namespace std;
-void
-debug_break()
-{
-#ifndef NDEBUG
- kill(getpid(), SIGTRAP);
-#else
- cprintf("debug_break suppressed, compiled with NDEBUG\n");
-#endif
-}
-
//
// Debug event: place a breakpoint on the process function and
// schedule the event to break at a particular cycle
//
-class DebugBreakEvent : public Event
+struct DebugBreakEvent : public Event
{
- public:
-
- DebugBreakEvent(EventQueue *q, Tick _when);
-
- void process(); // process event
+ DebugBreakEvent();
+ void process(); // process event
virtual const char *description() const;
};
//
// constructor: schedule at specified time
//
-DebugBreakEvent::DebugBreakEvent(EventQueue *q, Tick _when)
- : Event(q, Debug_Break_Pri)
+DebugBreakEvent::DebugBreakEvent()
+ : Event(Debug_Break_Pri)
{
setFlags(AutoDelete);
- schedule(_when);
}
//
@@ -99,12 +84,46 @@ DebugBreakEvent::description() const
void
schedBreakCycle(Tick when)
{
- new DebugBreakEvent(&mainEventQueue, when);
+ mainEventQueue.schedule(new DebugBreakEvent, when);
+ warn("need to stop all queues");
}
void
eventqDump()
{
mainEventQueue.dump();
+ warn("need to dump all queues");
+}
+
+void
+py_interact()
+{
+ PyObject *globals;
+ PyObject *locals;
+
+ globals = PyEval_GetGlobals();
+ Py_INCREF(globals);
+ locals = PyDict_New();
+ PyRun_String("import code", Py_file_input, globals, locals);
+ PyRun_String("code.interact(local=globals())", Py_file_input,
+ globals, locals);
+ Py_DECREF(globals);
+ Py_DECREF(locals);
+}
+
+int remote_gdb_base_port = 7000;
+
+int
+getRemoteGDBPort()
+{
+ return remote_gdb_base_port;
+}
+
+// Set remote GDB base port. 0 means disable remote GDB.
+// Callable from python.
+void
+setRemoteGDBPort(int port)
+{
+ remote_gdb_base_port = port;
}
diff --git a/src/sim/debug.hh b/src/sim/debug.hh
index 79792234b..7dafb8394 100644
--- a/src/sim/debug.hh
+++ b/src/sim/debug.hh
@@ -28,9 +28,15 @@
* Authors: Nathan Binkert
*/
-#ifndef __DEBUG_HH__
-#define __DEBUG_HH__
+#ifndef __SIM_DEBUG_HH__
+#define __SIM_DEBUG_HH__
-void debug_break();
+#include "sim/host.hh"
-#endif // __DEBUG_HH__
+void schedBreakCycle(Tick when);
+
+int getRemoteGDBPort();
+// Remote gdb base port. 0 disables remote gdb.
+void setRemoteGDBPort(int port);
+
+#endif // __SIM_DEBUG_HH__
diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc
index 2c679be1e..d1f84fcb2 100644
--- a/src/sim/eventq.cc
+++ b/src/sim/eventq.cc
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,18 +31,17 @@
* Steve Raasch
*/
-#include <assert.h>
-
+#include <cassert>
#include <iostream>
#include <string>
#include <vector>
-#include "cpu/smt.hh"
+#include "base/hashmap.hh"
#include "base/misc.hh"
-
-#include "sim/eventq.hh"
#include "base/trace.hh"
+#include "cpu/smt.hh"
#include "sim/core.hh"
+#include "sim/eventq.hh"
using namespace std;
@@ -51,100 +51,183 @@ using namespace std;
// Events on this queue are processed at the *beginning* of each
// cycle, before the pipeline simulation is performed.
//
-EventQueue mainEventQueue("MainEventQueue");
+EventQueue mainEventQueue("Main Event Queue");
#ifndef NDEBUG
Counter Event::instanceCounter = 0;
#endif
+Event::~Event()
+{
+ assert(!scheduled());
+}
+
+const std::string
+Event::name() const
+{
+#ifndef NDEBUG
+ return csprintf("Event_%d", instance);
+#else
+ return csprintf("Event_%x", (uintptr_t)this);
+#endif
+}
+
+
+Event *
+Event::insertBefore(Event *event, Event *curr)
+{
+ // Either way, event will be the top element in the 'in bin' list
+ // which is the pointer we need in order to look into the list, so
+ // we need to insert that into the bin list.
+ if (!curr || *event < *curr) {
+ // Insert the event before the current list since it is in the future.
+ event->nextBin = curr;
+ event->nextInBin = NULL;
+ } else {
+ // Since we're on the correct list, we need to point to the next list
+ event->nextBin = curr->nextBin; // curr->nextBin can now become stale
+
+ // Insert event at the top of the stack
+ event->nextInBin = curr;
+ }
+
+ return event;
+}
+
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;
+ // Deal with the head case
+ if (!head || *event <= *head) {
+ head = Event::insertBefore(event, head);
+ return;
+ }
- while (curr) {
- if (event->when() <= curr->when() &&
- (event->when() < curr->when() ||
- event->priority() <= curr->priority()))
- break;
+ // Figure out either which 'in bin' list we are on, or where a new list
+ // needs to be inserted
+ Event *prev = head;
+ Event *curr = head->nextBin;
+ while (curr && *curr < *event) {
+ prev = curr;
+ curr = curr->nextBin;
+ }
- prev = curr;
- curr = curr->next;
- }
+ // Note: this operation may render all nextBin pointers on the
+ // prev 'in bin' list stale (except for the top one)
+ prev->nextBin = Event::insertBefore(event, curr);
+}
+
+Event *
+Event::removeItem(Event *event, Event *top)
+{
+ Event *curr = top;
+ Event *next = top->nextInBin;
+
+ // if we removed the top item, we need to handle things specially
+ // and just remove the top item, fixing up the next bin pointer of
+ // the new top item
+ if (event == top) {
+ if (!next)
+ return top->nextBin;
+ next->nextBin = top->nextBin;
+ return next;
+ }
+
+ // Since we already checked the current element, we're going to
+ // keep checking event against the next element.
+ while (event != next) {
+ if (!next)
+ panic("event not found!");
- event->next = curr;
- prev->next = event;
+ curr = next;
+ next = next->nextInBin;
}
+
+ // remove next from the 'in bin' list since it's what we're looking for
+ curr->nextInBin = next->nextInBin;
+ return top;
}
void
EventQueue::remove(Event *event)
{
if (head == NULL)
- return;
+ panic("event not found!");
- if (head == event){
- head = event->next;
+ // deal with an event on the head's 'in bin' list (event has the same
+ // time as the head)
+ if (*head == *event) {
+ head = Event::removeItem(event, head);
return;
}
+ // Find the 'in bin' list that this event belongs on
Event *prev = head;
- Event *curr = head->next;
- while (curr && curr != event) {
+ Event *curr = head->nextBin;
+ while (curr && *curr < *event) {
prev = curr;
- curr = curr->next;
+ curr = curr->nextBin;
}
- if (curr == event)
- prev->next = curr->next;
+ if (!curr || *curr != *event)
+ panic("event not found!");
+
+ // curr points to the top item of the the correct 'in bin' list, when
+ // we remove an item, it returns the new top item (which may be
+ // unchanged)
+ prev->nextBin = Event::removeItem(event, curr);
}
Event *
EventQueue::serviceOne()
{
Event *event = head;
- event->clearFlags(Event::Scheduled);
- head = event->next;
+ Event *next = head->nextInBin;
+ event->flags.clear(Event::Scheduled);
+
+ if (next) {
+ // update the next bin pointer since it could be stale
+ next->nextBin = head->nextBin;
+
+ // pop the stack
+ head = next;
+ } else {
+ // this was the only element on the 'in bin' list, so get rid of
+ // the 'in bin' list and point to the next bin list
+ head = head->nextBin;
+ }
// handle action
if (!event->squashed()) {
event->process();
if (event->isExitEvent()) {
- assert(!event->getFlags(Event::AutoDelete)); // would be silly
+ assert(!event->flags.isSet(Event::AutoDelete)); // would be silly
return event;
}
} else {
- event->clearFlags(Event::Squashed);
+ event->flags.clear(Event::Squashed);
}
- if (event->getFlags(Event::AutoDelete) && !event->scheduled())
+ if (event->flags.isSet(Event::AutoDelete) && !event->scheduled())
delete event;
return NULL;
}
-
void
Event::serialize(std::ostream &os)
{
SERIALIZE_SCALAR(_when);
SERIALIZE_SCALAR(_priority);
- SERIALIZE_ENUM(_flags);
+ short _flags = flags;
+ SERIALIZE_SCALAR(_flags);
}
-
void
Event::unserialize(Checkpoint *cp, const string &section)
{
if (scheduled())
- deschedule();
+ mainEventQueue.deschedule(this);
UNSERIALIZE_SCALAR(_when);
UNSERIALIZE_SCALAR(_priority);
@@ -152,13 +235,16 @@ Event::unserialize(Checkpoint *cp, const string &section)
// 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);
+ short _flags;
+ UNSERIALIZE_SCALAR(_flags);
+ flags = _flags;
+
+ bool wasScheduled = flags.isSet(Scheduled) && !flags.isSet(Squashed);
+ flags.clear(Squashed | Scheduled);
if (wasScheduled) {
DPRINTF(Config, "rescheduling at %d\n", _when);
- schedule(_when);
+ mainEventQueue.schedule(this, _when);
}
}
@@ -168,18 +254,25 @@ 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 *nextBin = head;
+ while (nextBin) {
+ Event *nextInBin = nextBin;
+
+ while (nextInBin) {
+ if (nextInBin->flags.isSet(Event::AutoSerialize)) {
+ eventPtrs.push_back(nextInBin);
+ paramOut(os, csprintf("event%d", numEvents++),
+ nextInBin->name());
+ }
+ nextInBin = nextInBin->nextInBin;
}
- event = event->next;
+
+ nextBin = nextBin->nextBin;
}
SERIALIZE_SCALAR(numEvents);
- for (std::list<Event *>::iterator it=eventPtrs.begin();
+ for (std::list<Event *>::iterator it = eventPtrs.begin();
it != eventPtrs.end(); ++it) {
(*it)->nameOut(os);
(*it)->serialize(os);
@@ -203,7 +296,7 @@ EventQueue::unserialize(Checkpoint *cp, const std::string &section)
}
void
-EventQueue::dump()
+EventQueue::dump() const
{
cprintf("============================================================\n");
cprintf("EventQueue Dump (cycle %d)\n", curTick);
@@ -212,16 +305,63 @@ EventQueue::dump()
if (empty())
cprintf("<No Events>\n");
else {
- Event *event = head;
- while (event) {
- event->dump();
- event = event->next;
+ Event *nextBin = head;
+ while (nextBin) {
+ Event *nextInBin = nextBin;
+ while (nextInBin) {
+ nextInBin->dump();
+ nextInBin = nextInBin->nextInBin;
+ }
+
+ nextBin = nextBin->nextBin;
}
}
cprintf("============================================================\n");
}
+bool
+EventQueue::debugVerify() const
+{
+ m5::hash_map<long, bool> map;
+
+ Tick time = 0;
+ short priority = 0;
+
+ Event *nextBin = head;
+ while (nextBin) {
+ Event *nextInBin = nextBin;
+ while (nextInBin) {
+ if (nextInBin->when() < time) {
+ cprintf("time goes backwards!");
+ nextInBin->dump();
+ return false;
+ } else if (nextInBin->when() == time &&
+ nextInBin->priority() < priority) {
+ cprintf("priority inverted!");
+ nextInBin->dump();
+ return false;
+ }
+
+ if (map[reinterpret_cast<long>(nextInBin)]) {
+ cprintf("Node already seen");
+ nextInBin->dump();
+ return false;
+ }
+ map[reinterpret_cast<long>(nextInBin)] = true;
+
+ time = nextInBin->when();
+ priority = nextInBin->priority();
+
+ nextInBin = nextInBin->nextInBin;
+ }
+
+ nextBin = nextBin->nextBin;
+ }
+
+ return true;
+}
+
void
dumpMainQueue()
{
@@ -235,7 +375,6 @@ Event::description() const
return "generic";
}
-#if TRACING_ON
void
Event::trace(const char *action)
{
@@ -250,23 +389,21 @@ Event::trace(const char *action)
// needs to be printed.
DPRINTFN("%s event %s @ %d\n", description(), action, when());
}
-#endif
void
-Event::dump()
+Event::dump() const
{
- cprintf("Event (%s)\n", description());
- cprintf("Flags: %#x\n", _flags);
-#if TRACING_ON
- cprintf("Created: %d\n", when_created);
+ cprintf("Event %s (%s)\n", name(), description());
+ cprintf("Flags: %#x\n", flags);
+#ifdef EVENTQ_DEBUG
+ cprintf("Created: %d\n", whenCreated);
#endif
if (scheduled()) {
-#if TRACING_ON
- cprintf("Scheduled at %d\n", when_scheduled);
+#ifdef EVENTQ_DEBUG
+ cprintf("Scheduled at %d\n", whenScheduled);
#endif
cprintf("Scheduled for %d, priority %d\n", when(), _priority);
- }
- else {
+ } else {
cprintf("Not Scheduled\n");
}
}
diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh
index a454e5d64..33bb34252 100644
--- a/src/sim/eventq.hh
+++ b/src/sim/eventq.hh
@@ -36,45 +36,70 @@
#ifndef __SIM_EVENTQ_HH__
#define __SIM_EVENTQ_HH__
-#include <assert.h>
-
#include <algorithm>
+#include <cassert>
+#include <climits>
#include <map>
#include <string>
#include <vector>
-#include "sim/host.hh" // for Tick
-
#include "base/fast_alloc.hh"
+#include "base/flags.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "sim/serialize.hh"
+#include "sim/host.hh"
-class EventQueue; // forward declaration
-
-//////////////////////
-//
-// Main Event Queue
-//
-// Events on this queue are processed at the *beginning* of each
-// cycle, before the pipeline simulation is performed.
-//
-// defined in eventq.cc
-//
-//////////////////////
-extern EventQueue mainEventQueue;
+class EventQueue; // forward declaration
+extern EventQueue mainEventQueue;
/*
* An item on an event queue. The action caused by a given
* event is specified by deriving a subclass and overriding the
* process() member function.
+ *
+ * Caution, the order of members is chosen to maximize data packing.
*/
class Event : public Serializable, public FastAlloc
{
friend class EventQueue;
+ protected:
+ typedef short FlagsType;
+ typedef ::Flags<FlagsType> Flags;
+
+ static const FlagsType PublicRead = 0x003f;
+ static const FlagsType PublicWrite = 0x001d;
+ static const FlagsType Squashed = 0x0001;
+ static const FlagsType Scheduled = 0x0002;
+ static const FlagsType AutoDelete = 0x0004;
+ static const FlagsType AutoSerialize = 0x0008;
+ static const FlagsType IsExitEvent = 0x0010;
+ static const FlagsType IsMainQueue = 0x0020;
+#ifdef EVENTQ_DEBUG
+ static const FlagsType Initialized = 0xf000;
+#endif
+
private:
+ // The event queue is now a linked list of linked lists. The
+ // 'nextBin' pointer is to find the bin, where a bin is defined as
+ // when+priority. All events in the same bin will be stored in a
+ // second linked list (a stack) maintained by the 'nextInBin'
+ // pointer. The list will be accessed in LIFO order. The end
+ // result is that the insert/removal in 'nextBin' is
+ // linear/constant, and the lookup/removal in 'nextInBin' is
+ // constant/constant. Hopefully this is a significant improvement
+ // over the current fully linear insertion.
+ Event *nextBin;
+ Event *nextInBin;
+
+ static Event *insertBefore(Event *event, Event *curr);
+ static Event *removeItem(Event *event, Event *last);
+
+ Tick _when; //!< timestamp when event should be processed
+ short _priority; //!< event priority
+ Flags flags;
#ifndef NDEBUG
/// Global counter to generate unique IDs for Event instances
@@ -84,54 +109,85 @@ class Event : public Serializable, public FastAlloc
/// this but they're not consistent across runs making debugging
/// more difficult. Thus we use a global counter value when
/// debugging.
- Counter instanceId;
-#endif // NDEBUG
+ Counter instance;
/// queue to which this event belongs (though it may or may not be
/// scheduled on this queue yet)
EventQueue *queue;
+#endif
- Event *next;
+#ifdef EVENTQ_DEBUG
+ Tick whenCreated; //!< time created
+ Tick whenScheduled; //!< time scheduled
+#endif
- Tick _when; //!< timestamp when event should be processed
- int _priority; //!< event priority
- char _flags;
+ void
+ setWhen(Tick when, EventQueue *q)
+ {
+ _when = when;
+#ifndef NDEBUG
+ queue = q;
+#endif
+#ifdef EVENTQ_DEBUG
+ whenScheduled = curTick;
+#endif
+ }
protected:
- enum Flags {
- None = 0x0,
- Squashed = 0x1,
- Scheduled = 0x2,
- AutoDelete = 0x4,
- AutoSerialize = 0x8,
- IsExitEvent = 0x10
- };
+ /// Accessor for flags.
+ Flags
+ getFlags() const
+ {
+ return flags & PublicRead;
+ }
- bool getFlags(Flags f) const { return (_flags & f) == f; }
- void setFlags(Flags f) { _flags |= f; }
- void clearFlags(Flags f) { _flags &= ~f; }
+ Flags
+ getFlags(Flags _flags) const
+ {
+ assert(flags.noneSet(~PublicRead));
+ return flags.isSet(_flags);
+ }
- protected:
- EventQueue *theQueue() const { return queue; }
+ Flags
+ allFlags(Flags _flags) const
+ {
+ assert(_flags.noneSet(~PublicRead));
+ return flags.allSet(_flags);
+ }
-#if TRACING_ON
- Tick when_created; //!< Keep track of creation time For debugging
- Tick when_scheduled; //!< Keep track of creation time For debugging
+ /// Accessor for flags.
+ void
+ setFlags(Flags _flags)
+ {
+ assert(_flags.noneSet(~PublicWrite));
+ flags.set(_flags);
+ }
- virtual void trace(const char *action); //!< trace event activity
-#else
- void trace(const char *) {}
-#endif
+ void
+ clearFlags(Flags _flags)
+ {
+ assert(_flags.noneSet(~PublicWrite));
+ flags.clear(_flags);
+ }
- unsigned annotated_value;
+ void
+ clearFlags()
+ {
+ flags.clear(PublicWrite);
+ }
- public:
+ // This function isn't really useful if TRACING_ON is not defined
+ virtual void trace(const char *action); //!< trace event activity
+ public:
/// Event priorities, to provide tie-breakers for events scheduled
/// at the same cycle. Most events are scheduled at the default
/// priority; these values are used to control events that need to
/// be ordered within a cycle.
enum Priority {
+ /// Minimum priority
+ Minimum_Pri = SHRT_MIN,
+
/// If we enable tracing on a particular cycle, do that as the
/// very first thing so we don't miss any of the events on
/// that cycle (even if we enter the debugger).
@@ -140,81 +196,66 @@ class Event : public Serializable, public FastAlloc
/// Breakpoints should happen before anything else (except
/// enabling trace output), so we don't miss any action when
/// debugging.
- Debug_Break_Pri = -100,
+ Debug_Break_Pri = -100,
/// CPU switches schedule the new CPU's tick event for the
/// same cycle (after unscheduling the old CPU's tick event).
/// The switch needs to come before any tick events to make
/// sure we don't tick both CPUs in the same cycle.
- CPU_Switch_Pri = -31,
+ CPU_Switch_Pri = -31,
/// For some reason "delayed" inter-cluster writebacks are
/// scheduled before regular writebacks (which have default
/// priority). Steve?
- Delayed_Writeback_Pri = -1,
+ Delayed_Writeback_Pri = -1,
/// Default is zero for historical reasons.
- Default_Pri = 0,
+ Default_Pri = 0,
/// Serailization needs to occur before tick events also, so
/// that a serialize/unserialize is identical to an on-line
/// CPU switch.
- Serialize_Pri = 32,
+ Serialize_Pri = 32,
/// CPU ticks must come after other associated CPU events
/// (such as writebacks).
- CPU_Tick_Pri = 50,
+ CPU_Tick_Pri = 50,
/// Statistics events (dump, reset, etc.) come after
/// everything else, but before exit.
- Stat_Event_Pri = 90,
+ Stat_Event_Pri = 90,
/// Progress events come at the end.
Progress_Event_Pri = 95,
/// If we want to exit on this cycle, it's the very last thing
/// we do.
- Sim_Exit_Pri = 100
+ Sim_Exit_Pri = 100,
+
+ /// Maximum priority
+ Maximum_Pri = SHRT_MAX
};
/*
* Event constructor
* @param queue that the event gets scheduled on
*/
- Event(EventQueue *q, Priority p = Default_Pri)
- : queue(q), next(NULL), _priority(p), _flags(None),
-#if TRACING_ON
- when_created(curTick), when_scheduled(0),
-#endif
- annotated_value(0)
+ Event(Priority p = Default_Pri)
+ : nextBin(NULL), nextInBin(NULL), _priority(p)
{
#ifndef NDEBUG
- instanceId = ++instanceCounter;
+ instance = ++instanceCounter;
+ queue = NULL;
#endif
- }
-
- ~Event() {}
-
- virtual const std::string name() const {
-#ifndef NDEBUG
- return csprintf("Event_%d", instanceId);
-#else
- return csprintf("Event_%x", (uintptr_t)this);
+#ifdef EVENTQ_DEBUG
+ flags.set(Initialized);
+ whenCreated = curTick;
+ whenScheduled = 0;
#endif
}
- /// Determine if the current event is scheduled
- bool scheduled() const { return getFlags(Scheduled); }
-
- /// Schedule the event with the current priority or default priority
- void schedule(Tick t);
-
- /// Reschedule the event with the current priority
- // always parameter means to schedule if not already scheduled
- void reschedule(Tick t, bool always = false);
-
- /// Remove the event from the current schedule
- void deschedule();
+ virtual ~Event();
+ virtual const std::string name() const;
/// Return a C string describing the event. This string should
/// *not* be dynamically allocated; just a const char array
@@ -222,8 +263,9 @@ class Event : public Serializable, public FastAlloc
virtual const char *description() const;
/// Dump the current event data
- void dump();
+ void dump() const;
+ public:
/*
* This member function is invoked when the event is processed
* (occurs). There is no default implementation; each subclass
@@ -236,17 +278,17 @@ class Event : public Serializable, public FastAlloc
*/
virtual void process() = 0;
- void annotate(unsigned value) { annotated_value = value; };
- unsigned annotation() { return annotated_value; }
+ /// Determine if the current event is scheduled
+ bool scheduled() const { return flags.isSet(Scheduled); }
/// Squash the current event
- void squash() { setFlags(Squashed); }
+ void squash() { flags.set(Squashed); }
/// Check whether the event is squashed
- bool squashed() { return getFlags(Squashed); }
+ bool squashed() const { return flags.isSet(Squashed); }
/// See if this is a SimExitEvent (without resorting to RTTI)
- bool isExitEvent() { return getFlags(IsExitEvent); }
+ bool isExitEvent() const { return flags.isSet(IsExitEvent); }
/// Get the time that the event is scheduled
Tick when() const { return _when; }
@@ -254,65 +296,20 @@ class Event : public Serializable, public FastAlloc
/// Get the event priority
int priority() const { return _priority; }
- struct priority_compare :
- public std::binary_function<Event *, Event *, bool>
+#ifndef SWIG
+ struct priority_compare
+ : public std::binary_function<Event *, Event *, bool>
{
- bool operator()(const Event *l, const Event *r) const {
+ bool
+ operator()(const Event *l, const Event *r) const
+ {
return l->when() >= r->when() || l->priority() >= r->priority();
}
};
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
-};
-
-template <class T, void (T::* F)()>
-void
-DelayFunction(Tick when, T *object)
-{
- class DelayEvent : public Event
- {
- private:
- T *object;
-
- public:
- DelayEvent(Tick when, T *o)
- : Event(&mainEventQueue), object(o)
- { setFlags(this->AutoDestroy); schedule(when); }
- void process() { (object->*F)(); }
- const char *description() const { return "delay"; }
- };
-
- new DelayEvent(when, object);
-}
-
-template <class T, void (T::* F)()>
-class EventWrapper : public Event
-{
- private:
- T *object;
-
- public:
- EventWrapper(T *obj, bool del = false,
- EventQueue *q = &mainEventQueue,
- Priority p = Default_Pri)
- : Event(q, p), object(obj)
- {
- if (del)
- setFlags(AutoDelete);
- }
-
- EventWrapper(T *obj, Tick t, bool del = false,
- EventQueue *q = &mainEventQueue,
- Priority p = Default_Pri)
- : Event(q, p), object(obj)
- {
- if (del)
- setFlags(AutoDelete);
- schedule(t);
- }
-
- void process() { (object->*F)(); }
+#endif
};
/*
@@ -320,18 +317,14 @@ class EventWrapper : public Event
*/
class EventQueue : public Serializable
{
- protected:
- std::string objName;
-
private:
+ std::string objName;
Event *head;
void insert(Event *event);
void remove(Event *event);
public:
-
- // constructor
EventQueue(const std::string &n)
: objName(n), head(NULL)
{}
@@ -339,17 +332,19 @@ class EventQueue : public Serializable
virtual const std::string name() const { return objName; }
// schedule the given event on this queue
- void schedule(Event *ev);
- void deschedule(Event *ev);
- void reschedule(Event *ev);
+ void schedule(Event *event, Tick when);
+ void deschedule(Event *event);
+ void reschedule(Event *event, Tick when, bool always = false);
- Tick nextTick() { return head->when(); }
+ Tick nextTick() const { return head->when(); }
Event *serviceOne();
// process all events up to the given timestamp. we inline a
// quick test to see if there are any events to process; if so,
// call the internal out-of-line version to process them all.
- void serviceEvents(Tick when) {
+ void
+ serviceEvents(Tick when)
+ {
while (!empty()) {
if (nextTick() > when)
break;
@@ -367,76 +362,129 @@ class EventQueue : public Serializable
void serviceEvents() { serviceEvents(curTick); }
// return true if no events are queued
- bool empty() { return head == NULL; }
+ bool empty() const { return head == NULL; }
- void dump();
+ void dump() const;
Tick nextEventTime() { return empty() ? curTick : head->when(); }
+ bool debugVerify() const;
+
+#ifndef SWIG
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
+#endif
};
+#ifndef SWIG
+class EventManager
+{
+ protected:
+ /** A pointer to this object's event queue */
+ EventQueue *eventq;
-//////////////////////
-//
-// inline functions
-//
-// can't put these inside declaration due to circular dependence
-// between Event and EventQueue classes.
-//
-//////////////////////
+ public:
+ EventManager(EventManager &em) : eventq(em.queue()) {}
+ EventManager(EventManager *em) : eventq(em ? em->queue() : NULL) {}
+ EventManager(EventQueue *eq) : eventq(eq) {}
-// schedule at specified time (place on event queue specified via
-// constructor)
-inline void
-Event::schedule(Tick t)
-{
- assert(!scheduled());
-// if (t < curTick)
-// warn("t is less than curTick, ensure you don't want cycles");
+ EventQueue *
+ queue() const
+ {
+ return eventq;
+ }
- setFlags(Scheduled);
-#if TRACING_ON
- when_scheduled = curTick;
-#endif
- _when = t;
- queue->schedule(this);
-}
+ void
+ schedule(Event &event, Tick when)
+ {
+ eventq->schedule(&event, when);
+ }
-inline void
-Event::deschedule()
+ void
+ deschedule(Event &event)
+ {
+ eventq->deschedule(&event);
+ }
+
+ void
+ reschedule(Event &event, Tick when, bool always = false)
+ {
+ eventq->reschedule(&event, when, always);
+ }
+
+ void
+ schedule(Event *event, Tick when)
+ {
+ eventq->schedule(event, when);
+ }
+
+ void
+ deschedule(Event *event)
+ {
+ eventq->deschedule(event);
+ }
+
+ void
+ reschedule(Event *event, Tick when, bool always = false)
+ {
+ eventq->reschedule(event, when, always);
+ }
+};
+
+template <class T, void (T::* F)()>
+void
+DelayFunction(EventQueue *eventq, Tick when, T *object)
{
- assert(scheduled());
+ class DelayEvent : public Event
+ {
+ private:
+ T *object;
+
+ public:
+ DelayEvent(T *o)
+ : object(o)
+ { this->setFlags(AutoDelete); }
+ void process() { (object->*F)(); }
+ const char *description() const { return "delay"; }
+ };
- clearFlags(Squashed);
- clearFlags(Scheduled);
- queue->deschedule(this);
+ eventq->schedule(new DelayEvent(object), when);
}
-inline void
-Event::reschedule(Tick t, bool always)
+template <class T, void (T::* F)()>
+class EventWrapper : public Event
{
- assert(scheduled() || always);
+ private:
+ T *object;
-#if TRACING_ON
- when_scheduled = curTick;
-#endif
- _when = t;
-
- if (scheduled()) {
- clearFlags(Squashed);
- queue->reschedule(this);
- } else {
- setFlags(Scheduled);
- queue->schedule(this);
+ public:
+ EventWrapper(T *obj, bool del = false, Priority p = Default_Pri)
+ : Event(p), object(obj)
+ {
+ if (del)
+ setFlags(AutoDelete);
}
-}
+
+ void process() { (object->*F)(); }
+};
inline void
-EventQueue::schedule(Event *event)
+EventQueue::schedule(Event *event, Tick when)
{
+ assert(when >= curTick);
+ assert(!event->scheduled());
+#ifdef EVENTQ_DEBUG
+ assert((event->flags & Event::Initialized) == Event::Initialized);
+#endif
+
+ event->setWhen(when, this);
insert(event);
+ event->flags.set(Event::Scheduled);
+ if (this == &mainEventQueue)
+ event->flags.set(Event::IsMainQueue);
+ else
+ event->flags.clear(Event::IsMainQueue);
+
if (DTRACE(Event))
event->trace("scheduled");
}
@@ -444,20 +492,86 @@ EventQueue::schedule(Event *event)
inline void
EventQueue::deschedule(Event *event)
{
+ assert(event->scheduled());
+#ifdef EVENTQ_DEBUG
+ assert((event->flags & Event::Initialized) == Event::Initialized);
+#endif
+
remove(event);
+
+ event->flags.clear(Event::Squashed);
+ event->flags.clear(Event::Scheduled);
+
+ if (event->flags.isSet(Event::AutoDelete))
+ delete event;
+
if (DTRACE(Event))
event->trace("descheduled");
}
inline void
-EventQueue::reschedule(Event *event)
+EventQueue::reschedule(Event *event, Tick when, bool always)
{
- remove(event);
+ assert(when >= curTick);
+ assert(always || event->scheduled());
+#ifdef EVENTQ_DEBUG
+ assert((event->flags & Event::Initialized) == Event::Initialized);
+#endif
+
+ if (event->scheduled())
+ remove(event);
+
+ event->setWhen(when, this);
insert(event);
+ event->flags.clear(Event::Squashed);
+ event->flags.set(Event::Scheduled);
+ if (this == &mainEventQueue)
+ event->flags.set(Event::IsMainQueue);
+ else
+ event->flags.clear(Event::IsMainQueue);
+
if (DTRACE(Event))
event->trace("rescheduled");
}
+inline bool
+operator<(const Event &l, const Event &r)
+{
+ return l.when() < r.when() ||
+ (l.when() == r.when() && l.priority() < r.priority());
+}
+inline bool
+operator>(const Event &l, const Event &r)
+{
+ return l.when() > r.when() ||
+ (l.when() == r.when() && l.priority() > r.priority());
+}
+
+inline bool
+operator<=(const Event &l, const Event &r)
+{
+ return l.when() < r.when() ||
+ (l.when() == r.when() && l.priority() <= r.priority());
+}
+inline bool
+operator>=(const Event &l, const Event &r)
+{
+ return l.when() > r.when() ||
+ (l.when() == r.when() && l.priority() >= r.priority());
+}
+
+inline bool
+operator==(const Event &l, const Event &r)
+{
+ return l.when() == r.when() && l.priority() == r.priority();
+}
+
+inline bool
+operator!=(const Event &l, const Event &r)
+{
+ return l.when() != r.when() || l.priority() != r.priority();
+}
+#endif
#endif // __SIM_EVENTQ_HH__
diff --git a/src/sim/faults.hh b/src/sim/faults.hh
index cfc6ad105..75696641b 100644
--- a/src/sim/faults.hh
+++ b/src/sim/faults.hh
@@ -41,7 +41,7 @@ class FaultBase;
typedef RefCountingPtr<FaultBase> Fault;
typedef const char * FaultName;
-typedef Stats::Scalar<> FaultStat;
+typedef Stats::Scalar FaultStat;
// Each class has it's name statically define in _name,
// and has a virtual function to access it's name.
diff --git a/src/sim/host.hh b/src/sim/host.hh
index 93a5fe7f2..dd29534fd 100644
--- a/src/sim/host.hh
+++ b/src/sim/host.hh
@@ -38,13 +38,11 @@
#define __HOST_HH__
#include <inttypes.h>
-#include <limits>
-
/** uint64_t constant */
-#define ULL(N) ((uint64_t)N##ULL)
+#define ULL(N) ((uint64_t)N##ULL)
/** int64_t constant */
-#define LL(N) ((int64_t)N##LL)
+#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
@@ -58,7 +56,7 @@ typedef int64_t Counter;
*/
typedef int64_t Tick;
-const Tick MaxTick = std::numeric_limits<Tick>::max();
+const Tick MaxTick = LL(0x7fffffffffffffff);
/**
* Address type
diff --git a/src/sim/init.cc b/src/sim/init.cc
new file mode 100644
index 000000000..66eddfb6f
--- /dev/null
+++ b/src/sim/init.cc
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (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
+ */
+
+#include <Python.h>
+#include <marshal.h>
+#include <signal.h>
+
+#include <iostream>
+#include <string>
+#include <zlib.h>
+
+#include "base/cprintf.hh"
+#include "base/misc.hh"
+#include "sim/async.hh"
+#include "sim/core.hh"
+#include "sim/host.hh"
+#include "sim/init.hh"
+
+using namespace std;
+
+/// Stats signal handler.
+void
+dumpStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_statdump = true;
+}
+
+void
+dumprstStatsHandler(int sigtype)
+{
+ async_event = true;
+ async_statdump = true;
+ async_statreset = true;
+}
+
+/// Exit signal handler.
+void
+exitNowHandler(int sigtype)
+{
+ async_event = true;
+ async_exit = true;
+}
+
+/// Abort signal handler.
+void
+abortHandler(int sigtype)
+{
+ ccprintf(cerr, "Program aborted at cycle %d\n", curTick);
+}
+
+/*
+ * M5 can do several special things when various signals are sent.
+ * None are mandatory.
+ */
+void
+initSignals()
+{
+ // Floating point exceptions may happen on misspeculated paths, so
+ // ignore them
+ signal(SIGFPE, SIG_IGN);
+
+ // We use SIGTRAP sometimes for debugging
+ signal(SIGTRAP, SIG_IGN);
+
+ // Dump intermediate stats
+ signal(SIGUSR1, dumpStatsHandler);
+
+ // Dump intermediate stats and reset them
+ signal(SIGUSR2, dumprstStatsHandler);
+
+ // Exit cleanly on Interrupt (Ctrl-C)
+ signal(SIGINT, exitNowHandler);
+
+ // Print out cycle number on abort
+ signal(SIGABRT, abortHandler);
+}
+
+/*
+ * Uncompress and unmarshal the code object stored in the
+ * EmbeddedPyModule
+ */
+PyObject *
+getCode(const EmbeddedPyModule *pymod)
+{
+ assert(pymod->zlen == pymod->code_end - pymod->code);
+ Bytef *marshalled = new Bytef[pymod->mlen];
+ uLongf unzlen = pymod->mlen;
+ int ret = uncompress(marshalled, &unzlen, (const Bytef *)pymod->code,
+ pymod->zlen);
+ if (ret != Z_OK)
+ panic("Could not uncompress code: %s\n", zError(ret));
+ assert(unzlen == pymod->mlen);
+
+ return PyMarshal_ReadObjectFromString((char *)marshalled, pymod->mlen);
+}
+
+// The python library is totally messed up with respect to constness,
+// so make a simple macro to make life a little easier
+#define PyCC(x) (const_cast<char *>(x))
+
+/*
+ * Load and initialize all of the python parts of M5, including Swig
+ * and the embedded module importer.
+ */
+int
+initM5Python()
+{
+ extern void initSwig();
+
+ // initialize SWIG modules. initSwig() is autogenerated and calls
+ // all of the individual swig initialization functions.
+ initSwig();
+
+ // Load the importer module
+ PyObject *code = getCode(&embeddedPyImporter);
+ PyObject *module = PyImport_ExecCodeModule(PyCC("importer"), code);
+ if (!module) {
+ PyErr_Print();
+ return 1;
+ }
+
+ // Load the rest of the embedded python files into the embedded
+ // python importer
+ const EmbeddedPyModule *pymod = &embeddedPyModules[0];
+ while (pymod->filename) {
+ PyObject *code = getCode(pymod);
+ PyObject *result = PyObject_CallMethod(module, PyCC("add_module"),
+ PyCC("ssO"), pymod->filename, pymod->modpath, code);
+ if (!result) {
+ PyErr_Print();
+ return 1;
+ }
+ Py_DECREF(result);
+ ++pymod;
+ }
+
+ return 0;
+}
+
+/*
+ * Start up the M5 simulator. This mostly vectors into the python
+ * main function.
+ */
+int
+m5Main(int argc, char **argv)
+{
+ PySys_SetArgv(argc, argv);
+
+ // We have to set things up in the special __main__ module
+ PyObject *module = PyImport_AddModule(PyCC("__main__"));
+ if (module == NULL)
+ panic("Could not import __main__");
+ PyObject *dict = PyModule_GetDict(module);
+
+ // import the main m5 module
+ PyObject *result;
+ result = PyRun_String("import m5", Py_file_input, dict, dict);
+ if (!result) {
+ PyErr_Print();
+ return 1;
+ }
+ Py_DECREF(result);
+
+ // Start m5
+ result = PyRun_String("m5.main()", Py_file_input, dict, dict);
+ if (!result) {
+ PyErr_Print();
+ return 1;
+ }
+ Py_DECREF(result);
+
+ return 0;
+}
+
+PyMODINIT_FUNC
+initm5(void)
+{
+ initM5Python();
+ PyImport_ImportModule(PyCC("m5"));
+}
diff --git a/src/mem/config/prefetch.hh b/src/sim/init.hh
index d24db79da..b0f29bf30 100644
--- a/src/mem/config/prefetch.hh
+++ b/src/sim/init.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,17 +25,30 @@
* (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: Ron Dreslinski
+ * Authors: Nathan Binkert
*/
-/**
- * @file
- * Central location to configure which prefetch types we want to build
- * into the simulator. In the future, this should probably be
- * autogenerated by some sort of configuration script.
+#ifndef __SIM_INIT_HH__
+#define __SIM_INIT_HH__
+
+/*
+ * Data structure describing an embedded python file.
*/
-#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no
- //prefetching case unless you always want to use a
- //different prefetcher
-//#define USE_STRIDED 1
-//#define USE_GHB 1
+struct EmbeddedPyModule
+{
+ const char *filename;
+ const char *modpath;
+ const char *code;
+ const char *code_end;
+ int zlen;
+ int mlen;
+};
+
+extern const EmbeddedPyModule embeddedPyImporter;
+extern const EmbeddedPyModule embeddedPyModules[];
+
+void initSignals();
+int initM5Python();
+int m5Main(int argc, char **argv);
+
+#endif // __SIM_INIT_HH__
diff --git a/src/sim/insttracer.hh b/src/sim/insttracer.hh
index 9a20c7c56..9fb5f9f22 100644
--- a/src/sim/insttracer.hh
+++ b/src/sim/insttracer.hh
@@ -34,7 +34,7 @@
#include "base/bigint.hh"
#include "base/trace.hh"
-#include "cpu/inst_seq.hh" // for InstSeqNum
+#include "cpu/inst_seq.hh" // for InstSeqNum
#include "cpu/static_inst.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
@@ -55,6 +55,8 @@ class InstRecord
// dump the record
StaticInstPtr staticInst;
Addr PC;
+ StaticInstPtr macroStaticInst;
+ MicroPC upc;
bool misspeculating;
// The remaining fields are only valid for particular instruction
@@ -71,7 +73,7 @@ class InstRecord
} data;
enum {
DataInvalid = 0,
- DataInt8 = 1, // set to equal number of bytes
+ DataInt8 = 1, // set to equal number of bytes
DataInt16 = 2,
DataInt32 = 4,
DataInt64 = 8,
@@ -86,10 +88,13 @@ class InstRecord
public:
InstRecord(Tick _when, ThreadContext *_thread,
- const StaticInstPtr &_staticInst,
- Addr _pc, bool spec)
+ const StaticInstPtr _staticInst,
+ Addr _pc, bool spec,
+ const StaticInstPtr _macroStaticInst = NULL,
+ MicroPC _upc = 0)
: when(_when), thread(_thread),
staticInst(_staticInst), PC(_pc),
+ macroStaticInst(_macroStaticInst), upc(_upc),
misspeculating(spec)
{
data_status = DataInvalid;
@@ -137,7 +142,9 @@ class InstTracer : public SimObject
virtual InstRecord *
getInstRecord(Tick when, ThreadContext *tc,
- const StaticInstPtr staticInst, Addr pc) = 0;
+ const StaticInstPtr staticInst, Addr pc,
+ const StaticInstPtr macroStaticInst = NULL,
+ MicroPC _upc = 0) = 0;
};
diff --git a/src/sim/main.cc b/src/sim/main.cc
index baca556a0..d674e0cff 100644
--- a/src/sim/main.cc
+++ b/src/sim/main.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Hewlett-Packard Development Company
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,125 +29,33 @@
*/
#include <Python.h>
-#include <signal.h>
-#include <iostream>
-#include <string>
-
-#include "base/cprintf.hh"
-#include "base/misc.hh"
-#include "config/pythonhome.hh"
-#include "python/swig/init.hh"
-#include "sim/async.hh"
-#include "sim/host.hh"
-#include "sim/core.hh"
-
-using namespace std;
-
-/// Stats signal handler.
-void
-dumpStatsHandler(int sigtype)
-{
- async_event = true;
- async_statdump = true;
-}
-
-void
-dumprstStatsHandler(int sigtype)
-{
- async_event = true;
- async_statdump = true;
- async_statreset = true;
-}
-
-/// Exit signal handler.
-void
-exitNowHandler(int sigtype)
-{
- async_event = true;
- async_exit = true;
-}
-
-/// Abort signal handler.
-void
-abortHandler(int sigtype)
-{
- ccprintf(cerr, "Program aborted at cycle %d\n", curTick);
-}
-
-int
-python_main()
-{
- PyObject *module;
- PyObject *dict;
- PyObject *result;
-
- module = PyImport_AddModule(const_cast<char*>("__main__"));
- if (module == NULL)
- fatal("Could not import __main__");
-
- dict = PyModule_GetDict(module);
-
- result = PyRun_String("import m5.main", Py_file_input, dict, dict);
- if (!result) {
- PyErr_Print();
- return 1;
- }
- Py_DECREF(result);
-
- result = PyRun_String("m5.main.main()", Py_file_input, dict, dict);
- if (!result) {
- PyErr_Print();
- return 1;
- }
- Py_DECREF(result);
-
- if (Py_FlushLine())
- PyErr_Clear();
-
- return 0;
-}
+#include "sim/init.hh"
+// main() is now pretty stripped down and just sets up python and then
+// calls initM5Python which loads the various embedded python modules
+// into the python environment and then starts things running by
+// calling m5Main.
int
main(int argc, char **argv)
{
- 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);
-
- Py_SetProgramName(argv[0]);
-
- // default path to m5 python code is the currently executing
- // file... Python ZipImporter will find embedded zip archive.
- // The M5_ARCHIVE environment variable can be used to override this.
- char *m5_archive = getenv("M5_ARCHIVE");
- string pythonpath = m5_archive ? m5_archive : argv[0];
+ int ret;
- char *oldpath = getenv("PYTHONPATH");
- if (oldpath != NULL) {
- pythonpath += ":";
- pythonpath += oldpath;
- }
-
- if (setenv("PYTHONPATH", pythonpath.c_str(), true) == -1)
- fatal("setenv: %s\n", strerror(errno));
+ // Initialize m5 special signal handling.
+ initSignals();
- const char *python_home = getenv("PYTHONHOME");
- if (!python_home)
- python_home = PYTHONHOME;
- Py_SetPythonHome(const_cast<char*>(python_home));
+ Py_SetProgramName(argv[0]);
// initialize embedded Python interpreter
Py_Initialize();
- PySys_SetArgv(argc, argv);
- // initialize SWIG modules
- init_swig();
+ // Initialize the embedded m5 python library
+ ret = initM5Python();
- int ret = python_main();
+ if (ret == 0) {
+ // start m5
+ ret = m5Main(argc, argv);
+ }
// clean up Python intepreter.
Py_Finalize();
diff --git a/src/cpu/o3/sparc/cpu.cc b/src/sim/microcode_rom.hh
index 1546a2b88..be10de86b 100644
--- a/src/cpu/o3/sparc/cpu.cc
+++ b/src/sim/microcode_rom.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * Copyright (c) 2008 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,11 +28,25 @@
* Authors: Gabe Black
*/
-#include "cpu/o3/sparc/impl.hh"
-#include "cpu/o3/sparc/cpu_impl.hh"
-#include "cpu/o3/sparc/dyn_inst.hh"
+#ifndef __SIM_MICROCODE_ROM_HH__
+#define __SIM_MICROCODE_ROM_HH__
-// Force instantiation of SparcO3CPU for all the implementations that are
-// needed. Consider merging this and sparc_dyn_inst.cc, and maybe all
-// classes that depend on a certain impl, into one file (sparc_impl.cc?).
-template class SparcO3CPU<SparcSimpleImpl>;
+/*
+ * This is a generic stub microcode ROM ISAs can use if they don't need
+ * anything more.
+ */
+
+#include "base/misc.hh"
+#include "cpu/static_inst.hh"
+
+class MicrocodeRom
+{
+ public:
+ StaticInstPtr
+ fetchMicroop(MicroPC micropc, StaticInstPtr curMacroop)
+ {
+ panic("ROM based microcode isn't implemented.\n");
+ }
+};
+
+#endif // __SIM_MICROCODE_ROM_HH__
diff --git a/src/sim/process.cc b/src/sim/process.cc
index 16037b2f4..4be97f2f6 100644
--- a/src/sim/process.cc
+++ b/src/sim/process.cc
@@ -46,6 +46,7 @@
#include "mem/translating_port.hh"
#include "params/Process.hh"
#include "params/LiveProcess.hh"
+#include "sim/debug.hh"
#include "sim/process.hh"
#include "sim/process_impl.hh"
#include "sim/stats.hh"
@@ -85,12 +86,23 @@ using namespace TheISA;
// current number of allocated processes
int num_processes = 0;
+template<class IntType>
+AuxVector<IntType>::AuxVector(IntType type, IntType val)
+{
+ a_type = TheISA::htog(type);
+ a_val = TheISA::htog(val);
+}
+
+template class AuxVector<uint32_t>;
+template class AuxVector<uint64_t>;
+
Process::Process(ProcessParams * params)
: SimObject(params), system(params->system), checkpointRestored(false),
max_stack_size(params->max_stack_size)
{
string in = params->input;
string out = params->output;
+ string err = params->errout;
// initialize file descriptors to default: same as simulator
int stdin_fd, stdout_fd, stderr_fd;
@@ -111,7 +123,16 @@ Process::Process(ProcessParams * params)
else
stdout_fd = Process::openOutputFile(out);
- stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+ if (err == "stdout" || err == "cout")
+ stderr_fd = STDOUT_FILENO;
+ else if (err == "stderr" || err == "cerr")
+ stderr_fd = STDERR_FILENO;
+ else if (err == "None")
+ stderr_fd = -1;
+ else if (err == out)
+ stderr_fd = stdout_fd;
+ else
+ stderr_fd = Process::openOutputFile(err);
M5_pid = system->allocatePID();
// initialize first 3 fds (stdin, stdout, stderr)
@@ -131,7 +152,7 @@ Process::Process(ProcessParams * params)
fdo = &fd_map[STDERR_FILENO];
fdo->fd = stderr_fd;
- fdo->filename = "STDERR";
+ fdo->filename = err;
fdo->flags = O_WRONLY;
fdo->mode = -1;
fdo->fileOffset = 0;
@@ -182,7 +203,7 @@ Process::openInputFile(const string &filename)
int
Process::openOutputFile(const string &filename)
{
- int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0774);
+ int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd == -1) {
perror(NULL);
@@ -193,33 +214,29 @@ Process::openOutputFile(const string &filename)
return fd;
}
-
-int
-Process::registerThreadContext(ThreadContext *tc)
+ThreadContext *
+Process::findFreeContext()
{
- // add to list
- int myIndex = threadContexts.size();
- threadContexts.push_back(tc);
-
- RemoteGDB *rgdb = new RemoteGDB(system, tc);
- GDBListener *gdbl = new GDBListener(rgdb, 7000 + myIndex);
- gdbl->listen();
- //gdbl->accept();
-
- remoteGDB.push_back(rgdb);
-
- // return CPU number to caller
- return myIndex;
+ int size = contextIds.size();
+ ThreadContext *tc;
+ for (int i = 0; i < size; ++i) {
+ tc = system->getThreadContext(contextIds[i]);
+ if (tc->status() == ThreadContext::Unallocated) {
+ // inactive context, free to use
+ return tc;
+ }
+ }
+ return NULL;
}
void
Process::startup()
{
- if (threadContexts.empty())
- fatal("Process %s is not associated with any CPUs!\n", name());
+ if (contextIds.empty())
+ fatal("Process %s is not associated with any HW contexts!\n", name());
// first thread context for this process... initialize & enable
- ThreadContext *tc = threadContexts[0];
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
// mark this context as active so it will start ticking.
tc->activate(0);
@@ -232,17 +249,6 @@ Process::startup()
initVirtMem->setPeer(mem_port);
}
-void
-Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
-{
- if (tcIndex >= threadContexts.size()) {
- panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
- tcIndex, threadContexts.size());
- }
-
- threadContexts[tcIndex] = tc;
-}
-
// map simulator fd sim_fd to target fd tgt_fd
void
Process::dup_fd(int sim_fd, int tgt_fd)
@@ -337,7 +343,7 @@ Process::checkAndAllocNextPage(Addr vaddr)
if(stack_base - stack_min > 8*1024*1024)
fatal("Over max stack size for one thread\n");
pTable->allocate(stack_min, TheISA::PageBytes);
- warn("Increasing stack size by one page.");
+ inform("Increasing stack size by one page.");
};
return true;
}
@@ -352,6 +358,7 @@ Process::fix_file_offsets() {
Process::FdMap *fdo_stderr = &fd_map[STDERR_FILENO];
string in = fdo_stdin->filename;
string out = fdo_stdout->filename;
+ string err = fdo_stderr->filename;
// initialize file descriptors to default: same as simulator
int stdin_fd, stdout_fd, stderr_fd;
@@ -375,11 +382,23 @@ Process::fix_file_offsets() {
stdout_fd = -1;
else{
stdout_fd = Process::openOutputFile(out);
- if (lseek(stdin_fd, fdo_stdout->fileOffset, SEEK_SET) < 0)
- panic("Unable to seek to correct in file: %s", out);
+ if (lseek(stdout_fd, fdo_stdout->fileOffset, SEEK_SET) < 0)
+ panic("Unable to seek to correct location in file: %s", out);
}
- stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+ if (err == "stdout" || err == "cout")
+ stderr_fd = STDOUT_FILENO;
+ else if (err == "stderr" || err == "cerr")
+ stderr_fd = STDERR_FILENO;
+ else if (err == "None")
+ stderr_fd = -1;
+ else if (err == out)
+ stderr_fd = stdout_fd;
+ else {
+ stderr_fd = Process::openOutputFile(err);
+ if (lseek(stderr_fd, fdo_stderr->fileOffset, SEEK_SET) < 0)
+ panic("Unable to seek to correct location in file: %s", err);
+ }
fdo_stdin->fd = stdin_fd;
fdo_stdout->fd = stdout_fd;
@@ -597,17 +616,18 @@ LiveProcess::argsInit(int intSize, int pageSize)
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
- assert(NumArgumentRegs >= 2);
- threadContexts[0]->setIntReg(ArgumentReg[0], argc);
- threadContexts[0]->setIntReg(ArgumentReg[1], argv_array_base);
- threadContexts[0]->setIntReg(StackPointerReg, stack_min);
+ ThreadContext *tc = system->getThreadContext(contextIds[0]);
+
+ setSyscallArg(tc, 0, argc);
+ setSyscallArg(tc, 1, argv_array_base);
+ tc->setIntReg(StackPointerReg, stack_min);
Addr prog_entry = objFile->entryPoint();
- threadContexts[0]->setPC(prog_entry);
- threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ tc->setPC(prog_entry);
+ tc->setNextPC(prog_entry + sizeof(MachInst));
#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
- threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ tc->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
#endif
num_processes++;
@@ -643,18 +663,17 @@ LiveProcess::create(LiveProcessParams * params)
"executable as a static binary and try again.\n");
#if THE_ISA == ALPHA_ISA
- if (objFile->hasTLS())
- fatal("Object file has a TLS section and single threaded TLS is not\n"
- " currently supported for Alpha! Please recompile your "
- "executable with \n a non-TLS toolchain.\n");
-
if (objFile->getArch() != ObjectFile::Alpha)
fatal("Object file architecture does not match compiled ISA (Alpha).");
+
switch (objFile->getOpSys()) {
case ObjectFile::Tru64:
process = new AlphaTru64Process(params, objFile);
break;
+ case ObjectFile::UnknownOpSys:
+ warn("Unknown operating system; assuming Linux.");
+ // fall through
case ObjectFile::Linux:
process = new AlphaLinuxProcess(params, objFile);
break;
@@ -663,9 +682,13 @@ LiveProcess::create(LiveProcessParams * params)
fatal("Unknown/unsupported operating system.");
}
#elif THE_ISA == SPARC_ISA
- if (objFile->getArch() != ObjectFile::SPARC64 && objFile->getArch() != ObjectFile::SPARC32)
+ if (objFile->getArch() != ObjectFile::SPARC64 &&
+ objFile->getArch() != ObjectFile::SPARC32)
fatal("Object file architecture does not match compiled ISA (SPARC).");
switch (objFile->getOpSys()) {
+ case ObjectFile::UnknownOpSys:
+ warn("Unknown operating system; assuming Linux.");
+ // fall through
case ObjectFile::Linux:
if (objFile->getArch() == ObjectFile::SPARC64) {
process = new Sparc64LinuxProcess(params, objFile);
@@ -678,16 +701,26 @@ LiveProcess::create(LiveProcessParams * params)
case ObjectFile::Solaris:
process = new SparcSolarisProcess(params, objFile);
break;
+
default:
fatal("Unknown/unsupported operating system.");
}
#elif THE_ISA == X86_ISA
- if (objFile->getArch() != ObjectFile::X86)
+ if (objFile->getArch() != ObjectFile::X86_64 &&
+ objFile->getArch() != ObjectFile::I386)
fatal("Object file architecture does not match compiled ISA (x86).");
switch (objFile->getOpSys()) {
+ case ObjectFile::UnknownOpSys:
+ warn("Unknown operating system; assuming Linux.");
+ // fall through
case ObjectFile::Linux:
- process = new X86LinuxProcess(params, objFile);
+ if (objFile->getArch() == ObjectFile::X86_64) {
+ process = new X86_64LinuxProcess(params, objFile);
+ } else {
+ process = new I386LinuxProcess(params, objFile);
+ }
break;
+
default:
fatal("Unknown/unsupported operating system.");
}
@@ -695,6 +728,9 @@ LiveProcess::create(LiveProcessParams * params)
if (objFile->getArch() != ObjectFile::Mips)
fatal("Object file architecture does not match compiled ISA (MIPS).");
switch (objFile->getOpSys()) {
+ case ObjectFile::UnknownOpSys:
+ warn("Unknown operating system; assuming Linux.");
+ // fall through
case ObjectFile::Linux:
process = new MipsLinuxProcess(params, objFile);
break;
@@ -706,6 +742,9 @@ LiveProcess::create(LiveProcessParams * params)
if (objFile->getArch() != ObjectFile::Arm)
fatal("Object file architecture does not match compiled ISA (ARM).");
switch (objFile->getOpSys()) {
+ case ObjectFile::UnknownOpSys:
+ warn("Unknown operating system; assuming Linux.");
+ // fall through
case ObjectFile::Linux:
process = new ArmLinuxProcess(params, objFile);
break;
diff --git a/src/sim/process.hh b/src/sim/process.hh
index 29d6e5aae..527209467 100644
--- a/src/sim/process.hh
+++ b/src/sim/process.hh
@@ -44,9 +44,11 @@
#include <string>
#include <vector>
+#include "arch/types.hh"
#include "base/statistics.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
+#include "sim/syscallreturn.hh"
class GDBListener;
class PageTable;
@@ -61,6 +63,18 @@ namespace TheISA
class RemoteGDB;
}
+template<class IntType>
+struct AuxVector
+{
+ IntType a_type;
+ IntType a_val;
+
+ AuxVector()
+ {}
+
+ AuxVector(IntType type, IntType val);
+};
+
class Process : public SimObject
{
public:
@@ -77,7 +91,7 @@ class Process : public SimObject
bool checkpointRestored;
// thread contexts associated with this process
- std::vector<ThreadContext *> threadContexts;
+ std::vector<int> contextIds;
// remote gdb objects
std::vector<TheISA::RemoteGDB *> remoteGDB;
@@ -85,7 +99,7 @@ class Process : public SimObject
bool breakpoint();
// number of CPUs (esxec contexts, really) assigned to this process.
- unsigned int numCpus() { return threadContexts.size(); }
+ unsigned int numCpus() { return contextIds.size(); }
// record of blocked context
struct WaitRec
@@ -95,17 +109,17 @@ class Process : public SimObject
WaitRec(Addr chan, ThreadContext *ctx)
: waitChan(chan), waitingContext(ctx)
- { }
+ { }
};
// list of all blocked contexts
std::list<WaitRec> waitList;
- Addr brk_point; // top of the data segment
+ 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 stack_base; // stack segment base (highest address)
+ unsigned stack_size; // initial stack size
+ Addr stack_min; // lowest address accessed on the stack
// The maximum size allowed for the stack.
Addr max_stack_size;
@@ -121,9 +135,9 @@ class Process : public SimObject
Addr nxm_start;
Addr nxm_end;
- std::string prog_fname; // file name
+ std::string prog_fname; // file name
- Stats::Scalar<> num_syscalls; // number of syscalls executed
+ Stats::Scalar num_syscalls; // number of syscalls executed
protected:
@@ -187,12 +201,15 @@ class Process : public SimObject
// override of virtual SimObject method: register statistics
virtual void regStats();
- // register a thread context for this process.
- // returns tc's cpu number (index into threadContexts[])
- int registerThreadContext(ThreadContext *tc);
-
+ // After getting registered with system object, tell process which
+ // system-wide context id it is assigned.
+ void assignThreadContext(int context_id)
+ {
+ contextIds.push_back(context_id);
+ }
- void replaceThreadContext(ThreadContext *tc, int tcIndex);
+ // Find a free context to use
+ ThreadContext * findFreeContext();
// map simulator fd sim_fd to target fd tgt_fd
void dup_fd(int sim_fd, int tgt_fd);
@@ -303,7 +320,14 @@ class LiveProcess : public Process
return full + filename;
}
+ std::string getcwd() const { return cwd; }
+
virtual void syscall(int64_t callnum, ThreadContext *tc);
+ virtual TheISA::IntReg getSyscallArg(ThreadContext *tc, int i) = 0;
+ virtual void setSyscallArg(ThreadContext *tc,
+ int i, TheISA::IntReg val) = 0;
+ virtual void setSyscallReturn(ThreadContext *tc,
+ SyscallReturn return_value) = 0;
virtual SyscallDesc* getDesc(int callnum) = 0;
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
index 157d39e93..3c2a27f54 100644
--- a/src/sim/pseudo_inst.cc
+++ b/src/sim/pseudo_inst.cc
@@ -35,275 +35,291 @@
#include <fstream>
#include <string>
+#include "arch/kernel_stats.hh"
#include "arch/vtophys.hh"
-#include "base/annotate.hh"
+#include "base/debug.hh"
#include "cpu/base.hh"
#include "cpu/thread_context.hh"
#include "cpu/quiesce_event.hh"
-#include "arch/kernel_stats.hh"
+#include "params/BaseCPU.hh"
#include "sim/pseudo_inst.hh"
#include "sim/serialize.hh"
+#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/stat_control.hh"
#include "sim/stats.hh"
#include "sim/system.hh"
-#include "sim/debug.hh"
+#if FULL_SYSTEM
#include "sim/vptr.hh"
+#endif
using namespace std;
using namespace Stats;
using namespace TheISA;
-namespace PseudoInst
+namespace PseudoInst {
+
+#if FULL_SYSTEM
+
+void
+arm(ThreadContext *tc)
{
- void
- arm(ThreadContext *tc)
- {
- if (tc->getKernelStats())
- tc->getKernelStats()->arm();
- }
+ if (tc->getKernelStats())
+ tc->getKernelStats()->arm();
+}
- void
- quiesce(ThreadContext *tc)
- {
- if (!tc->getCpuPtr()->params->do_quiesce)
- return;
+void
+quiesce(ThreadContext *tc)
+{
+ if (!tc->getCpuPtr()->params()->do_quiesce)
+ return;
- DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name());
+ DPRINTF(Quiesce, "%s: quiesce()\n", tc->getCpuPtr()->name());
- tc->suspend();
- if (tc->getKernelStats())
- tc->getKernelStats()->quiesce();
- }
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+}
- void
- quiesceNs(ThreadContext *tc, uint64_t ns)
- {
- if (!tc->getCpuPtr()->params->do_quiesce || ns == 0)
- return;
+void
+quiesceNs(ThreadContext *tc, uint64_t ns)
+{
+ if (!tc->getCpuPtr()->params()->do_quiesce || ns == 0)
+ return;
- EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
- Tick resume = curTick + Clock::Int::ns * ns;
+ Tick resume = curTick + Clock::Int::ns * ns;
- quiesceEvent->reschedule(resume, true);
+ mainEventQueue.reschedule(quiesceEvent, resume, true);
- DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n",
- tc->getCpuPtr()->name(), ns, resume);
+ DPRINTF(Quiesce, "%s: quiesceNs(%d) until %d\n",
+ tc->getCpuPtr()->name(), ns, resume);
- tc->suspend();
- if (tc->getKernelStats())
- tc->getKernelStats()->quiesce();
- }
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+}
- void
- quiesceCycles(ThreadContext *tc, uint64_t cycles)
- {
- if (!tc->getCpuPtr()->params->do_quiesce || cycles == 0)
- return;
+void
+quiesceCycles(ThreadContext *tc, uint64_t cycles)
+{
+ if (!tc->getCpuPtr()->params()->do_quiesce || cycles == 0)
+ return;
- EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
- Tick resume = curTick + tc->getCpuPtr()->ticks(cycles);
+ Tick resume = curTick + tc->getCpuPtr()->ticks(cycles);
- quiesceEvent->reschedule(resume, true);
+ mainEventQueue.reschedule(quiesceEvent, resume, true);
- DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n",
- tc->getCpuPtr()->name(), cycles, resume);
+ DPRINTF(Quiesce, "%s: quiesceCycles(%d) until %d\n",
+ tc->getCpuPtr()->name(), cycles, resume);
- tc->suspend();
- if (tc->getKernelStats())
- tc->getKernelStats()->quiesce();
- }
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
+}
- uint64_t
- quiesceTime(ThreadContext *tc)
- {
- return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns;
- }
+uint64_t
+quiesceTime(ThreadContext *tc)
+{
+ return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns;
+}
- void
- m5exit_old(ThreadContext *tc)
- {
- exitSimLoop("m5_exit_old instruction encountered");
- }
+#endif
- void
- m5exit(ThreadContext *tc, Tick delay)
- {
- Tick when = curTick + delay * Clock::Int::ns;
- schedExitSimLoop("m5_exit instruction encountered", when);
- }
+uint64_t
+rpns(ThreadContext *tc)
+{
+ return curTick / Clock::Int::ns;
+}
+
+void
+wakeCPU(ThreadContext *tc, uint64_t cpuid)
+{
+ System *sys = tc->getSystemPtr();
+ ThreadContext *other_tc = sys->threadContexts[cpuid];
+ if (other_tc->status() == ThreadContext::Suspended)
+ other_tc->activate();
+}
- void
- loadsymbol(ThreadContext *tc)
- {
- const string &filename = tc->getCpuPtr()->system->params()->symbolfile;
- if (filename.empty()) {
- return;
- }
+void
+m5exit(ThreadContext *tc, Tick delay)
+{
+ Tick when = curTick + delay * Clock::Int::ns;
+ Event *event = new SimLoopExitEvent("m5_exit instruction encountered", 0);
+ mainEventQueue.schedule(event, when);
+}
+
+#if FULL_SYSTEM
+
+void
+loadsymbol(ThreadContext *tc)
+{
+ const string &filename = tc->getCpuPtr()->system->params()->symbolfile;
+ if (filename.empty()) {
+ return;
+ }
- std::string buffer;
- ifstream file(filename.c_str());
+ std::string buffer;
+ ifstream file(filename.c_str());
- if (!file)
- fatal("file error: Can't open symbol table file %s\n", filename);
+ if (!file)
+ fatal("file error: Can't open symbol table file %s\n", filename);
- while (!file.eof()) {
- getline(file, buffer);
+ while (!file.eof()) {
+ getline(file, buffer);
- if (buffer.empty())
- continue;
+ if (buffer.empty())
+ continue;
- int idx = buffer.find(' ');
- if (idx == string::npos)
- continue;
+ int idx = buffer.find(' ');
+ if (idx == string::npos)
+ continue;
- string address = "0x" + buffer.substr(0, idx);
- eat_white(address);
- if (address.empty())
- continue;
+ string address = "0x" + buffer.substr(0, idx);
+ eat_white(address);
+ if (address.empty())
+ continue;
- // Skip over letter and space
- string symbol = buffer.substr(idx + 3);
- eat_white(symbol);
- if (symbol.empty())
- continue;
+ // Skip over letter and space
+ string symbol = buffer.substr(idx + 3);
+ eat_white(symbol);
+ if (symbol.empty())
+ continue;
- Addr addr;
- if (!to_number(address, addr))
- continue;
+ Addr addr;
+ if (!to_number(address, addr))
+ continue;
- if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
- continue;
+ if (!tc->getSystemPtr()->kernelSymtab->insert(addr, symbol))
+ continue;
- DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
- }
- file.close();
+ DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
}
+ file.close();
+}
- void
- resetstats(ThreadContext *tc, Tick delay, Tick period)
- {
- if (!tc->getCpuPtr()->params->do_statistics_insts)
- return;
+void
+addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
+{
+ char symb[100];
+ CopyStringOut(tc, symb, symbolAddr, 100);
+ std::string symbol(symb);
+ DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
- Tick when = curTick + delay * Clock::Int::ns;
- Tick repeat = period * Clock::Int::ns;
+ tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
+ debugSymbolTable->insert(addr,symbol);
+}
- Stats::StatEvent(false, true, when, repeat);
- }
+#endif
- void
- dumpstats(ThreadContext *tc, Tick delay, Tick period)
- {
- if (!tc->getCpuPtr()->params->do_statistics_insts)
- return;
+void
+resetstats(ThreadContext *tc, Tick delay, Tick period)
+{
+ if (!tc->getCpuPtr()->params()->do_statistics_insts)
+ return;
- Tick when = curTick + delay * Clock::Int::ns;
- Tick repeat = period * Clock::Int::ns;
- Stats::StatEvent(true, false, when, repeat);
- }
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
- void
- addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
- {
- char symb[100];
- CopyStringOut(tc, symb, symbolAddr, 100);
- std::string symbol(symb);
+ Stats::StatEvent(false, true, when, repeat);
+}
- DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
+void
+dumpstats(ThreadContext *tc, Tick delay, Tick period)
+{
+ if (!tc->getCpuPtr()->params()->do_statistics_insts)
+ return;
- tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
- }
- void
- anBegin(ThreadContext *tc, uint64_t cur)
- {
- Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur &
- 0xFFFFFFFF, 0,0);
- }
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
- void
- anWait(ThreadContext *tc, uint64_t cur, uint64_t wait)
- {
- Annotate::annotations.add(tc->getSystemPtr(), 0, cur >> 32, cur &
- 0xFFFFFFFF, wait >> 32, wait & 0xFFFFFFFF);
- }
+ Stats::StatEvent(true, false, when, repeat);
+}
+void
+dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
+{
+ if (!tc->getCpuPtr()->params()->do_statistics_insts)
+ return;
- void
- dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
- {
- if (!tc->getCpuPtr()->params->do_statistics_insts)
- return;
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
- Tick when = curTick + delay * Clock::Int::ns;
- Tick repeat = period * Clock::Int::ns;
+ Stats::StatEvent(true, true, when, repeat);
+}
- Stats::StatEvent(true, true, when, repeat);
- }
+void
+m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
+{
+ if (!tc->getCpuPtr()->params()->do_checkpoint_insts)
+ return;
- void
- m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
- {
- if (!tc->getCpuPtr()->params->do_checkpoint_insts)
- return;
+ Tick when = curTick + delay * Clock::Int::ns;
+ Tick repeat = period * Clock::Int::ns;
- Tick when = curTick + delay * Clock::Int::ns;
- Tick repeat = period * Clock::Int::ns;
+ Event *event = new SimLoopExitEvent("checkpoint", 0, repeat);
+ mainEventQueue.schedule(event, when);
+}
- schedExitSimLoop("checkpoint", when, repeat);
- }
+#if FULL_SYSTEM
- uint64_t
- readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
- {
- const string &file = tc->getSystemPtr()->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(tc, vaddr, buf, result);
- delete [] buf;
- return result;
+uint64_t
+readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
+{
+ const string &file = tc->getSystemPtr()->params()->readfile;
+ if (file.empty()) {
+ return ULL(0);
}
- void debugbreak(ThreadContext *tc)
- {
- debug_break();
- }
+ uint64_t result = 0;
- void switchcpu(ThreadContext *tc)
- {
- exitSimLoop("switchcpu");
+ 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(tc, vaddr, buf, result);
+ delete [] buf;
+ return result;
}
+
+#endif
+
+void
+debugbreak(ThreadContext *tc)
+{
+ debug_break();
+}
+
+void
+switchcpu(ThreadContext *tc)
+{
+ exitSimLoop("switchcpu");
+}
+
+/* namespace PseudoInst */ }
diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh
index 93021abad..30996fc3b 100644
--- a/src/sim/pseudo_inst.hh
+++ b/src/sim/pseudo_inst.hh
@@ -33,31 +33,35 @@ class ThreadContext;
//We need the "Tick" and "Addr" data types from here
#include "sim/host.hh"
-namespace PseudoInst
-{
- /**
- * @todo these externs are only here for a hack in fullCPU::takeOver...
- */
- extern bool doStatisticsInsts;
- extern bool doCheckpointInsts;
- extern bool doQuiesce;
+namespace PseudoInst {
- void arm(ThreadContext *tc);
- void quiesce(ThreadContext *tc);
- void quiesceNs(ThreadContext *tc, uint64_t ns);
- void quiesceCycles(ThreadContext *tc, uint64_t cycles);
- uint64_t quiesceTime(ThreadContext *tc);
- void m5exit(ThreadContext *tc, Tick delay);
- void m5exit_old(ThreadContext *tc);
- void loadsymbol(ThreadContext *xc);
- void resetstats(ThreadContext *tc, Tick delay, Tick period);
- void dumpstats(ThreadContext *tc, Tick delay, Tick period);
- void dumpresetstats(ThreadContext *tc, Tick delay, Tick period);
- void m5checkpoint(ThreadContext *tc, Tick delay, Tick period);
- uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset);
- void debugbreak(ThreadContext *tc);
- void switchcpu(ThreadContext *tc);
- void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
- void anBegin(ThreadContext *tc, uint64_t cur);
- void anWait(ThreadContext *tc, uint64_t cur, uint64_t wait);
-}
+/**
+ * @todo these externs are only here for a hack in fullCPU::takeOver...
+ */
+extern bool doStatisticsInsts;
+extern bool doCheckpointInsts;
+extern bool doQuiesce;
+
+#if FULL_SYSTEM
+void arm(ThreadContext *tc);
+void quiesce(ThreadContext *tc);
+void quiesceNs(ThreadContext *tc, uint64_t ns);
+void quiesceCycles(ThreadContext *tc, uint64_t cycles);
+uint64_t quiesceTime(ThreadContext *tc);
+uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len,
+ uint64_t offset);
+void loadsymbol(ThreadContext *xc);
+void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
+#endif
+
+uint64_t rpns(ThreadContext *tc);
+void wakeCPU(ThreadContext *tc, uint64_t cpuid);
+void m5exit(ThreadContext *tc, Tick delay);
+void resetstats(ThreadContext *tc, Tick delay, Tick period);
+void dumpstats(ThreadContext *tc, Tick delay, Tick period);
+void dumpresetstats(ThreadContext *tc, Tick delay, Tick period);
+void m5checkpoint(ThreadContext *tc, Tick delay, Tick period);
+void debugbreak(ThreadContext *tc);
+void switchcpu(ThreadContext *tc);
+
+/* namespace PseudoInst */ }
diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc
index a0d17f489..481b9af3b 100644
--- a/src/sim/serialize.cc
+++ b/src/sim/serialize.cc
@@ -321,23 +321,23 @@ objParamIn(Checkpoint *cp, const std::string &section,
}
-#define INSTANTIATE_PARAM_TEMPLATES(type) \
-template void \
-paramOut(ostream &os, const std::string &name, type const &param); \
-template void \
-paramIn(Checkpoint *cp, const std::string &section, \
- const std::string &name, type & param); \
-template void \
-arrayParamOut(ostream &os, const std::string &name, \
- type const *param, int size); \
-template void \
-arrayParamIn(Checkpoint *cp, const std::string &section, \
+#define INSTANTIATE_PARAM_TEMPLATES(type) \
+template void \
+paramOut(ostream &os, const std::string &name, type const &param); \
+template void \
+paramIn(Checkpoint *cp, const std::string &section, \
+ const std::string &name, type & param); \
+template void \
+arrayParamOut(ostream &os, const std::string &name, \
+ type const *param, int size); \
+template void \
+arrayParamIn(Checkpoint *cp, const std::string &section, \
const std::string &name, type *param, int size); \
-template void \
-arrayParamOut(ostream &os, const std::string &name, \
- const std::vector<type> &param); \
-template void \
-arrayParamIn(Checkpoint *cp, const std::string &section, \
+template void \
+arrayParamOut(ostream &os, const std::string &name, \
+ const std::vector<type> &param); \
+template void \
+arrayParamIn(Checkpoint *cp, const std::string &section, \
const std::string &name, std::vector<type> &param);
INSTANTIATE_PARAM_TEMPLATES(signed char)
@@ -351,6 +351,8 @@ INSTANTIATE_PARAM_TEMPLATES(unsigned long)
INSTANTIATE_PARAM_TEMPLATES(signed long long)
INSTANTIATE_PARAM_TEMPLATES(unsigned long long)
INSTANTIATE_PARAM_TEMPLATES(bool)
+INSTANTIATE_PARAM_TEMPLATES(float)
+INSTANTIATE_PARAM_TEMPLATES(double)
INSTANTIATE_PARAM_TEMPLATES(string)
@@ -394,6 +396,24 @@ Globals::unserialize(Checkpoint *cp)
mainEventQueue.unserialize(cp, "MainEventQueue");
}
+Serializable::Serializable()
+{
+}
+
+Serializable::~Serializable()
+{
+}
+
+void
+Serializable::serialize(std::ostream &os)
+{
+}
+
+void
+Serializable::unserialize(Checkpoint *cp, const std::string &section)
+{
+}
+
void
Serializable::serializeAll(const std::string &cpt_dir)
{
@@ -405,6 +425,8 @@ Serializable::serializeAll(const std::string &cpt_dir)
string cpt_file = dir + Checkpoint::baseFilename;
ofstream outstream(cpt_file.c_str());
time_t t = time(NULL);
+ if (!outstream.is_open())
+ fatal("Unable to open file %s for writing\n", cpt_file.c_str());
outstream << "// checkpoint generated: " << ctime(&t);
globals.serialize(outstream);
diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh
index e72eedb30..c33633065 100644
--- a/src/sim/serialize.hh
+++ b/src/sim/serialize.hh
@@ -82,33 +82,33 @@ objParamIn(Checkpoint *cp, const std::string &section,
// These macros are streamlined to use in serialize/unserialize
// functions. It's assumed that serialize() has a parameter 'os' for
// the ostream, and unserialize() has parameters 'cp' and 'section'.
-#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar)
+#define SERIALIZE_SCALAR(scalar) paramOut(os, #scalar, scalar)
-#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar)
+#define UNSERIALIZE_SCALAR(scalar) paramIn(cp, section, #scalar, scalar)
// ENUMs are like SCALARs, but we cast them to ints on the way out
-#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar)
+#define SERIALIZE_ENUM(scalar) paramOut(os, #scalar, (int)scalar)
-#define UNSERIALIZE_ENUM(scalar) \
- do { \
- int tmp; \
- paramIn(cp, section, #scalar, tmp); \
- scalar = (typeof(scalar))tmp; \
+#define UNSERIALIZE_ENUM(scalar) \
+ do { \
+ int tmp; \
+ paramIn(cp, section, #scalar, tmp); \
+ scalar = (typeof(scalar))tmp; \
} while (0)
-#define SERIALIZE_ARRAY(member, size) \
+#define SERIALIZE_ARRAY(member, size) \
arrayParamOut(os, #member, member, size)
-#define UNSERIALIZE_ARRAY(member, size) \
+#define UNSERIALIZE_ARRAY(member, size) \
arrayParamIn(cp, section, #member, member, size)
-#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name())
+#define SERIALIZE_OBJPTR(objptr) paramOut(os, #objptr, (objptr)->name())
-#define UNSERIALIZE_OBJPTR(objptr) \
- do { \
- SimObject *sptr; \
- objParamIn(cp, section, #objptr, sptr); \
- objptr = dynamic_cast<typeof(objptr)>(sptr); \
+#define UNSERIALIZE_OBJPTR(objptr) \
+ do { \
+ SimObject *sptr; \
+ objParamIn(cp, section, #objptr, sptr); \
+ objptr = dynamic_cast<typeof(objptr)>(sptr); \
} while (0)
/*
@@ -121,17 +121,16 @@ class Serializable
void nameOut(std::ostream &os, const std::string &_name);
public:
- Serializable() {}
- virtual ~Serializable() {}
+ Serializable();
+ virtual ~Serializable();
// manditory virtual function, so objects must provide names
virtual const std::string name() const = 0;
- virtual void serialize(std::ostream &os) {}
- virtual void unserialize(Checkpoint *cp, const std::string &section) {}
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
- static Serializable *create(Checkpoint *cp,
- const std::string &section);
+ static Serializable *create(Checkpoint *cp, const std::string &section);
static int ckptCount;
static int ckptMaxCount;
@@ -211,8 +210,8 @@ class SerializableClass
// SerializableBuilder and SerializableClass objects
//
-#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
-SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
+#define REGISTER_SERIALIZEABLE(CLASS_NAME, OBJ_CLASS) \
+SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
OBJ_CLASS::createForUnserialize);
void
diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc
index 09087ef84..a6e3f0af3 100644
--- a/src/sim/sim_events.cc
+++ b/src/sim/sim_events.cc
@@ -40,6 +40,13 @@
using namespace std;
+SimLoopExitEvent::SimLoopExitEvent(const std::string &_cause, int c, Tick r)
+ : Event(Sim_Exit_Pri), cause(_cause), code(c), repeat(r)
+{
+ setFlags(IsExitEvent);
+}
+
+
//
// handle termination event
//
@@ -49,7 +56,7 @@ SimLoopExitEvent::process()
// if this got scheduled on a different queue (e.g. the committed
// instruction queue) then make a corresponding event on the main
// queue.
- if (theQueue() != &mainEventQueue) {
+ if (!getFlags(IsMainQueue)) {
exitSimLoop(cause, code);
delete this;
}
@@ -59,7 +66,8 @@ SimLoopExitEvent::process()
// but if you are doing this on intervals, don't forget to make another
if (repeat) {
- schedule(curTick + repeat);
+ assert(getFlags(IsMainQueue));
+ mainEventQueue.schedule(this, curTick + repeat);
}
}
@@ -70,43 +78,32 @@ SimLoopExitEvent::description() const
return "simulation loop exit";
}
-SimLoopExitEvent *
-schedExitSimLoop(const std::string &message, Tick when, Tick repeat,
- EventQueue *q, int exit_code)
-{
- if (q == NULL)
- q = &mainEventQueue;
-
- return new SimLoopExitEvent(q, when, repeat, message, exit_code);
-}
-
void
exitSimLoop(const std::string &message, int exit_code)
{
- schedExitSimLoop(message, curTick, 0, NULL, exit_code);
+ Event *event = new SimLoopExitEvent(message, exit_code);
+ mainEventQueue.schedule(event, curTick);
}
+CountedDrainEvent::CountedDrainEvent()
+ : SimLoopExitEvent("Finished drain", 0), count(0)
+{ }
+
void
CountedDrainEvent::process()
{
- if (--count == 0) {
- exitSimLoop("Finished drain");
- }
+ if (--count == 0)
+ exitSimLoop(cause, code);
}
//
// constructor: automatically schedules at specified time
//
-CountedExitEvent::CountedExitEvent(EventQueue *q, const std::string &_cause,
- Tick _when, int &_downCounter)
- : Event(q, Sim_Exit_Pri),
- cause(_cause),
- downCounter(_downCounter)
+CountedExitEvent::CountedExitEvent(const std::string &_cause, int &counter)
+ : Event(Sim_Exit_Pri), cause(_cause), downCounter(counter)
{
// catch stupid mistakes
assert(downCounter > 0);
-
- schedule(_when);
}
@@ -128,9 +125,11 @@ CountedExitEvent::description() const
return "counted exit";
}
-#ifdef CHECK_SWAP_CYCLES
-new CheckSwapEvent(&mainEventQueue, CHECK_SWAP_CYCLES);
-#endif
+CheckSwapEvent::CheckSwapEvent(int ival)
+ : interval(ival)
+{
+ mainEventQueue.schedule(this, curTick + interval);
+}
void
CheckSwapEvent::process()
@@ -149,7 +148,8 @@ CheckSwapEvent::process()
exitSimLoop("Lack of swap space");
}
- schedule(curTick + interval);
+ assert(getFlags(IsMainQueue));
+ mainEventQueue.schedule(this, curTick + interval);
}
const char *
diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh
index 58ec963c0..ffd31f385 100644
--- a/src/sim/sim_events.hh
+++ b/src/sim/sim_events.hh
@@ -38,35 +38,19 @@
//
class SimLoopExitEvent : public Event
{
- private:
+ protected:
// string explaining why we're terminating
std::string cause;
int code;
Tick repeat;
public:
- // Default constructor. Only really used for derived classes.
- SimLoopExitEvent()
- : Event(&mainEventQueue, Sim_Exit_Pri)
- { }
-
- SimLoopExitEvent(EventQueue *q,
- Tick _when, Tick _repeat, const std::string &_cause,
- int c = 0)
- : Event(q, Sim_Exit_Pri), cause(_cause),
- code(c), repeat(_repeat)
- { setFlags(IsExitEvent); schedule(_when); }
-
-// SimLoopExitEvent(EventQueue *q,
-// Tick _when, const std::string &_cause,
-// Tick _repeat = 0, int c = 0)
-// : Event(q, Sim_Exit_Pri), cause(_cause), code(c), repeat(_repeat)
-// { setFlags(IsExitEvent); schedule(_when); }
+ SimLoopExitEvent(const std::string &_cause, int c, Tick repeat = 0);
std::string getCause() { return cause; }
int getCode() { return code; }
- void process(); // process event
+ void process(); // process event
virtual const char *description() const;
};
@@ -76,10 +60,10 @@ class CountedDrainEvent : public SimLoopExitEvent
private:
// Count of how many objects have not yet drained
int count;
+
public:
- CountedDrainEvent()
- : count(0)
- { }
+ CountedDrainEvent();
+
void process();
void setCount(int _count) { count = _count; }
@@ -95,14 +79,13 @@ class CountedDrainEvent : public SimLoopExitEvent
class CountedExitEvent : public Event
{
private:
- std::string cause; // string explaining why we're terminating
- int &downCounter; // decrement & terminate if zero
+ std::string cause; // string explaining why we're terminating
+ int &downCounter; // decrement & terminate if zero
public:
- CountedExitEvent(EventQueue *q, const std::string &_cause,
- Tick _when, int &_downCounter);
+ CountedExitEvent(const std::string &_cause, int &_downCounter);
- void process(); // process event
+ void process(); // process event
virtual const char *description() const;
};
@@ -116,11 +99,8 @@ class CheckSwapEvent : public Event
int interval;
public:
- CheckSwapEvent(EventQueue *q, int ival)
- : Event(q), interval(ival)
- { schedule(curTick + interval); }
-
- void process(); // process event
+ CheckSwapEvent(int ival);
+ void process(); // process event
virtual const char *description() const;
};
diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh
index d4b31d1ea..174b00024 100644
--- a/src/sim/sim_exit.hh
+++ b/src/sim/sim_exit.hh
@@ -46,14 +46,6 @@ class SimLoopExitEvent;
void registerExitCallback(Callback *);
/// Schedule an event to exit the simulation loop (returning to
-/// Python) at the indicated tick. The message and exit_code
-/// parameters are saved in the SimLoopExitEvent to indicate why the
-/// exit occurred.
-SimLoopExitEvent *schedExitSimLoop(const std::string &message, Tick when,
- Tick repeat = 0, EventQueue *q = NULL,
- int exit_code = 0);
-
-/// Schedule an event to exit the simulation loop (returning to
/// Python) at the end of the current cycle (curTick). The message
/// and exit_code parameters are saved in the SimLoopExitEvent to
/// indicate why the exit occurred.
diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc
index a835aee5b..dad8f6e8b 100644
--- a/src/sim/sim_object.cc
+++ b/src/sim/sim_object.cc
@@ -59,7 +59,7 @@ SimObject::SimObjectList SimObject::simObjectList;
// SimObject constructor: used to maintain static simObjectList
//
SimObject::SimObject(const Params *p)
- : _params(p)
+ : EventManager(p->eventq), _params(p)
{
#ifdef DEBUG
doDebugBreak = false;
@@ -69,14 +69,6 @@ SimObject::SimObject(const Params *p)
state = Running;
}
-SimObjectParams *
-SimObject::makeParams(const std::string &name)
-{
- SimObjectParams *params = new SimObjectParams;
- params->name = name;
- return params;
-}
-
void
SimObject::init()
{
diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh
index ec565ce82..d6d08f255 100644
--- a/src/sim/sim_object.hh
+++ b/src/sim/sim_object.hh
@@ -36,12 +36,14 @@
#ifndef __SIM_OBJECT_HH__
#define __SIM_OBJECT_HH__
-#include <map>
+#include <iostream>
#include <list>
+#include <map>
+#include <string>
#include <vector>
-#include <iostream>
#include "params/SimObject.hh"
+#include "sim/eventq.hh"
#include "sim/serialize.hh"
#include "sim/startup.hh"
@@ -53,7 +55,8 @@ class Event;
* correspond to physical components and can be specified via the
* config file (CPUs, caches, etc.).
*/
-class SimObject : public Serializable, protected StartupCallback
+class SimObject
+ : public EventManager, public Serializable, protected StartupCallback
{
public:
enum State {
@@ -86,10 +89,6 @@ class SimObject : public Serializable, protected StartupCallback
SimObject(const Params *_params);
virtual ~SimObject() {}
- protected:
- // static: support for old-style constructors (call manually)
- static Params *makeParams(const std::string &name);
-
public:
virtual const std::string name() const { return params()->name; }
diff --git a/src/sim/sim_object_params.hh b/src/sim/sim_object_params.hh
new file mode 100644
index 000000000..750181135
--- /dev/null
+++ b/src/sim/sim_object_params.hh
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ *
+ * Authors: Steve Reinhardt
+ * Nathan Binkert
+ */
+
+#ifndef __SIM_SIM_OBJECT_PARAMS_HH__
+#define __SIM_SIM_OBJECT_PARAMS_HH__
+
+#ifndef PY_VERSION
+struct PyObject;
+#endif
+
+#include <string>
+
+struct EventQueue;
+
+struct SimObjectParams
+{
+ SimObjectParams()
+ {
+ extern EventQueue mainEventQueue;
+ eventq = &mainEventQueue;
+ }
+ virtual ~SimObjectParams() {}
+
+ std::string name;
+ PyObject *pyobj;
+ EventQueue *eventq;
+};
+
+
+#endif // __SIM_SIM_OBJECT_PARAMS_HH__
diff --git a/src/sim/simulate.cc b/src/sim/simulate.cc
index 36bdff45e..1ac2c80df 100644
--- a/src/sim/simulate.cc
+++ b/src/sim/simulate.cc
@@ -47,7 +47,7 @@
SimLoopExitEvent *
simulate(Tick num_cycles)
{
- warn("Entering event queue @ %d. Starting simulation...\n", curTick);
+ inform("Entering event queue @ %d. Starting simulation...\n", curTick);
if (num_cycles < 0)
fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
@@ -56,8 +56,9 @@ simulate(Tick num_cycles)
else
num_cycles = curTick + num_cycles;
- Event *limit_event;
- limit_event = schedExitSimLoop("simulate() limit reached", num_cycles);
+ Event *limit_event =
+ new SimLoopExitEvent("simulate() limit reached", 0);
+ mainEventQueue.schedule(limit_event, num_cycles);
while (1) {
// there should always be at least one event (the SimLoopExitEvent
@@ -82,8 +83,8 @@ simulate(Tick num_cycles)
// if we didn't hit limit_event, delete it
if (se_event != limit_event) {
assert(limit_event->scheduled());
- limit_event->deschedule();
- delete limit_event;
+ limit_event->squash();
+ hack_once("be nice to actually delete the event here");
}
return se_event;
diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc
index 228c83898..2dcf4798d 100644
--- a/src/sim/stat_control.cc
+++ b/src/sim/stat_control.cc
@@ -44,14 +44,6 @@
using namespace std;
-Stats::Formula hostInstRate;
-Stats::Formula hostTickRate;
-Stats::Value hostMemory;
-Stats::Value hostSeconds;
-
-Stats::Value simTicks;
-Stats::Value simInsts;
-Stats::Value simFreq;
Stats::Formula simSeconds;
namespace Stats {
@@ -84,8 +76,21 @@ statElapsedTicks()
SimTicksReset simTicksReset;
-void
-initSimStats()
+struct Global
+{
+ Stats::Formula hostInstRate;
+ Stats::Formula hostTickRate;
+ Stats::Value hostMemory;
+ Stats::Value hostSeconds;
+
+ Stats::Value simTicks;
+ Stats::Value simInsts;
+ Stats::Value simFreq;
+
+ Global();
+};
+
+Global::Global()
{
simInsts
.functor(BaseCPU::numSimulatedInstructions)
@@ -146,6 +151,12 @@ initSimStats()
registerResetCallback(&simTicksReset);
}
+void
+initSimStats()
+{
+ static Global global;
+}
+
class _StatEvent : public Event
{
private:
@@ -154,12 +165,10 @@ class _StatEvent : public Event
Tick repeat;
public:
- _StatEvent(bool _dump, bool _reset, Tick _when, Tick _repeat)
- : Event(&mainEventQueue, Stat_Event_Pri), dump(_dump), reset(_reset),
- repeat(_repeat)
+ _StatEvent(bool _dump, bool _reset, Tick _repeat)
+ : Event(Stat_Event_Pri), dump(_dump), reset(_reset), repeat(_repeat)
{
setFlags(AutoDelete);
- schedule(_when);
}
virtual void
@@ -171,15 +180,18 @@ class _StatEvent : public Event
if (reset)
Stats::reset();
- if (repeat)
- new _StatEvent(dump, reset, curTick + repeat, repeat);
+ if (repeat) {
+ Event *event = new _StatEvent(dump, reset, repeat);
+ mainEventQueue.schedule(event, curTick + repeat);
+ }
}
};
void
StatEvent(bool dump, bool reset, Tick when, Tick repeat)
{
- new _StatEvent(dump, reset, when, repeat);
+ Event *event = new _StatEvent(dump, reset, repeat);
+ mainEventQueue.schedule(event, when);
}
/* namespace Stats */ }
diff --git a/src/sim/stats.hh b/src/sim/stats.hh
index 97251283d..481c36cf6 100644
--- a/src/sim/stats.hh
+++ b/src/sim/stats.hh
@@ -34,6 +34,5 @@
#include "base/statistics.hh"
extern Stats::Formula simSeconds;
-extern Stats::Value simTicks;
#endif // __SIM_SIM_STATS_HH__
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index f4b9b7ae3..5fe30c269 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -53,8 +53,8 @@ SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
{
DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
curTick,tc->getCpuPtr()->name(), name,
- tc->getSyscallArg(0),tc->getSyscallArg(1),
- tc->getSyscallArg(2),tc->getSyscallArg(3));
+ process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1),
+ process->getSyscallArg(tc, 2), process->getSyscallArg(tc, 3));
SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
@@ -62,7 +62,7 @@ SyscallDesc::doSyscall(int callnum, LiveProcess *process, ThreadContext *tc)
curTick,tc->getCpuPtr()->name(), name, retval.value());
if (!(flags & SyscallDesc::SuppressReturnValue))
- tc->setSyscallReturn(retval);
+ process->setSyscallReturn(tc, retval);
}
@@ -81,7 +81,7 @@ ignoreFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
warn("ignoring syscall %s(%d, %d, ...)", desc->name,
- tc->getSyscallArg(0), tc->getSyscallArg(1));
+ process->getSyscallArg(tc, 0), process->getSyscallArg(tc, 1));
return 0;
}
@@ -92,7 +92,8 @@ exitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
if (tc->exit()) {
- exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
+ exitSimLoop("target called exit()",
+ process->getSyscallArg(tc, 0) & 0xff);
}
return 1;
@@ -107,21 +108,27 @@ getpagesizeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
-obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+brkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- Addr junk;
-
// change brk addr to first arg
- Addr new_brk = tc->getSyscallArg(0);
- if (new_brk != 0) {
+ Addr new_brk = p->getSyscallArg(tc, 0);
+
+ // in Linux at least, brk(0) returns the current break value
+ // (note that the syscall and the glibc function have different behavior)
+ if (new_brk == 0)
+ return p->brk_point;
+
+ if (new_brk > p->brk_point) {
+ // might need to allocate some new pages
for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
VMPageSize); !gen.done(); gen.next()) {
- if (!p->pTable->translate(gen.addr(), junk))
+ if (!p->pTable->translate(gen.addr()))
p->pTable->allocate(roundDown(gen.addr(), VMPageSize),
VMPageSize);
}
- p->brk_point = new_brk;
}
+
+ p->brk_point = new_brk;
DPRINTF(SyscallVerbose, "Break Point changed to: %#X\n", p->brk_point);
return p->brk_point;
}
@@ -130,7 +137,7 @@ obreakFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int target_fd = tc->getSyscallArg(0);
+ int target_fd = p->getSyscallArg(tc, 0);
int status = close(p->sim_fd(target_fd));
if (status >= 0)
p->free_fd(target_fd);
@@ -141,9 +148,9 @@ closeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int fd = p->sim_fd(tc->getSyscallArg(0));
- int nbytes = tc->getSyscallArg(2);
- BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+ int fd = p->sim_fd(p->getSyscallArg(tc, 0));
+ int nbytes = p->getSyscallArg(tc, 2);
+ BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes);
int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
@@ -156,9 +163,9 @@ readFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int fd = p->sim_fd(tc->getSyscallArg(0));
- int nbytes = tc->getSyscallArg(2);
- BufferArg bufArg(tc->getSyscallArg(1), nbytes);
+ int fd = p->sim_fd(p->getSyscallArg(tc, 0));
+ int nbytes = p->getSyscallArg(tc, 2);
+ BufferArg bufArg(p->getSyscallArg(tc, 1), nbytes);
bufArg.copyIn(tc->getMemPort());
@@ -173,9 +180,9 @@ writeFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int fd = p->sim_fd(tc->getSyscallArg(0));
- uint64_t offs = tc->getSyscallArg(1);
- int whence = tc->getSyscallArg(2);
+ int fd = p->sim_fd(p->getSyscallArg(tc, 0));
+ uint64_t offs = p->getSyscallArg(tc, 1);
+ int whence = p->getSyscallArg(tc, 2);
off_t result = lseek(fd, offs, whence);
@@ -186,11 +193,11 @@ lseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
_llseekFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int fd = p->sim_fd(tc->getSyscallArg(0));
- uint64_t offset_high = tc->getSyscallArg(1);
- uint32_t offset_low = tc->getSyscallArg(2);
- Addr result_ptr = tc->getSyscallArg(3);
- int whence = tc->getSyscallArg(4);
+ int fd = p->sim_fd(p->getSyscallArg(tc, 0));
+ uint64_t offset_high = p->getSyscallArg(tc, 1);
+ uint32_t offset_low = p->getSyscallArg(tc, 2);
+ Addr result_ptr = p->getSyscallArg(tc, 3);
+ int whence = p->getSyscallArg(tc, 4);
uint64_t offset = (offset_high << 32) | offset_low;
@@ -229,8 +236,8 @@ const char *hostname = "m5.eecs.umich.edu";
SyscallReturn
gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- int name_len = tc->getSyscallArg(1);
- BufferArg name(tc->getSyscallArg(0), name_len);
+ int name_len = p->getSyscallArg(tc, 1);
+ BufferArg name(p->getSyscallArg(tc, 0), name_len);
strncpy((char *)name.bufferPtr(), hostname, name_len);
@@ -240,11 +247,64 @@ gethostnameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
}
SyscallReturn
+getcwdFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ int result = 0;
+ unsigned long size = p->getSyscallArg(tc, 1);
+ BufferArg buf(p->getSyscallArg(tc, 0), size);
+
+ // Is current working directory defined?
+ string cwd = p->getcwd();
+ if (!cwd.empty()) {
+ if (cwd.length() >= size) {
+ // Buffer too small
+ return -ERANGE;
+ }
+ strncpy((char *)buf.bufferPtr(), cwd.c_str(), size);
+ result = cwd.length();
+ }
+ else {
+ if (getcwd((char *)buf.bufferPtr(), size) != NULL) {
+ result = strlen((char *)buf.bufferPtr());
+ }
+ else {
+ result = -1;
+ }
+ }
+
+ buf.copyOut(tc->getMemPort());
+
+ return (result == -1) ? -errno : result;
+}
+
+
+SyscallReturn
+readlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+ return (TheISA::IntReg)-EFAULT;
+
+ // Adjust path for current working directory
+ path = p->fullPath(path);
+
+ size_t bufsiz = p->getSyscallArg(tc, 2);
+ BufferArg buf(p->getSyscallArg(tc, 1), bufsiz);
+
+ int result = readlink(path.c_str(), (char *)buf.bufferPtr(), bufsiz);
+
+ buf.copyOut(tc->getMemPort());
+
+ return (result == -1) ? -errno : result;
+}
+
+SyscallReturn
unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
return (TheISA::IntReg)-EFAULT;
// Adjust path for current working directory
@@ -254,17 +314,35 @@ unlinkFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
return (result == -1) ? -errno : result;
}
+
+SyscallReturn
+mkdirFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
+{
+ string path;
+
+ if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
+ return (TheISA::IntReg)-EFAULT;
+
+ // Adjust path for current working directory
+ path = p->fullPath(path);
+
+ mode_t mode = p->getSyscallArg(tc, 1);
+
+ int result = mkdir(path.c_str(), mode);
+ return (result == -1) ? -errno : result;
+}
+
SyscallReturn
renameFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
string old_name;
- if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(old_name, p->getSyscallArg(tc, 0)))
return -EFAULT;
string new_name;
- if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
+ if (!tc->getMemPort()->tryReadString(new_name, p->getSyscallArg(tc, 1)))
return -EFAULT;
// Adjust path for current working directory
@@ -280,10 +358,10 @@ truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
return -EFAULT;
- off_t length = tc->getSyscallArg(1);
+ off_t length = p->getSyscallArg(tc, 1);
// Adjust path for current working directory
path = p->fullPath(path);
@@ -295,29 +373,40 @@ truncateFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
ftruncateFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
if (fd < 0)
return -EBADF;
- off_t length = tc->getSyscallArg(1);
+ off_t length = process->getSyscallArg(tc, 1);
int result = ftruncate(fd, length);
return (result == -1) ? -errno : result;
}
SyscallReturn
+umaskFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
+{
+ // Letting the simulated program change the simulator's umask seems like
+ // a bad idea. Compromise by just returning the current umask but not
+ // changing anything.
+ mode_t oldMask = umask(0);
+ umask(oldMask);
+ return (int)oldMask;
+}
+
+SyscallReturn
chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, p->getSyscallArg(tc, 0)))
return -EFAULT;
/* XXX endianess */
- uint32_t owner = tc->getSyscallArg(1);
+ uint32_t owner = p->getSyscallArg(tc, 1);
uid_t hostOwner = owner;
- uint32_t group = tc->getSyscallArg(2);
+ uint32_t group = p->getSyscallArg(tc, 2);
gid_t hostGroup = group;
// Adjust path for current working directory
@@ -330,15 +419,15 @@ chownFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
SyscallReturn
fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
if (fd < 0)
return -EBADF;
/* XXX endianess */
- uint32_t owner = tc->getSyscallArg(1);
+ uint32_t owner = process->getSyscallArg(tc, 1);
uid_t hostOwner = owner;
- uint32_t group = tc->getSyscallArg(2);
+ uint32_t group = process->getSyscallArg(tc, 2);
gid_t hostGroup = group;
int result = fchown(fd, hostOwner, hostGroup);
@@ -349,11 +438,11 @@ fchownFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
SyscallReturn
dupFunc(SyscallDesc *desc, int num, LiveProcess *process, ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
if (fd < 0)
return -EBADF;
- Process::FdMap *fdo = process->sim_fd_obj(tc->getSyscallArg(0));
+ Process::FdMap *fdo = process->sim_fd_obj(process->getSyscallArg(tc, 0));
int result = dup(fd);
return (result == -1) ? -errno : process->alloc_fd(result, fdo->filename, fdo->flags, fdo->mode, false);
@@ -364,12 +453,12 @@ SyscallReturn
fcntlFunc(SyscallDesc *desc, int num, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int fd = process->getSyscallArg(tc, 0);
if (fd < 0 || process->sim_fd(fd) < 0)
return -EBADF;
- int cmd = tc->getSyscallArg(1);
+ int cmd = process->getSyscallArg(tc, 1);
switch (cmd) {
case 0: // F_DUPFD
// if we really wanted to support this, we'd need to do it
@@ -406,12 +495,12 @@ SyscallReturn
fcntl64Func(SyscallDesc *desc, int num, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int fd = process->getSyscallArg(tc, 0);
if (fd < 0 || process->sim_fd(fd) < 0)
return -EBADF;
- int cmd = tc->getSyscallArg(1);
+ int cmd = process->getSyscallArg(tc, 1);
switch (cmd) {
case 33: //F_GETLK64
warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
@@ -476,7 +565,7 @@ getuidPseudoFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
// EUID goes in r20.
tc->setIntReg(SyscallPseudoReturnReg, process->euid()); //EUID
- return process->uid(); // UID
+ return process->uid(); // UID
}
@@ -495,7 +584,7 @@ setuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
// can't fathom why a benchmark would call this.
- warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
+ warn("Ignoring call to setuid(%d)\n", process->getSyscallArg(tc, 0));
return 0;
}
@@ -522,14 +611,14 @@ SyscallReturn
getuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- return process->uid(); // UID
+ return process->uid(); // UID
}
SyscallReturn
geteuidFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- return process->euid(); // UID
+ return process->euid(); // UID
}
SyscallReturn
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index e35b0a75b..0b0e73692 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -44,15 +44,15 @@
#include <errno.h>
#include <string>
#ifdef __CYGWIN32__
-#include <sys/fcntl.h> // for O_BINARY
+#include <sys/fcntl.h> // for O_BINARY
#endif
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
-#include "sim/host.hh" // for Addr
+#include "sim/host.hh" // for Addr
#include "base/chunk_generator.hh"
-#include "base/intmath.hh" // for RoundUp
+#include "base/intmath.hh" // for RoundUp
#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
@@ -72,9 +72,9 @@ class SyscallDesc {
typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
LiveProcess *, ThreadContext *);
- const char *name; //!< Syscall name (e.g., "open").
- FuncPtr funcPtr; //!< Pointer to emulation function.
- int flags; //!< Flags (see Flags enum).
+ 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 {
@@ -117,7 +117,7 @@ class BaseBufferArg {
virtual bool copyIn(TranslatingPort *memport)
{
memport->readBlob(addr, bufPtr, size);
- return true; // no EFAULT detection for now
+ return true; // no EFAULT detection for now
}
//
@@ -126,7 +126,7 @@ class BaseBufferArg {
virtual bool copyOut(TranslatingPort *memport)
{
memport->writeBlob(addr, bufPtr, size);
- return true; // no EFAULT detection for now
+ return true; // no EFAULT detection for now
}
protected:
@@ -140,7 +140,7 @@ class BufferArg : public BaseBufferArg
{
public:
BufferArg(Addr _addr, int _size) : BaseBufferArg(_addr, _size) { }
- void *bufferPtr() { return bufPtr; }
+ void *bufferPtr() { return bufPtr; }
};
template <class T>
@@ -158,8 +158,8 @@ class TypedBufferArg : public BaseBufferArg
operator T*() { return (T *)bufPtr; }
// dereference operators
- T &operator*() { return *((T *)bufPtr); }
- T* operator->() { return (T *)bufPtr; }
+ T &operator*() { return *((T *)bufPtr); }
+ T* operator->() { return (T *)bufPtr; }
T &operator[](int i) { return ((T *)bufPtr)[i]; }
};
@@ -191,9 +191,9 @@ SyscallReturn exitFunc(SyscallDesc *desc, int num,
SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
-/// Target obreak() handler: set brk address.
-SyscallReturn obreakFunc(SyscallDesc *desc, int num,
- LiveProcess *p, ThreadContext *tc);
+/// Target brk() handler: set brk address.
+SyscallReturn brkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
/// Target close() handler.
SyscallReturn closeFunc(SyscallDesc *desc, int num,
@@ -223,10 +223,22 @@ SyscallReturn munmapFunc(SyscallDesc *desc, int num,
SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target getcwd() handler.
+SyscallReturn getcwdFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+/// Target unlink() handler.
+SyscallReturn readlinkFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
/// Target unlink() handler.
SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target mkdir() handler.
+SyscallReturn mkdirFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
/// Target rename() handler.
SyscallReturn renameFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
@@ -242,6 +254,11 @@ SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
+/// Target umask() handler.
+SyscallReturn umaskFunc(SyscallDesc *desc, int num,
+ LiveProcess *p, ThreadContext *tc);
+
+
/// Target chown() handler.
SyscallReturn chownFunc(SyscallDesc *desc, int num,
LiveProcess *p, ThreadContext *tc);
@@ -363,6 +380,11 @@ convertStatBuf(target_stat &tgt, host_stat *host, bool fakeTTY = false)
tgt->st_ino = host->st_ino;
tgt->st_ino = htog(tgt->st_ino);
tgt->st_mode = host->st_mode;
+ if (fakeTTY) {
+ // Claim to be a character device
+ tgt->st_mode &= ~S_IFMT; // Clear S_IFMT
+ tgt->st_mode |= S_IFCHR; // Set S_IFCHR
+ }
tgt->st_mode = htog(tgt->st_mode);
tgt->st_nlink = host->st_nlink;
tgt->st_nlink = htog(tgt->st_nlink);
@@ -445,8 +467,8 @@ SyscallReturn
ioctlFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
- unsigned req = tc->getSyscallArg(1);
+ int fd = process->getSyscallArg(tc, 0);
+ unsigned req = process->getSyscallArg(tc, 1);
DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
@@ -480,7 +502,7 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
if (path == "/dev/sysdev0") {
@@ -490,8 +512,8 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
return -ENOENT;
}
- int tgtFlags = tc->getSyscallArg(1);
- int mode = tc->getSyscallArg(2);
+ int tgtFlags = process->getSyscallArg(tc, 1);
+ int mode = process->getSyscallArg(tc, 2);
int hostFlags = 0;
// translate open flags
@@ -515,10 +537,18 @@ openFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
DPRINTF(SyscallVerbose, "opening file %s\n", path.c_str());
- // open the file
- int fd = open(path.c_str(), hostFlags, mode);
+ int fd;
+ if (!path.compare(0, 6, "/proc/") || !path.compare(0, 8, "/system/") ||
+ !path.compare(0, 10, "/platform/") || !path.compare(0, 5, "/sys/")) {
+ // It's a proc/sys entery and requires special handling
+ fd = OS::openSpecialFile(path, process, tc);
+ return (fd == -1) ? -1 : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false);
+ } else {
+ // open the file
+ fd = open(path.c_str(), hostFlags, mode);
+ return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false);
+ }
- return (fd == -1) ? -errno : process->alloc_fd(fd,path.c_str(),hostFlags,mode, false);
}
@@ -530,10 +560,10 @@ chmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
- uint32_t mode = tc->getSyscallArg(1);
+ uint32_t mode = process->getSyscallArg(tc, 1);
mode_t hostMode = 0;
// XXX translate mode flags via OS::something???
@@ -557,13 +587,13 @@ SyscallReturn
fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int fd = process->getSyscallArg(tc, 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 = tc->getSyscallArg(1);
+ uint32_t mode = process->getSyscallArg(tc, 1);
mode_t hostMode = 0;
// XXX translate mode flags via OS::someting???
@@ -577,6 +607,51 @@ fchmodFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
return 0;
}
+/// Target mremap() handler.
+template <class OS>
+SyscallReturn
+mremapFunc(SyscallDesc *desc, int callnum, LiveProcess *process, ThreadContext *tc)
+{
+ Addr start = process->getSyscallArg(tc, 0);
+ uint64_t old_length = process->getSyscallArg(tc, 1);
+ uint64_t new_length = process->getSyscallArg(tc, 2);
+ uint64_t flags = process->getSyscallArg(tc, 3);
+
+ if ((start % TheISA::VMPageSize != 0) ||
+ (new_length % TheISA::VMPageSize != 0)) {
+ warn("mremap failing: arguments not page aligned");
+ return -EINVAL;
+ }
+
+ if (new_length > old_length) {
+ if ((start + old_length) == process->mmap_end) {
+ uint64_t diff = new_length - old_length;
+ process->pTable->allocate(process->mmap_end, diff);
+ process->mmap_end += diff;
+ return start;
+ } else {
+ // sys/mman.h defined MREMAP_MAYMOVE
+ if (!(flags & 1)) {
+ warn("can't remap here and MREMAP_MAYMOVE flag not set\n");
+ return -ENOMEM;
+ } else {
+ process->pTable->remap(start, old_length, process->mmap_end);
+ warn("mremapping to totally new vaddr %08p-%08p, adding %d\n",
+ process->mmap_end, process->mmap_end + new_length, new_length);
+ start = process->mmap_end;
+ // add on the remaining unallocated pages
+ process->pTable->allocate(start + old_length, new_length - old_length);
+ process->mmap_end += new_length;
+ warn("returning %08p as start\n", start);
+ return start;
+ }
+ }
+ } else {
+ process->pTable->deallocate(start + new_length, old_length -
+ new_length);
+ return start;
+ }
+}
/// Target stat() handler.
template <class OS>
@@ -586,7 +661,7 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
// Adjust path for current working directory
@@ -598,7 +673,8 @@ statFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
+ &hostBuf);
return 0;
}
@@ -612,7 +688,7 @@ stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
// Adjust path for current working directory
@@ -629,7 +705,8 @@ stat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
+ &hostBuf);
return 0;
}
@@ -641,7 +718,7 @@ SyscallReturn
fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int fd = process->getSyscallArg(tc, 0);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
@@ -658,7 +735,7 @@ fstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
+ copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
&hostBuf, (fd == 1));
return 0;
@@ -673,7 +750,7 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
// Adjust path for current working directory
@@ -685,7 +762,8 @@ lstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
+ &hostBuf);
return 0;
}
@@ -698,7 +776,7 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
// Adjust path for current working directory
@@ -715,7 +793,8 @@ lstat64Func(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStat64Buf<OS>(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
+ copyOutStat64Buf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
+ &hostBuf);
return 0;
}
@@ -726,7 +805,7 @@ SyscallReturn
fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
@@ -739,7 +818,7 @@ fstatFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- copyOutStatBuf<OS>(tc->getMemPort(), tc->getSyscallArg(1),
+ copyOutStatBuf<OS>(tc->getMemPort(), process->getSyscallArg(tc, 1),
&hostBuf, (fd == 1));
return 0;
@@ -754,7 +833,7 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
// Adjust path for current working directory
@@ -767,7 +846,7 @@ statfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
return -errno;
OS::copyOutStatfsBuf(tc->getMemPort(),
- (Addr)(tc->getSyscallArg(1)), &hostBuf);
+ (Addr)(process->getSyscallArg(tc, 1)), &hostBuf);
return 0;
}
@@ -779,7 +858,7 @@ SyscallReturn
fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = process->sim_fd(tc->getSyscallArg(0));
+ int fd = process->sim_fd(process->getSyscallArg(tc, 0));
if (fd < 0)
return -EBADF;
@@ -790,7 +869,7 @@ fstatfsFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
if (result < 0)
return -errno;
- OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1),
+ OS::copyOutStatfsBuf(tc->getMemPort(), process->getSyscallArg(tc, 1),
&hostBuf);
return 0;
@@ -803,15 +882,15 @@ SyscallReturn
writevFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int fd = tc->getSyscallArg(0);
+ int fd = process->getSyscallArg(tc, 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 = tc->getMemPort();
- uint64_t tiov_base = tc->getSyscallArg(1);
- size_t count = tc->getSyscallArg(2);
+ uint64_t tiov_base = process->getSyscallArg(tc, 1);
+ size_t count = process->getSyscallArg(tc, 2);
struct iovec hiov[count];
for (int i = 0; i < count; ++i)
{
@@ -855,12 +934,13 @@ template <class OS>
SyscallReturn
mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
{
- Addr start = tc->getSyscallArg(0);
- uint64_t length = tc->getSyscallArg(1);
- // int prot = tc->getSyscallArg(2);
- int flags = tc->getSyscallArg(3);
- // int fd = p->sim_fd(tc->getSyscallArg(4));
- // int offset = tc->getSyscallArg(5);
+ Addr start = p->getSyscallArg(tc, 0);
+ uint64_t length = p->getSyscallArg(tc, 1);
+ // int prot = p->getSyscallArg(tc, 2);
+ int flags = p->getSyscallArg(tc, 3);
+ // int fd = p->sim_fd(p->getSyscallArg(tc, 4));
+ // int offset = p->getSyscallArg(tc, 5);
+
if ((start % TheISA::VMPageSize) != 0 ||
(length % TheISA::VMPageSize) != 0) {
@@ -882,7 +962,7 @@ mmapFunc(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc)
if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
warn("allowing mmap of file @ fd %d. "
- "This will break if not /dev/zero.", tc->getSyscallArg(4));
+ "This will break if not /dev/zero.", p->getSyscallArg(tc, 4));
}
return start;
@@ -894,17 +974,24 @@ SyscallReturn
getrlimitFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- unsigned resource = tc->getSyscallArg(0);
- TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
+ unsigned resource = process->getSyscallArg(tc, 0);
+ TypedBufferArg<typename OS::rlimit> rlp(process->getSyscallArg(tc, 1));
switch (resource) {
case OS::TGT_RLIMIT_STACK:
- // max stack size in bytes: make up a number (2MB for now)
+ // max stack size in bytes: make up a number (8MB 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;
+ case OS::TGT_RLIMIT_DATA:
+ // max data segment size in bytes: make up a number
+ rlp->rlim_cur = rlp->rlim_max = 256 * 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;
@@ -922,7 +1009,7 @@ SyscallReturn
gettimeofdayFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
+ TypedBufferArg<typename OS::timeval> tp(process->getSyscallArg(tc, 0));
getElapsedTime(tp->tv_sec, tp->tv_usec);
tp->tv_sec += seconds_since_epoch;
@@ -943,10 +1030,10 @@ utimesFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
{
std::string path;
- if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, process->getSyscallArg(tc, 0)))
return -EFAULT;
- TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
+ TypedBufferArg<typename OS::timeval [2]> tp(process->getSyscallArg(tc, 1));
tp.copyIn(tc->getMemPort());
struct timeval hostTimeval[2];
@@ -972,8 +1059,8 @@ SyscallReturn
getrusageFunc(SyscallDesc *desc, int callnum, LiveProcess *process,
ThreadContext *tc)
{
- int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
- TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
+ int who = process->getSyscallArg(tc, 0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<typename OS::rusage> rup(process->getSyscallArg(tc, 1));
rup->ru_utime.tv_sec = 0;
rup->ru_utime.tv_usec = 0;
diff --git a/src/sim/system.cc b/src/sim/system.cc
index 10b9b1217..d16524c41 100644
--- a/src/sim/system.cc
+++ b/src/sim/system.cc
@@ -42,6 +42,7 @@
#include "mem/physical.hh"
#include "sim/byteswap.hh"
#include "sim/system.hh"
+#include "sim/debug.hh"
#if FULL_SYSTEM
#include "arch/vtophys.hh"
#include "kern/kernel_stats.hh"
@@ -57,7 +58,7 @@ vector<System *> System::systemList;
int System::numSystemsRunning = 0;
System::System(Params *p)
- : SimObject(p), physmem(p->physmem), numcpus(0),
+ : SimObject(p), physmem(p->physmem), _numContexts(0),
#if FULL_SYSTEM
init_param(p->init_param),
functionalPort(p->name + "-fport"),
@@ -94,12 +95,12 @@ System::System(Params *p)
* Load the kernel code into memory
*/
if (params()->kernel == "") {
- warn("No kernel set for full system simulation. Assuming you know what"
+ inform("No kernel set for full system simulation. Assuming you know what"
" you're doing...\n");
} else {
// Load kernel code
kernel = createObjectFile(params()->kernel);
- warn("kernel located at: %s", params()->kernel);
+ inform("kernel located at: %s", params()->kernel);
if (kernel == NULL)
fatal("Could not load kernel file %s", params()->kernel);
@@ -114,16 +115,16 @@ System::System(Params *p)
// load symbols
if (!kernel->loadGlobalSymbols(kernelSymtab))
- panic("could not load kernel symbols\n");
+ fatal("could not load kernel symbols\n");
if (!kernel->loadLocalSymbols(kernelSymtab))
- panic("could not load kernel local symbols\n");
+ fatal("could not load kernel local symbols\n");
if (!kernel->loadGlobalSymbols(debugSymbolTable))
- panic("could not load kernel symbols\n");
+ fatal("could not load kernel symbols\n");
if (!kernel->loadLocalSymbols(debugSymbolTable))
- panic("could not load kernel local symbols\n");
+ fatal("could not load kernel local symbols\n");
DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
@@ -165,27 +166,33 @@ bool System::breakpoint()
}
int
-System::registerThreadContext(ThreadContext *tc, int id)
+System::registerThreadContext(ThreadContext *tc, int assigned)
{
- if (id == -1) {
+ int id;
+ if (assigned == -1) {
for (id = 0; id < threadContexts.size(); id++) {
if (!threadContexts[id])
break;
}
- }
- if (threadContexts.size() <= id)
- threadContexts.resize(id + 1);
+ if (threadContexts.size() <= id)
+ threadContexts.resize(id + 1);
+ } else {
+ if (threadContexts.size() <= assigned)
+ threadContexts.resize(assigned + 1);
+ id = assigned;
+ }
if (threadContexts[id])
- panic("Cannot have two CPUs with the same id (%d)\n", id);
+ fatal("Cannot have two CPUs with the same id (%d)\n", id);
threadContexts[id] = tc;
- numcpus++;
+ _numContexts++;
- if (rgdb_enable) {
+ int port = getRemoteGDBPort();
+ if (rgdb_enable && port) {
RemoteGDB *rgdb = new RemoteGDB(this, tc);
- GDBListener *gdbl = new GDBListener(rgdb, 7000 + id);
+ GDBListener *gdbl = new GDBListener(rgdb, port + id);
gdbl->listen();
/**
* Uncommenting this line waits for a remote debugger to
@@ -207,22 +214,24 @@ System::registerThreadContext(ThreadContext *tc, int id)
void
System::startup()
{
+#if FULL_SYSTEM
int i;
for (i = 0; i < threadContexts.size(); i++)
TheISA::startupCPU(threadContexts[i], i);
+#endif
}
void
-System::replaceThreadContext(ThreadContext *tc, int id)
+System::replaceThreadContext(ThreadContext *tc, int context_id)
{
- if (id >= threadContexts.size()) {
+ if (context_id >= threadContexts.size()) {
panic("replaceThreadContext: bad id, %d >= %d\n",
- id, threadContexts.size());
+ context_id, threadContexts.size());
}
- threadContexts[id] = tc;
- if (id < remoteGDB.size())
- remoteGDB[id]->replaceThreadContext(tc);
+ threadContexts[context_id] = tc;
+ if (context_id < remoteGDB.size())
+ remoteGDB[context_id]->replaceThreadContext(tc);
}
#if !FULL_SYSTEM
@@ -235,6 +244,19 @@ System::new_page()
fatal("Out of memory, please increase size of physical memory.");
return return_addr;
}
+
+Addr
+System::memSize()
+{
+ return physmem->size();
+}
+
+Addr
+System::freeMemSize()
+{
+ return physmem->size() - (page_ptr << LogVMPageSize);
+}
+
#endif
void
@@ -283,11 +305,7 @@ const char *System::MemoryModeStrings[3] = {"invalid", "atomic",
System *
SystemParams::create()
{
- System::Params *p = new System::Params;
- p->name = name;
- p->physmem = physmem;
- p->mem_mode = mem_mode;
- return new System(p);
+ return new System(this);
}
#endif
diff --git a/src/sim/system.hh b/src/sim/system.hh
index cdd5bebb0..bfa5ea8bb 100644
--- a/src/sim/system.hh
+++ b/src/sim/system.hh
@@ -87,14 +87,19 @@ class System : public SimObject
PCEventQueue pcEventQueue;
std::vector<ThreadContext *> threadContexts;
- int numcpus;
+ int _numContexts;
- int getNumCPUs()
+ ThreadContext * getThreadContext(int tid)
{
- if (numcpus != threadContexts.size())
+ return threadContexts[tid];
+ }
+
+ int numContexts()
+ {
+ if (_numContexts != threadContexts.size())
panic("cpu array not fully populated!");
- return numcpus;
+ return _numContexts;
}
#if FULL_SYSTEM
@@ -134,6 +139,12 @@ class System : public SimObject
return next_PID++;
}
+ /** Amount of physical memory that is still free */
+ Addr freeMemSize();
+
+ /** Amount of physical memory that exists */
+ Addr memSize();
+
#endif // FULL_SYSTEM
@@ -219,8 +230,8 @@ class System : public SimObject
#endif // FULL_SYSTEM
- int registerThreadContext(ThreadContext *tc, int tcIndex);
- void replaceThreadContext(ThreadContext *tc, int tcIndex);
+ int registerThreadContext(ThreadContext *tc, int assigned=-1);
+ void replaceThreadContext(ThreadContext *tc, int context_id);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
diff --git a/src/sim/tlb.cc b/src/sim/tlb.cc
index 7292a69e0..e82e4f277 100644
--- a/src/sim/tlb.cc
+++ b/src/sim/tlb.cc
@@ -34,7 +34,7 @@
#include "sim/tlb.hh"
Fault
-GenericTLB::translate(RequestPtr req, ThreadContext * tc, bool)
+GenericTLB::translateAtomic(RequestPtr req, ThreadContext * tc, bool)
{
#if FULL_SYSTEM
panic("Generic translation shouldn't be used in full system mode.\n");
@@ -50,6 +50,14 @@ GenericTLB::translate(RequestPtr req, ThreadContext * tc, bool)
}
void
+GenericTLB::translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool write)
+{
+ assert(translation);
+ translation->finish(translateAtomic(req, tc, write), req, tc, write);
+}
+
+void
GenericTLB::demapPage(Addr vaddr, uint64_t asn)
{
warn("Demapping pages in the generic TLB is unnecessary.\n");
diff --git a/src/sim/tlb.hh b/src/sim/tlb.hh
index 011cc1144..8893f8c97 100644
--- a/src/sim/tlb.hh
+++ b/src/sim/tlb.hh
@@ -47,6 +47,21 @@ class BaseTLB : public SimObject
public:
virtual void demapPage(Addr vaddr, uint64_t asn) = 0;
+
+ class Translation
+ {
+ public:
+ virtual ~Translation()
+ {}
+
+ /*
+ * The memory for this object may be dynamically allocated, and it may
+ * be responsible for cleaning itself up which will happen in this
+ * function. Once it's called, the object is no longer valid.
+ */
+ virtual void finish(Fault fault, RequestPtr req,
+ ThreadContext *tc, bool write=false) = 0;
+ };
};
class GenericTLB : public BaseTLB
@@ -58,7 +73,9 @@ class GenericTLB : public BaseTLB
public:
void demapPage(Addr vaddr, uint64_t asn);
- Fault translate(RequestPtr req, ThreadContext *tc, bool=false);
+ Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool=false);
+ void translateTiming(RequestPtr req, ThreadContext *tc,
+ Translation *translation, bool=false);
};
#endif // __ARCH_SPARC_TLB_HH__
diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh
index 383f65351..09aa2d213 100644
--- a/src/sim/vptr.hh
+++ b/src/sim/vptr.hh
@@ -71,9 +71,8 @@ class VPtr
if (!ptr)
return;
- VirtualPort *port = tc->getVirtPort(tc);
+ VirtualPort *port = tc->getVirtPort();
port->readBlob(ptr, buffer, sizeof(T));
- tc->delVirtPort(port);
}
bool
diff --git a/src/unittest/Makefile b/src/unittest/Makefile
deleted file mode 100644
index e6a621a9e..000000000
--- a/src/unittest/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-# Copyright (c) 2006-2007 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (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: unittest/bitvectest.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-circletest: unittest/circletest.cc base/circlebuf.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-cprintftest: unittest/cprintftest.cc base/cprintf.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-cprintftime: unittest/cprintftime.cc base/cprintf.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-initest: unittest/initest.cc base/str.cc base/inifile.cc base/cprintf.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-lrutest: unittest/lru_test.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-nmtest: unittest/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: unittest/offtest.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-rangetest: unittest/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+= unittest/stattest.cc
-stattest: $(STATTEST)
- $(CXX) $(CCFLAGS) $(MYSQL) -o $@ $^
-
-strnumtest: unittest/strnumtest.cc base/str.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-symtest: unittest/symtest.cc base/misc.cc base/symtab.cc base/str.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-tokentest: unittest/tokentest.cc base/str.cc
- $(CXX) $(CCFLAGS) -o $@ $^
-
-TRACE+=unittest/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/src/unittest/SConscript b/src/unittest/SConscript
new file mode 100644
index 000000000..1c1959165
--- /dev/null
+++ b/src/unittest/SConscript
@@ -0,0 +1,48 @@
+# -*- 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.
+#
+# Authors: Nathan Binkert
+
+Import('*')
+
+UnitTest('bitvectest', 'bitvectest.cc')
+UnitTest('circletest', 'circletest.cc')
+UnitTest('cprintftest', 'cprintftest.cc')
+UnitTest('cprintftime', 'cprintftest.cc')
+UnitTest('initest', 'initest.cc')
+UnitTest('lrutest', 'lru_test.cc')
+UnitTest('nmtest', 'nmtest.cc')
+UnitTest('offtest', 'offtest.cc')
+UnitTest('rangetest', 'rangetest.cc')
+UnitTest('rangemaptest', 'rangemaptest.cc')
+UnitTest('rangemultimaptest', 'rangemultimaptest.cc')
+UnitTest('stattest', 'stattest.cc')
+UnitTest('strnumtest', 'strnumtest.cc')
+UnitTest('symtest', 'symtest.cc')
+UnitTest('tokentest', 'tokentest.cc')
+UnitTest('tracetest', 'tracetest.cc')
diff --git a/src/unittest/bitvectest.cc b/src/unittest/bitvectest.cc
index 440a150a3..29069081b 100644
--- a/src/unittest/bitvectest.cc
+++ b/src/unittest/bitvectest.cc
@@ -28,41 +28,42 @@
* Authors: Nathan Binkert
*/
-#include <iostream.h>
-
+#include <iostream>
#include <vector>
+using namespace std;
+
int
main()
{
- vector<bool> v1(100);
+ vector<bool> v1(100);
- v1[0] = true;
- v1.resize(500);
- v1[100] = true;
- v1[499] = true;
- v1.resize(10000);
- v1[9999] = true;
+ v1[0] = true;
+ v1.resize(500);
+ v1[100] = true;
+ v1[499] = true;
+ v1.resize(10000);
+ v1[9999] = true;
- cout << "v1.size() = " << v1.size() << "\n";
- for (int i = 0; i < v1.size(); i++)
- if (v1[i])
- cout << "v1[" << i << "] = " << v1[i] << "\n";
+ cout << "v1.size() = " << v1.size() << "\n";
+ for (int i = 0; i < v1.size(); i++)
+ if (v1[i])
+ cout << "v1[" << i << "] = " << v1[i] << "\n";
- cout << "\n";
+ cout << "\n";
- vector<bool> v2 = v1;
+ vector<bool> v2 = v1;
- for (int i = 0; i < v2.size(); i++)
- if (v2[i])
- cout << "v2[" << i << "] = " << v2[i] << "\n";
+ for (int i = 0; i < v2.size(); i++)
+ if (v2[i])
+ cout << "v2[" << i << "] = " << v2[i] << "\n";
- cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
- v2[8583] = true;
- cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
- v1[8583] = true;
- cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
- v1.resize(100000);
- cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
- cout << flush;
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v2[8583] = true;
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v1[8583] = true;
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ v1.resize(100000);
+ cout << "v1 " << ((v1 == v2) ? "==" : "!=") << " v2" << "\n";
+ cout << flush;
}
diff --git a/src/unittest/circletest.cc b/src/unittest/circletest.cc
index f072cf044..2ee75b6df 100644
--- a/src/unittest/circletest.cc
+++ b/src/unittest/circletest.cc
@@ -29,19 +29,21 @@
*/
#include <fcntl.h>
-#include <iostream.h>
#include <unistd.h>
+#include <iostream>
+
#include "base/circlebuf.hh"
-char *strings[] =
-{ "This is the first test\n",
- "he went with his woman to the store\n",
- "the man with the bat hit the woman with the hat\n",
- "that that is is that that was\n",
- "sue sells sea shells by the sea shore\n",
- "go to the store and buy me some milk and bread\n",
- "the friendly flight attendants spoke soothingly to the frightened passengers in their native languages\n"
+const char *strings[] = {
+ "This is the first test\n",
+ "he went with his woman to the store\n",
+ "the man with the bat hit the woman with the hat\n",
+ "that that is is that that was\n",
+ "sue sells sea shells by the sea shore\n",
+ "go to the store and buy me some milk and bread\n",
+ "the friendly flight attendants spoke soothingly to "
+ "the frightened passengers in their native languages\n"
};
const int num_strings = sizeof(strings) / sizeof(char *);
@@ -49,26 +51,26 @@ const int num_strings = sizeof(strings) / sizeof(char *);
int
main()
{
- CircleBuf buf(1024);
+ CircleBuf buf(1024);
- for (int count = 0; count < 100; count++)
- buf.write(strings[count % num_strings]);
- buf.read(STDOUT_FILENO);
- write(STDOUT_FILENO, "<\n", 2);
+ for (int count = 0; count < 100; count++)
+ buf.write(strings[count % num_strings]);
+ buf.read(STDOUT_FILENO);
+ write(STDOUT_FILENO, "<\n", 2);
- for (int count = 0; count < 100; count++)
- buf.write(strings[count % num_strings]);
- buf.read(STDOUT_FILENO, 100);
- write(STDOUT_FILENO, "<\n", 2);
+ for (int count = 0; count < 100; count++)
+ buf.write(strings[count % num_strings]);
+ buf.read(STDOUT_FILENO, 100);
+ write(STDOUT_FILENO, "<\n", 2);
- buf.flush();
- buf.write("asdfa asdf asd fasdf asdf\n");
- buf.write("");
- buf.write("");
- buf.write("");
- buf.write("");
- buf.write("");
- buf.write("");
- buf.read(STDOUT_FILENO);
- write(STDOUT_FILENO, "<\n", 2);
+ buf.flush();
+ buf.write("asdfa asdf asd fasdf asdf\n");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.write("");
+ buf.read(STDOUT_FILENO);
+ write(STDOUT_FILENO, "<\n", 2);
}
diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc
index 7fb10375c..6722ce6a3 100644
--- a/src/unittest/cprintftest.cc
+++ b/src/unittest/cprintftest.cc
@@ -34,6 +34,7 @@
#include <sstream>
#include "base/cprintf.hh"
+#include "base/misc.hh"
using namespace std;
@@ -43,6 +44,14 @@ main()
char foo[] = "foo";
cprintf("%s\n", foo);
+ string _bar = "asdfkhasdlkfjhasdlkfhjalksdjfhalksdjhfalksdjfhalksdjhf";
+ int length = 11;
+ char bar[length + 1];
+ bar[length] = 0;
+
+ memcpy(bar, _bar.c_str(), length);
+ warn("%s\n", bar);
+
cprintf("%d\n", 'A');
cprintf("%shits%%s + %smisses%%s\n", "test", "test");
cprintf("%%s%-10s %c he went home \'\"%d %#o %#x %1.5f %1.2E\n",
@@ -158,6 +167,13 @@ main()
cprintf("%c %c\n", 'c', 65);
- cout << '9';
+ cout << '9' << endl;
+
+ cout << endl;
+
+ cprintf("%08.4f\n", 99.99);
+ cprintf("%0*.*f\n", 8, 4, 99.99);
+ cprintf("%07.*f\n", 4, 1.234);
+ cprintf("%#0*x\n", 9, 123412);
return 0;
}
diff --git a/src/unittest/foo.ini b/src/unittest/foo.ini
index 534a4e001..0f91c1fd6 100644
--- a/src/unittest/foo.ini
+++ b/src/unittest/foo.ini
@@ -1,4 +1,3 @@
-#define JUNK
[Foo]
Foo1=89
Foo2=384
diff --git a/src/unittest/initest.cc b/src/unittest/initest.cc
index 8f53fce5c..67ac44874 100644
--- a/src/unittest/initest.cc
+++ b/src/unittest/initest.cc
@@ -68,32 +68,14 @@ main(int argc, char *argv[])
progname = argv[0];
- vector<char *> cppArgs;
-
- vector<char *> cpp_options;
- cpp_options.reserve(argc * 2);
-
for (int i = 1; i < argc; ++i) {
char *arg_str = argv[i];
// if arg starts with '-', parse as option,
// else treat it as a configuration file name and load it
if (arg_str[0] == '-') {
-
// switch on second char
switch (arg_str[1]) {
- case 'D':
- case 'U':
- case 'I':
- // cpp options: record & pass to cpp. Note that these
- // cannot have spaces, i.e., '-Dname=val' is OK, but
- // '-D name=val' is not. I don't consider this a
- // problem, since even though gnu cpp accepts the
- // latter, other cpp implementations do not (Tru64,
- // for one).
- cppArgs.push_back(arg_str);
- break;
-
case '-':
// command-line configuration parameter:
// '--<section>:<parameter>=<value>'
@@ -115,7 +97,7 @@ main(int argc, char *argv[])
else {
// no '-', treat as config file name
- if (!simConfigDB.loadCPP(arg_str, cppArgs)) {
+ if (!simConfigDB.load(arg_str)) {
cprintf("Error processing file %s\n", arg_str);
exit(1);
}
diff --git a/src/unittest/initest.ini b/src/unittest/initest.ini
deleted file mode 100644
index ebf2719d8..000000000
--- a/src/unittest/initest.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-#define JUNK
-// General stuff
-#define FOO(X) BAR##X
-[General]
- Test1=FOO(asdf)
- Test2=bar
-
-#ifdef JUNK
-[Junk] // This is the junk
-Test3=yo
-Test4=mama
-#endif
-
-#include "foo.ini"
diff --git a/src/unittest/lru_test.cc b/src/unittest/lru_test.cc
deleted file mode 100644
index d10eb1dd0..000000000
--- a/src/unittest/lru_test.cc
+++ /dev/null
@@ -1,85 +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.
- *
- * Authors: Dave Greene
- * Nathan Binkert
- */
-
-#include <iostream>
-#include "bhgp.hh"
-
-int main(void)
-{
- typedef AssociativeTable<unsigned int, unsigned int> tableType;
- tableType table(10, 4); // 40 entry table
-
- std::cout << "Initial state:" << std::endl;
- table.dump();
-
- std::cout << "Inserting (2, 1)" << std::endl;
- table[2] = 1;
- table.dump();
-
- std::cout << "Inserting (5, 2)" << std::endl;
- table[5] = 2;
- table.dump();
-
- std::cout << "Inserting (10 + 2, 3)" << std::endl;
- table[10 + 2] = 3;
- table.dump();
-
- tableType::const_iterator i = table.find(2);
- assert(i != table.end());
- std::cout << "Accessed 2: " << *i << std::endl;
- table.dump();
-
- i = table.find(10 + 2);
- assert(i != table.end());
- std::cout << "Accessed 10 + 2: " << *i << std::endl;
- table.dump();
-
- i = table.find(34);
- assert(i == table.end());
-
- std::cout << "Inserting (2 * 10 + 2, 4)" << std::endl;
- table[2 * 10 + 2] = 4;
- table.dump();
-
- std::cout << "Replacing (10 + 2) with 5" << std::endl;
- table[10 + 2] = 5;
- table.dump();
-
- std::cout << "Inserting (3 * 10 + 2, 6)" << std::endl;
- table[3 * 10 + 2] = 6;
- table.dump();
-
- std::cout << "Inserting (4 * 10 + 2, 7)" << std::endl;
- table[4 * 10 + 2] = 7;
- table.dump();
-
- return(0);
-}
diff --git a/src/unittest/nmtest.cc b/src/unittest/nmtest.cc
index b6b74e08d..fdd865f2d 100644
--- a/src/unittest/nmtest.cc
+++ b/src/unittest/nmtest.cc
@@ -38,9 +38,6 @@
#include "base/str.hh"
using namespace std;
-Tick curTick;
-
-ostream *outputStream = &cout;
int
main(int argc, char *argv[])
diff --git a/src/unittest/paramtest.cc b/src/unittest/paramtest.cc
deleted file mode 100644
index e513ab981..000000000
--- a/src/unittest/paramtest.cc
+++ /dev/null
@@ -1,107 +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.
- *
- * Authors: Nathan Binkert
- */
-
-//
-// This file is not part of the regular simulator. It is solely for
-// testing the parameter code. Edit the Makefile to add param_test.cc
-// to the sources list, then use configs/test.ini as the configuration
-// file.
-//
-#include "sim/sim_object.hh"
-#include "mem/cache/cache.hh"
-
-class ParamTest : public SimObject
-{
- public:
- ParamTest(string name)
- : SimObject(name)
- {
- }
-
- virtual ~ParamTest() {}
-};
-
-enum Enum1Type { Enum0 };
-enum Enum2Type { Enum10 };
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(ParamTest)
-
- Param<int> intparam;
- VectorParam<int> vecint;
- Param<string> stringparam;
- VectorParam<string> vecstring;
- Param<bool> boolparam;
- VectorParam<bool> vecbool;
- SimObjectParam<BaseMemory *> memobj;
- SimObjectVectorParam<BaseMemory *> vecmemobj;
- SimpleEnumParam<Enum1Type> enum1;
- MappedEnumParam<Enum2Type> enum2;
- SimpleEnumVectorParam<Enum1Type> vecenum1;
- MappedEnumVectorParam<Enum2Type> vecenum2;
-
-END_DECLARE_SIM_OBJECT_PARAMS(ParamTest)
-
-const char *enum1_strings[] =
-{
- "zero", "one", "two", "three"
-};
-
-const EnumParamMap enum2_map[] =
-{
- { "ten", 10 },
- { "twenty", 20 },
- { "thirty", 30 },
- { "forty", 40 }
-};
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(ParamTest)
-
- INIT_PARAM(intparam, "intparam"),
- INIT_PARAM(vecint, "vecint"),
- INIT_PARAM(stringparam, "stringparam"),
- INIT_PARAM(vecstring, "vecstring"),
- INIT_PARAM(boolparam, "boolparam"),
- INIT_PARAM(vecbool, "vecbool"),
- INIT_PARAM(memobj, "memobj"),
- INIT_PARAM(vecmemobj, "vecmemobj"),
- INIT_ENUM_PARAM(enum1, "enum1", enum1_strings),
- INIT_ENUM_PARAM(enum2, "enum2", enum2_map),
- INIT_ENUM_PARAM(vecenum1, "vecenum1", enum1_strings),
- INIT_ENUM_PARAM(vecenum2, "vecenum2", enum2_map)
-
-END_INIT_SIM_OBJECT_PARAMS(ParamTest)
-
-
-CREATE_SIM_OBJECT(ParamTest)
-{
- return new ParamTest(getInstanceName());
-}
-
-REGISTER_SIM_OBJECT("ParamTest", ParamTest)
diff --git a/src/unittest/rangemaptest.cc b/src/unittest/rangemaptest.cc
index 983a41520..36223ed9c 100644
--- a/src/unittest/rangemaptest.cc
+++ b/src/unittest/rangemaptest.cc
@@ -35,7 +35,8 @@
using namespace std;
-int main()
+int
+main()
{
range_map<Addr,int> r;
diff --git a/src/unittest/rangemaptest2.cc b/src/unittest/rangemultimaptest.cc
index b253dbe86..a110256c9 100644
--- a/src/unittest/rangemaptest2.cc
+++ b/src/unittest/rangemultimaptest.cc
@@ -28,20 +28,22 @@
* Authors: Ali Saidi
*/
-#include <iostream>
#include <cassert>
+#include <iostream>
+
#include "sim/host.hh"
#include "base/range_map.hh"
using namespace std;
-int main()
+int
+main()
{
- range_multimap<Addr,int> r;
+ typedef range_multimap<Addr, int> multimap_t;
- range_multimap<Addr,int>::iterator i;
- std::pair<range_multimap<Addr,int>::iterator,range_multimap<Addr,int>::iterator>
- jk;
+ multimap_t r;
+ multimap_t::iterator i;
+ std::pair<multimap_t::iterator, multimap_t::iterator> jk;
i = r.insert(RangeIn<Addr>(10,40),5);
assert(i != r.end());
diff --git a/src/unittest/rangetest.cc b/src/unittest/rangetest.cc
index b7a68ab44..eab2f39a8 100644
--- a/src/unittest/rangetest.cc
+++ b/src/unittest/rangetest.cc
@@ -38,39 +38,40 @@ using namespace std;
int
main()
{
- Range<int> r1(make_pair(9, 28));
- Range<unsigned> r2("0x1000:+0x100");
+ Range<int> r1(make_pair(9, 28));
+ Range<unsigned> r2("0x1000:+0x100");
- cout << r1 << "\n"
- << r2 << "\n";
+ cout << r1 << "\n"
+ << r2 << "\n";
-#define RANGETEST(X, C, Y) \
- cout << X << " "#C" " << Y << " => " << ((X C Y) ? "true" : "false") << "\n"
+#define RANGETEST(X, C, Y) \
+ cout << X << " "#C" " << Y << " => " << \
+ ((X C Y) ? "true" : "false") << "\n"
#define TESTEM(X, Y) do { \
- RANGETEST(X, < , Y); \
- RANGETEST(X, <=, Y); \
- RANGETEST(X, > , Y); \
- RANGETEST(X, >=, Y); \
- RANGETEST(X, ==, Y); \
- RANGETEST(X, !=, Y); \
- RANGETEST(Y, < , X); \
- RANGETEST(Y, <=, X); \
- RANGETEST(Y, > , X); \
- RANGETEST(Y, >=, X); \
- RANGETEST(Y, ==, X); \
- RANGETEST(Y, !=, X); \
-} while (0)
+ RANGETEST(X, < , Y); \
+ RANGETEST(X, <=, Y); \
+ RANGETEST(X, > , Y); \
+ RANGETEST(X, >=, Y); \
+ RANGETEST(X, ==, Y); \
+ RANGETEST(X, !=, Y); \
+ RANGETEST(Y, < , X); \
+ RANGETEST(Y, <=, X); \
+ RANGETEST(Y, > , X); \
+ RANGETEST(Y, >=, X); \
+ RANGETEST(Y, ==, X); \
+ RANGETEST(Y, !=, X); \
+ } while (0)
- TESTEM(8, r1);
- TESTEM(9, r1);
- TESTEM(27, r1);
- TESTEM(28, r1);
+ TESTEM(8, r1);
+ TESTEM(9, r1);
+ TESTEM(27, r1);
+ TESTEM(28, r1);
- TESTEM(0x0fff, r2);
- TESTEM(0x1000, r2);
- TESTEM(0x10ff, r2);
- TESTEM(0x1100, r2);
+ TESTEM(0x0fff, r2);
+ TESTEM(0x1000, r2);
+ TESTEM(0x10ff, r2);
+ TESTEM(0x1100, r2);
- return 0;
+ return 0;
}
diff --git a/src/unittest/sized_test.cc b/src/unittest/sized_test.cc
deleted file mode 100644
index f1bf7528f..000000000
--- a/src/unittest/sized_test.cc
+++ /dev/null
@@ -1,70 +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.
- *
- * Authors: Dave Greene
- * Nathan Binkert
- */
-
-#include <iostream>
-#include <algorithm>
-
-#include "sized.hh"
-#include <queue>
-#include <typeinfo>
-
-template<typename C>
-void print(C &cont)
-{
- std::cout << std::endl;
- std::cout << "Printing " << typeid(cont).name() << std::endl;
- while (!cont.empty()) {
- std::cout << cont.front() << " ";
- cont.pop();
- }
- std::cout << std::endl;
-}
-
-int main(void)
-{
- sized<std::queue<int>, sized_error_policy<std::queue<int> > >
- error_queue(10);
- sized<std::queue<int>, sized_drop_policy<std::queue<int> > >
- drop_queue(5);
-
- for (int i = 0; i < 10; ++i) {
- error_queue.push(i);
- }
-
- for (int i = 0; i < 3; ++i) {
- drop_queue.push(i);
- }
-
- print(error_queue);
- print(drop_queue);
-
- return(0);
-}
diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc
index 4e504fde9..3934786ec 100644
--- a/src/unittest/stattest.cc
+++ b/src/unittest/stattest.cc
@@ -30,9 +30,7 @@
#include <iomanip>
#include <iostream>
-#include <fstream>
#include <string>
-#include <unistd.h>
#include "base/cprintf.hh"
#include "base/misc.hh"
@@ -44,36 +42,6 @@
using namespace std;
using namespace Stats;
-Tick curTick = 0;
-Tick ticksPerSecond = ULL(2000000000);
-
-Scalar<> s1;
-Scalar<> s2;
-Average<> s3;
-Scalar<> s4;
-Vector<> s5;
-Distribution<> s6;
-Vector<> s7;
-AverageVector<> s8;
-StandardDeviation<> s9;
-AverageDeviation<> s10;
-Scalar<> s11;
-Distribution<> s12;
-VectorDistribution<> s13;
-VectorStandardDeviation<> s14;
-VectorAverageDeviation<> s15;
-Vector2d<> s16;
-
-Formula f1;
-Formula f2;
-Formula f3;
-Value f4;
-Value f5;
-Formula f6;
-Formula f7;
-
-ostream *outputStream = &cout;
-
double
testfunc()
{
@@ -85,7 +53,7 @@ class TestClass {
double operator()() { return 9.7; }
};
-char *progname = "";
+const char *progname = "";
void
usage()
@@ -101,14 +69,18 @@ main(int argc, char *argv[])
bool descriptions = false;
bool compat = false;
bool text = false;
+
+#if USE_MYSQL
string mysql_name;
+ string mysql_db;
string mysql_host;
string mysql_user = "binkertn";
string mysql_passwd;
+#endif
char c;
progname = argv[0];
- while ((c = getopt(argc, argv, "cdh:P:p:s:tu:")) != -1) {
+ while ((c = getopt(argc, argv, "cD:dh:P:p:s:tu:")) != -1) {
switch (c) {
case 'c':
compat = true;
@@ -116,6 +88,13 @@ main(int argc, char *argv[])
case 'd':
descriptions = true;
break;
+ case 't':
+ text = true;
+ break;
+#if USE_MYSQL
+ case 'D':
+ mysql_db = optarg;
+ break;
case 'h':
mysql_host = optarg;
break;
@@ -125,12 +104,10 @@ main(int argc, char *argv[])
case 's':
mysql_name = optarg;
break;
- case 't':
- text = true;
- break;
case 'u':
mysql_user = optarg;
break;
+#endif
default:
usage();
}
@@ -139,15 +116,34 @@ main(int argc, char *argv[])
if (!text && (compat || descriptions))
usage();
- s5.init(5);
- s6.init(1, 100, 13);
- s7.init(7);
- s8.init(10);
- s12.init(1, 100, 13);
- s13.init(4, 0, 99, 10);
- s14.init(9);
- s15.init(10);
- s16.init(2, 9);
+ Scalar s1;
+ Scalar s2;
+ Average s3;
+ Scalar s4;
+ Vector s5;
+ Distribution s6;
+ Vector s7;
+ AverageVector s8;
+ StandardDeviation s9;
+ AverageDeviation s10;
+ Scalar s11;
+ Distribution s12;
+ VectorDistribution s13;
+ VectorStandardDeviation s14;
+ VectorAverageDeviation s15;
+ Vector2d s16;
+ Value s17;
+ Value s18;
+
+ Formula f1;
+ Formula f2;
+ Formula f3;
+ Formula f4;
+ Formula f5;
+
+ cprintf("sizeof(Scalar) = %d\n", sizeof(Scalar));
+ cprintf("sizeof(Vector) = %d\n", sizeof(Vector));
+ cprintf("sizeof(Distribution) = %d\n", sizeof(Distribution));
s1
.name("Stat01")
@@ -163,7 +159,7 @@ main(int argc, char *argv[])
s3
.name("Stat03")
.desc("this is statistic 3")
- .prereq(f7)
+ .prereq(f5)
;
s4
@@ -173,6 +169,7 @@ main(int argc, char *argv[])
;
s5
+ .init(5)
.name("Stat05")
.desc("this is statistic 5")
.prereq(s11)
@@ -184,12 +181,14 @@ main(int argc, char *argv[])
;
s6
+ .init(1, 100, 13)
.name("Stat06")
.desc("this is statistic 6")
.prereq(s11)
;
s7
+ .init(7)
.name("Stat07")
.desc("this is statistic 7")
.precision(1)
@@ -198,6 +197,7 @@ main(int argc, char *argv[])
;
s8
+ .init(10)
.name("Stat08")
.desc("this is statistic 8")
.precision(2)
@@ -219,26 +219,31 @@ main(int argc, char *argv[])
;
s12
+ .init(1, 100, 13)
.name("Stat12")
.desc("this is statistic 12")
;
s13
+ .init(4, 0, 99, 10)
.name("Stat13")
.desc("this is statistic 13")
;
s14
+ .init(9)
.name("Stat14")
.desc("this is statistic 14")
;
s15
+ .init(10)
.name("Stat15")
.desc("this is statistic 15")
;
s16
+ .init(2, 9)
.name("Stat16")
.desc("this is statistic 16")
.flags(total)
@@ -248,6 +253,20 @@ main(int argc, char *argv[])
.ysubname(1, "y1")
;
+ s17
+ .functor(testfunc)
+ .name("Stat17")
+ .desc("this is stat 17")
+ ;
+
+ TestClass testclass;
+ s18
+ .functor(testclass)
+ .name("Stat18")
+ .desc("this is stat 18")
+ ;
+
+
f1
.name("Formula1")
.desc("this is formula 1")
@@ -273,29 +292,17 @@ main(int argc, char *argv[])
;
f4
- .functor(testfunc)
.name("Formula4")
.desc("this is formula 4")
;
- TestClass testclass;
- f5
- .functor(testclass)
- .name("Formula5")
- .desc("this is formula 5")
- ;
-
- f6
- .name("Formula6")
- .desc("this is formula 6")
- ;
f1 = s1 + s2;
f2 = (-s1) / (-s2) * (-s3 + ULL(100) + s4);
f3 = sum(s5) * s7;
- f6 += constant(10.0);
- f6 += s5[3];
- f7 = constant(1);
+ f4 += constant(10.0);
+ f4 += s5[3];
+ f5 = constant(1);
check();
reset();
@@ -545,12 +552,14 @@ main(int argc, char *argv[])
out();
}
+#if USE_MYSQL
if (!mysql_name.empty()) {
MySql out;
- out.connect(mysql_host, mysql_user, mysql_passwd, "m5stats",
+ out.connect(mysql_host, mysql_db, mysql_user, mysql_passwd, "test",
mysql_name, "test");
out();
}
+#endif
return 0;
}
diff --git a/src/unittest/strnumtest.cc b/src/unittest/strnumtest.cc
index ea28e35df..0e234884d 100644
--- a/src/unittest/strnumtest.cc
+++ b/src/unittest/strnumtest.cc
@@ -28,8 +28,7 @@
* Authors: Nathan Binkert
*/
-#include <iostream.h>
-
+#include <iostream>
#include <string>
#include <vector>
@@ -40,39 +39,39 @@ using namespace std;
int
main(int argc, char *argv[])
{
- if (argc != 2) {
- cout << "Usage: " << argv[0] << " <number>\n";
- exit(1);
- }
+ if (argc != 2) {
+ cout << "Usage: " << argv[0] << " <number>\n";
+ exit(1);
+ }
- string s = argv[1];
+ string s = argv[1];
#define OUTVAL(valtype, type) do { \
- valtype value; \
- cout << "TYPE = " #valtype "\n"; \
- if (to_number(s, value)) { \
- cout << "Number(" << s << ") = " << dec \
- << (unsigned long long)(unsigned type)value << "\n" \
- << "Number(" << s << ") = " << dec \
- << (signed long long)(signed type)value << "\n" \
- << "Number(" << s << ") = 0x" << hex \
- << (unsigned long long)(unsigned type)value << "\n" \
- << "Number(" << s << ") = 0" << oct \
- << (unsigned long long)(unsigned type)value << "\n\n"; \
- } else \
- cout << "Number(" << s << ") is invalid\n\n"; \
- } while (0)
+ valtype value; \
+ cout << "TYPE = " #valtype "\n"; \
+ if (to_number(s, value)) { \
+ cout << "Number(" << s << ") = " << dec \
+ << (unsigned long long)(unsigned type)value << "\n" \
+ << "Number(" << s << ") = " << dec \
+ << (signed long long)(signed type)value << "\n" \
+ << "Number(" << s << ") = 0x" << hex \
+ << (unsigned long long)(unsigned type)value << "\n" \
+ << "Number(" << s << ") = 0" << oct \
+ << (unsigned long long)(unsigned type)value << "\n\n"; \
+ } else \
+ cout << "Number(" << s << ") is invalid\n\n"; \
+ } while (0)
- OUTVAL(signed long long, long long);
- OUTVAL(unsigned long long, long long);
- OUTVAL(signed long, long);
- OUTVAL(unsigned long, long);
- OUTVAL(signed int, int);
- OUTVAL(unsigned int, int);
- OUTVAL(signed short, short);
- OUTVAL(unsigned short, short);
- OUTVAL(signed char, char);
- OUTVAL(unsigned char, char);
+ OUTVAL(signed long long, long long);
+ OUTVAL(unsigned long long, long long);
+ OUTVAL(signed long, long);
+ OUTVAL(unsigned long, long);
+ OUTVAL(signed int, int);
+ OUTVAL(unsigned int, int);
+ OUTVAL(signed short, short);
+ OUTVAL(unsigned short, short);
+ OUTVAL(signed char, char);
+ OUTVAL(unsigned char, char);
- return 0;
+ return 0;
}
diff --git a/src/unittest/symtest.cc b/src/unittest/symtest.cc
index f0142b923..10ffb42e5 100644
--- a/src/unittest/symtest.cc
+++ b/src/unittest/symtest.cc
@@ -28,12 +28,12 @@
* Authors: Nathan Binkert
*/
-#include <iostream.h>
+#include <iostream>
#include "base/str.hh"
#include "base/loader/symtab.hh"
-Tick curTick = 0;
+using namespace std;
void
usage(const char *progname)