summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/SConscript130
-rw-r--r--src/arch/SConscript15
-rw-r--r--src/arch/alpha/SConscript3
-rw-r--r--src/arch/alpha/aout_machdep.h3
-rw-r--r--src/arch/alpha/arguments.cc14
-rw-r--r--src/arch/alpha/arguments.hh22
-rw-r--r--src/arch/alpha/ev5.cc96
-rw-r--r--src/arch/alpha/ev5.hh4
-rw-r--r--src/arch/alpha/faults.cc88
-rw-r--r--src/arch/alpha/faults.hh34
-rw-r--r--src/arch/alpha/freebsd/system.cc28
-rw-r--r--src/arch/alpha/freebsd/system.hh6
-rw-r--r--src/arch/alpha/isa/branch.isa15
-rw-r--r--src/arch/alpha/isa/decoder.isa85
-rw-r--r--src/arch/alpha/isa/fp.isa11
-rw-r--r--src/arch/alpha/isa/int.isa7
-rw-r--r--src/arch/alpha/isa/main.isa16
-rw-r--r--src/arch/alpha/isa/mem.isa8
-rw-r--r--src/arch/alpha/isa/opcdec.isa7
-rw-r--r--src/arch/alpha/isa/pal.isa13
-rw-r--r--src/arch/alpha/isa/unimp.isa7
-rw-r--r--src/arch/alpha/isa/unknown.isa7
-rw-r--r--src/arch/alpha/isa/util.isa7
-rw-r--r--src/arch/alpha/isa_traits.hh3
-rw-r--r--src/arch/alpha/linux/aligned.hh3
-rw-r--r--src/arch/alpha/linux/linux.cc2
-rw-r--r--src/arch/alpha/linux/linux.hh2
-rw-r--r--src/arch/alpha/linux/process.cc31
-rw-r--r--src/arch/alpha/linux/process.hh2
-rw-r--r--src/arch/alpha/linux/system.cc61
-rw-r--r--src/arch/alpha/linux/system.hh26
-rw-r--r--src/arch/alpha/linux/thread_info.hh3
-rw-r--r--src/arch/alpha/linux/threadinfo.hh15
-rw-r--r--src/arch/alpha/osfpal.cc2
-rw-r--r--src/arch/alpha/osfpal.hh2
-rw-r--r--src/arch/alpha/process.cc104
-rw-r--r--src/arch/alpha/process.hh15
-rw-r--r--src/arch/alpha/regfile.hh42
-rw-r--r--src/arch/alpha/stacktrace.cc106
-rw-r--r--src/arch/alpha/stacktrace.hh24
-rw-r--r--src/arch/alpha/system.cc15
-rw-r--r--src/arch/alpha/system.hh3
-rw-r--r--src/arch/alpha/tlb.cc30
-rw-r--r--src/arch/alpha/tlb.hh9
-rw-r--r--src/arch/alpha/tru64/process.cc65
-rw-r--r--src/arch/alpha/tru64/process.hh2
-rw-r--r--src/arch/alpha/tru64/system.cc15
-rw-r--r--src/arch/alpha/tru64/system.hh5
-rw-r--r--src/arch/alpha/tru64/tru64.cc2
-rw-r--r--src/arch/alpha/tru64/tru64.hh2
-rw-r--r--src/arch/alpha/types.hh3
-rw-r--r--src/arch/alpha/utility.hh19
-rw-r--r--src/arch/alpha/vtophys.cc36
-rw-r--r--src/arch/alpha/vtophys.hh15
-rwxr-xr-xsrc/arch/isa_parser.py8
-rw-r--r--src/arch/isa_specific.hh2
-rw-r--r--src/arch/mips/SConscript12
-rw-r--r--src/arch/mips/faults.cc57
-rw-r--r--src/arch/mips/faults.hh30
-rw-r--r--src/arch/mips/isa/base.isa43
-rw-r--r--src/arch/mips/isa/bitfields.isa47
-rw-r--r--src/arch/mips/isa/decoder.isa1639
-rw-r--r--src/arch/mips/isa/formats/basic.isa33
-rw-r--r--src/arch/mips/isa/formats/branch.isa188
-rw-r--r--src/arch/mips/isa/formats/control.isa156
-rw-r--r--src/arch/mips/isa/formats/formats.isa35
-rw-r--r--src/arch/mips/isa/formats/fp.isa364
-rw-r--r--src/arch/mips/isa/formats/int.isa183
-rw-r--r--src/arch/mips/isa/formats/mem.isa183
-rw-r--r--src/arch/mips/isa/formats/mt.isa82
-rw-r--r--src/arch/mips/isa/formats/noop.isa67
-rw-r--r--src/arch/mips/isa/formats/tlbop.isa35
-rw-r--r--src/arch/mips/isa/formats/trap.isa43
-rw-r--r--src/arch/mips/isa/formats/unimp.isa41
-rw-r--r--src/arch/mips/isa/formats/unknown.isa48
-rw-r--r--src/arch/mips/isa/formats/util.isa54
-rw-r--r--src/arch/mips/isa/includes.isa35
-rw-r--r--src/arch/mips/isa/main.isa11
-rw-r--r--src/arch/mips/isa/operands.isa44
-rw-r--r--src/arch/mips/isa_traits.cc151
-rw-r--r--src/arch/mips/isa_traits.hh32
-rw-r--r--src/arch/mips/linux/process.cc48
-rw-r--r--src/arch/mips/process.cc120
-rw-r--r--src/arch/mips/process.hh16
-rw-r--r--src/arch/mips/regfile/float_regfile.hh55
-rw-r--r--src/arch/mips/regfile/int_regfile.hh11
-rw-r--r--src/arch/mips/regfile/misc_regfile.hh29
-rw-r--r--src/arch/mips/regfile/regfile.hh39
-rw-r--r--src/arch/mips/stacktrace.hh30
-rw-r--r--src/arch/mips/types.hh9
-rw-r--r--src/arch/mips/utility.cc202
-rw-r--r--src/arch/mips/utility.hh13
-rw-r--r--src/arch/sparc/SConscript9
-rw-r--r--src/arch/sparc/faults.cc59
-rw-r--r--src/arch/sparc/faults.hh33
-rw-r--r--src/arch/sparc/isa/decoder.isa198
-rw-r--r--src/arch/sparc/isa/formats/integerop.isa48
-rw-r--r--src/arch/sparc/isa/formats/priv.isa48
-rw-r--r--src/arch/sparc/isa/includes.isa2
-rw-r--r--src/arch/sparc/isa/main.isa9
-rw-r--r--src/arch/sparc/isa/operands.isa83
-rw-r--r--src/arch/sparc/isa_traits.hh16
-rw-r--r--src/arch/sparc/linux/linux.cc2
-rw-r--r--src/arch/sparc/linux/linux.hh2
-rw-r--r--src/arch/sparc/linux/process.cc26
-rw-r--r--src/arch/sparc/linux/process.hh4
-rw-r--r--src/arch/sparc/process.cc146
-rw-r--r--src/arch/sparc/process.hh12
-rw-r--r--src/arch/sparc/regfile.hh523
-rw-r--r--src/arch/sparc/solaris/process.cc10
-rw-r--r--src/arch/sparc/solaris/process.hh2
-rw-r--r--src/arch/sparc/solaris/solaris.cc2
-rw-r--r--src/arch/sparc/solaris/solaris.hh2
-rw-r--r--src/arch/sparc/stacktrace.hh24
-rw-r--r--src/arch/sparc/system.cc5
-rw-r--r--src/arch/sparc/system.hh7
-rw-r--r--src/arch/sparc/tlb.hh35
-rw-r--r--src/arch/sparc/ua2005.cc224
-rw-r--r--src/arch/sparc/utility.hh8
-rw-r--r--src/arch/sparc/vtophys.cc166
-rw-r--r--src/arch/sparc/vtophys.hh55
-rw-r--r--src/base/bitfield.hh3
-rw-r--r--src/base/callback.hh2
-rw-r--r--src/base/chunk_generator.hh2
-rw-r--r--src/base/circlebuf.cc2
-rw-r--r--src/base/circlebuf.hh2
-rw-r--r--src/base/compression/lzss_compression.cc2
-rw-r--r--src/base/compression/lzss_compression.hh2
-rw-r--r--src/base/compression/null_compression.hh3
-rw-r--r--src/base/cprintf.cc2
-rw-r--r--src/base/cprintf.hh3
-rw-r--r--src/base/cprintf_formats.hh2
-rw-r--r--src/base/crc.hh2
-rw-r--r--src/base/date.cc2
-rw-r--r--src/base/dbl_list.hh2
-rw-r--r--src/base/endian.hh2
-rw-r--r--src/base/fast_alloc.cc4
-rw-r--r--src/base/fast_alloc.hh2
-rw-r--r--src/base/fenv.hh2
-rw-r--r--src/base/fifo_buffer.cc3
-rw-r--r--src/base/fifo_buffer.hh3
-rw-r--r--src/base/hashmap.hh2
-rw-r--r--src/base/hostinfo.cc2
-rw-r--r--src/base/hostinfo.hh2
-rw-r--r--src/base/hybrid_pred.cc3
-rw-r--r--src/base/hybrid_pred.hh3
-rw-r--r--src/base/inet.cc2
-rw-r--r--src/base/inet.hh3
-rw-r--r--src/base/inifile.cc3
-rw-r--r--src/base/inifile.hh3
-rw-r--r--src/base/intmath.cc3
-rw-r--r--src/base/intmath.hh2
-rw-r--r--src/base/loader/aout_object.cc2
-rw-r--r--src/base/loader/aout_object.hh2
-rw-r--r--src/base/loader/ecoff_object.cc2
-rw-r--r--src/base/loader/ecoff_object.hh2
-rw-r--r--src/base/loader/elf_object.cc3
-rw-r--r--src/base/loader/elf_object.hh2
-rw-r--r--src/base/loader/object_file.cc3
-rw-r--r--src/base/loader/object_file.hh3
-rw-r--r--src/base/loader/symtab.cc2
-rw-r--r--src/base/loader/symtab.hh5
-rw-r--r--src/base/match.cc2
-rw-r--r--src/base/match.hh2
-rw-r--r--src/base/misc.cc2
-rw-r--r--src/base/misc.hh3
-rw-r--r--src/base/mod_num.hh2
-rw-r--r--src/base/mysql.cc2
-rw-r--r--src/base/mysql.hh2
-rw-r--r--src/base/output.cc2
-rw-r--r--src/base/output.hh2
-rw-r--r--src/base/pollevent.cc2
-rw-r--r--src/base/pollevent.hh2
-rw-r--r--src/base/predictor.hh3
-rw-r--r--src/base/random.cc3
-rw-r--r--src/base/random.hh3
-rw-r--r--src/base/range.cc2
-rw-r--r--src/base/range.hh3
-rw-r--r--src/base/refcnt.hh2
-rw-r--r--src/base/remote_gdb.cc19
-rw-r--r--src/base/remote_gdb.hh12
-rw-r--r--src/base/res_list.hh3
-rw-r--r--src/base/sat_counter.cc3
-rw-r--r--src/base/sat_counter.hh3
-rw-r--r--src/base/sched_list.hh2
-rw-r--r--src/base/socket.cc2
-rw-r--r--src/base/socket.hh2
-rw-r--r--src/base/statistics.cc70
-rw-r--r--src/base/statistics.hh1167
-rw-r--r--src/base/stats/events.cc2
-rw-r--r--src/base/stats/events.hh2
-rw-r--r--src/base/stats/flags.hh2
-rw-r--r--src/base/stats/mysql.cc98
-rw-r--r--src/base/stats/mysql.hh5
-rw-r--r--src/base/stats/mysql_run.hh2
-rw-r--r--src/base/stats/output.hh2
-rw-r--r--src/base/stats/statdb.cc14
-rw-r--r--src/base/stats/statdb.hh8
-rw-r--r--src/base/stats/text.cc22
-rw-r--r--src/base/stats/text.hh3
-rw-r--r--src/base/stats/types.hh2
-rw-r--r--src/base/stats/visit.cc2
-rw-r--r--src/base/stats/visit.hh2
-rw-r--r--src/base/str.cc2
-rw-r--r--src/base/str.hh3
-rw-r--r--src/base/time.cc2
-rw-r--r--src/base/time.hh3
-rw-r--r--src/base/timebuf.hh3
-rw-r--r--src/base/trace.cc8
-rw-r--r--src/base/trace.hh3
-rw-r--r--src/base/traceflags.py22
-rw-r--r--src/base/userinfo.cc2
-rw-r--r--src/base/userinfo.hh2
-rw-r--r--src/cpu/SConscript75
-rw-r--r--src/cpu/activity.cc157
-rw-r--r--src/cpu/activity.hh126
-rw-r--r--src/cpu/base.cc89
-rw-r--r--src/cpu/base.hh20
-rw-r--r--src/cpu/base_dyn_inst.cc364
-rw-r--r--src/cpu/base_dyn_inst.hh501
-rw-r--r--src/cpu/base_dyn_inst_impl.hh299
-rw-r--r--src/cpu/checker/cpu.cc408
-rw-r--r--src/cpu/checker/cpu.hh402
-rw-r--r--src/cpu/checker/cpu_impl.hh460
-rw-r--r--src/cpu/checker/thread_context.hh306
-rw-r--r--src/cpu/cpu_models.py33
-rw-r--r--src/cpu/cpuevent.cc61
-rw-r--r--src/cpu/cpuevent.hh89
-rw-r--r--src/cpu/exec_context.hh545
-rw-r--r--src/cpu/exetrace.cc11
-rw-r--r--src/cpu/exetrace.hh12
-rw-r--r--src/cpu/func_unit.cc171
-rw-r--r--src/cpu/func_unit.hh101
-rw-r--r--src/cpu/inst_seq.hh5
-rw-r--r--src/cpu/intr_control.cc21
-rw-r--r--src/cpu/intr_control.hh3
-rw-r--r--src/cpu/memtest/memtest.cc9
-rw-r--r--src/cpu/memtest/memtest.hh7
-rw-r--r--src/cpu/o3/2bit_local_pred.cc57
-rw-r--r--src/cpu/o3/2bit_local_pred.hh49
-rwxr-xr-xsrc/cpu/o3/SConscript79
-rw-r--r--src/cpu/o3/alpha/cpu.cc (renamed from src/cpu/o3/alpha_cpu.cc)12
-rw-r--r--src/cpu/o3/alpha/cpu.hh204
-rw-r--r--src/cpu/o3/alpha/cpu_builder.cc (renamed from src/cpu/o3/alpha_cpu_builder.cc)348
-rw-r--r--src/cpu/o3/alpha/cpu_impl.hh422
-rw-r--r--src/cpu/o3/alpha/dyn_inst.cc (renamed from src/cpu/o3/alpha_dyn_inst.cc)6
-rw-r--r--src/cpu/o3/alpha/dyn_inst.hh (renamed from src/cpu/o3/alpha_dyn_inst.hh)107
-rw-r--r--src/cpu/o3/alpha/dyn_inst_impl.hh (renamed from src/cpu/o3/alpha_dyn_inst_impl.hh)108
-rw-r--r--src/cpu/o3/alpha/impl.hh (renamed from src/cpu/o3/alpha_impl.hh)39
-rw-r--r--src/cpu/o3/alpha/params.hh69
-rwxr-xr-xsrc/cpu/o3/alpha/thread_context.cc36
-rw-r--r--src/cpu/o3/alpha/thread_context.hh87
-rw-r--r--src/cpu/o3/alpha_cpu.hh291
-rw-r--r--src/cpu/o3/alpha_cpu_impl.hh371
-rw-r--r--src/cpu/o3/base_dyn_inst.cc39
-rw-r--r--src/cpu/o3/bpred_unit.cc9
-rw-r--r--src/cpu/o3/bpred_unit.hh197
-rw-r--r--src/cpu/o3/bpred_unit_impl.hh306
-rw-r--r--src/cpu/o3/btb.cc36
-rw-r--r--src/cpu/o3/btb.hh68
-rw-r--r--src/cpu/o3/checker_builder.cc157
-rw-r--r--src/cpu/o3/comm.hh111
-rw-r--r--src/cpu/o3/commit.cc7
-rw-r--r--src/cpu/o3/commit.hh385
-rw-r--r--src/cpu/o3/commit_impl.hh1219
-rw-r--r--src/cpu/o3/cpu.cc1089
-rw-r--r--src/cpu/o3/cpu.hh488
-rw-r--r--src/cpu/o3/cpu_policy.hh63
-rw-r--r--src/cpu/o3/decode.cc7
-rw-r--r--src/cpu/o3/decode.hh186
-rw-r--r--src/cpu/o3/decode_impl.hh728
-rw-r--r--src/cpu/o3/dep_graph.hh272
-rw-r--r--src/cpu/o3/fetch.cc7
-rw-r--r--src/cpu/o3/fetch.hh343
-rw-r--r--src/cpu/o3/fetch_impl.hh1226
-rw-r--r--src/cpu/o3/free_list.cc38
-rw-r--r--src/cpu/o3/free_list.hh85
-rw-r--r--src/cpu/o3/fu_pool.cc299
-rw-r--r--src/cpu/o3/fu_pool.hh167
-rw-r--r--src/cpu/o3/iew.cc7
-rw-r--r--src/cpu/o3/iew.hh385
-rw-r--r--src/cpu/o3/iew_impl.hh1579
-rw-r--r--src/cpu/o3/inst_queue.cc11
-rw-r--r--src/cpu/o3/inst_queue.hh464
-rw-r--r--src/cpu/o3/inst_queue_impl.hh1489
-rwxr-xr-xsrc/cpu/o3/isa_specific.hh40
-rw-r--r--src/cpu/o3/lsq.cc36
-rw-r--r--src/cpu/o3/lsq.hh321
-rw-r--r--src/cpu/o3/lsq_impl.hh539
-rw-r--r--src/cpu/o3/lsq_unit.cc37
-rw-r--r--src/cpu/o3/lsq_unit.hh727
-rw-r--r--src/cpu/o3/lsq_unit_impl.hh986
-rw-r--r--src/cpu/o3/mem_dep_unit.cc21
-rw-r--r--src/cpu/o3/mem_dep_unit.hh240
-rw-r--r--src/cpu/o3/mem_dep_unit_impl.hh570
-rwxr-xr-x[-rw-r--r--]src/cpu/o3/params.hh (renamed from src/cpu/o3/alpha_params.hh)88
-rw-r--r--src/cpu/o3/ras.cc25
-rw-r--r--src/cpu/o3/ras.hh39
-rw-r--r--src/cpu/o3/regfile.hh163
-rw-r--r--src/cpu/o3/rename.cc7
-rw-r--r--src/cpu/o3/rename.hh371
-rw-r--r--src/cpu/o3/rename_impl.hh1432
-rw-r--r--src/cpu/o3/rename_map.cc281
-rw-r--r--src/cpu/o3/rename_map.hh69
-rw-r--r--src/cpu/o3/rob.cc8
-rw-r--r--src/cpu/o3/rob.hh244
-rw-r--r--src/cpu/o3/rob_impl.hh626
-rw-r--r--src/cpu/o3/sat_counter.cc28
-rw-r--r--src/cpu/o3/sat_counter.hh52
-rw-r--r--src/cpu/o3/scoreboard.cc109
-rw-r--r--src/cpu/o3/scoreboard.hh117
-rw-r--r--src/cpu/o3/store_set.cc180
-rw-r--r--src/cpu/o3/store_set.hh89
-rwxr-xr-xsrc/cpu/o3/thread_context.hh250
-rwxr-xr-xsrc/cpu/o3/thread_context_impl.hh489
-rw-r--r--src/cpu/o3/thread_state.hh102
-rw-r--r--src/cpu/o3/tournament_pred.cc279
-rw-r--r--src/cpu/o3/tournament_pred.hh127
-rw-r--r--src/cpu/op_class.cc2
-rw-r--r--src/cpu/op_class.hh5
-rw-r--r--src/cpu/ozone/back_end.cc34
-rw-r--r--src/cpu/ozone/back_end.hh543
-rw-r--r--src/cpu/ozone/back_end_impl.hh1933
-rw-r--r--src/cpu/ozone/base_dyn_inst.cc39
-rw-r--r--src/cpu/ozone/bpred_unit.cc36
-rw-r--r--src/cpu/ozone/checker_builder.cc158
-rw-r--r--src/cpu/ozone/cpu.cc12
-rw-r--r--src/cpu/ozone/cpu.hh789
-rw-r--r--src/cpu/ozone/cpu_builder.cc451
-rw-r--r--src/cpu/ozone/cpu_impl.hh1105
-rw-r--r--src/cpu/ozone/dyn_inst.cc37
-rw-r--r--src/cpu/ozone/dyn_inst.hh253
-rw-r--r--src/cpu/ozone/dyn_inst_impl.hh307
-rw-r--r--src/cpu/ozone/ea_list.cc3
-rw-r--r--src/cpu/ozone/ea_list.hh3
-rw-r--r--src/cpu/ozone/front_end.cc36
-rw-r--r--src/cpu/ozone/front_end.hh318
-rw-r--r--src/cpu/ozone/front_end_impl.hh976
-rw-r--r--src/cpu/ozone/inorder_back_end.cc34
-rw-r--r--src/cpu/ozone/inorder_back_end.hh478
-rw-r--r--src/cpu/ozone/inorder_back_end_impl.hh548
-rw-r--r--src/cpu/ozone/inst_queue.cc38
-rw-r--r--src/cpu/ozone/inst_queue.hh508
-rw-r--r--src/cpu/ozone/inst_queue_impl.hh1343
-rw-r--r--src/cpu/ozone/lsq_unit.cc36
-rw-r--r--src/cpu/ozone/lsq_unit.hh636
-rw-r--r--src/cpu/ozone/lsq_unit_impl.hh840
-rw-r--r--src/cpu/ozone/lw_back_end.cc34
-rw-r--r--src/cpu/ozone/lw_back_end.hh431
-rw-r--r--src/cpu/ozone/lw_back_end_impl.hh1626
-rw-r--r--src/cpu/ozone/lw_lsq.cc36
-rw-r--r--src/cpu/ozone/lw_lsq.hh703
-rw-r--r--src/cpu/ozone/lw_lsq_impl.hh973
-rw-r--r--src/cpu/ozone/null_predictor.hh105
-rw-r--r--src/cpu/ozone/ozone_base_dyn_inst.cc39
-rw-r--r--src/cpu/ozone/ozone_impl.hh75
-rw-r--r--src/cpu/ozone/rename_table.cc36
-rw-r--r--src/cpu/ozone/rename_table.hh55
-rw-r--r--src/cpu/ozone/rename_table_impl.hh52
-rw-r--r--src/cpu/ozone/simple_base_dyn_inst.cc39
-rw-r--r--src/cpu/ozone/simple_cpu_builder.cc452
-rw-r--r--src/cpu/ozone/simple_impl.hh71
-rw-r--r--src/cpu/ozone/simple_params.hh192
-rw-r--r--src/cpu/ozone/thread_state.hh134
-rw-r--r--src/cpu/pc_event.cc17
-rw-r--r--src/cpu/pc_event.hh15
-rw-r--r--src/cpu/profile.cc6
-rw-r--r--src/cpu/profile.hh12
-rw-r--r--src/cpu/quiesce_event.cc49
-rw-r--r--src/cpu/quiesce_event.hh53
-rw-r--r--src/cpu/simple/atomic.cc103
-rw-r--r--src/cpu/simple/atomic.hh8
-rw-r--r--src/cpu/simple/base.cc151
-rw-r--r--src/cpu/simple/base.hh77
-rw-r--r--src/cpu/simple/timing.cc135
-rw-r--r--src/cpu/simple/timing.hh16
-rw-r--r--src/cpu/simple_thread.cc (renamed from src/cpu/cpu_exec_context.cc)213
-rw-r--r--src/cpu/simple_thread.hh (renamed from src/cpu/cpu_exec_context.hh)291
-rw-r--r--src/cpu/smt.hh2
-rw-r--r--src/cpu/static_inst.cc7
-rw-r--r--src/cpu/static_inst.hh42
-rw-r--r--src/cpu/thread_context.hh448
-rw-r--r--src/cpu/thread_state.cc68
-rw-r--r--src/cpu/thread_state.hh220
-rw-r--r--src/cpu/trace/opt_cpu.cc4
-rw-r--r--src/cpu/trace/opt_cpu.hh2
-rw-r--r--src/cpu/trace/reader/ibm_reader.cc2
-rw-r--r--src/cpu/trace/reader/ibm_reader.hh2
-rw-r--r--src/cpu/trace/reader/itx_reader.cc2
-rw-r--r--src/cpu/trace/reader/itx_reader.hh2
-rw-r--r--src/cpu/trace/reader/m5_reader.cc2
-rw-r--r--src/cpu/trace/reader/m5_reader.hh2
-rw-r--r--src/cpu/trace/reader/mem_trace_reader.cc2
-rw-r--r--src/cpu/trace/reader/mem_trace_reader.hh2
-rw-r--r--src/cpu/trace/trace_cpu.cc4
-rw-r--r--src/cpu/trace/trace_cpu.hh2
-rw-r--r--src/dev/alpha_access.h2
-rw-r--r--src/dev/alpha_console.cc10
-rw-r--r--src/dev/alpha_console.hh2
-rw-r--r--src/dev/baddev.cc2
-rw-r--r--src/dev/baddev.hh2
-rw-r--r--src/dev/disk_image.cc2
-rw-r--r--src/dev/disk_image.hh2
-rw-r--r--src/dev/etherbus.cc2
-rw-r--r--src/dev/etherbus.hh2
-rw-r--r--src/dev/etherdump.cc2
-rw-r--r--src/dev/etherdump.hh2
-rw-r--r--src/dev/etherint.cc2
-rw-r--r--src/dev/etherint.hh2
-rw-r--r--src/dev/etherlink.cc3
-rw-r--r--src/dev/etherlink.hh2
-rw-r--r--src/dev/etherpkt.cc2
-rw-r--r--src/dev/etherpkt.hh3
-rw-r--r--src/dev/ethertap.cc2
-rw-r--r--src/dev/ethertap.hh2
-rw-r--r--src/dev/ide_ctrl.cc7
-rw-r--r--src/dev/ide_ctrl.hh3
-rw-r--r--src/dev/ide_disk.cc3
-rw-r--r--src/dev/ide_disk.hh2
-rw-r--r--src/dev/io_device.cc127
-rw-r--r--src/dev/io_device.hh64
-rw-r--r--src/dev/isa_fake.cc6
-rw-r--r--src/dev/isa_fake.hh3
-rw-r--r--src/dev/ns_gige.cc8
-rw-r--r--src/dev/ns_gige.hh3
-rw-r--r--src/dev/ns_gige_reg.h2
-rw-r--r--src/dev/pciconfigall.cc6
-rw-r--r--src/dev/pciconfigall.hh3
-rw-r--r--src/dev/pcidev.cc4
-rw-r--r--src/dev/pcidev.hh4
-rw-r--r--src/dev/pcireg.h3
-rw-r--r--src/dev/pitreg.h2
-rw-r--r--src/dev/pktfifo.cc2
-rw-r--r--src/dev/pktfifo.hh2
-rw-r--r--src/dev/platform.cc3
-rw-r--r--src/dev/platform.hh3
-rw-r--r--src/dev/rtcreg.h4
-rw-r--r--src/dev/simconsole.cc30
-rw-r--r--src/dev/simconsole.hh5
-rw-r--r--src/dev/simple_disk.cc2
-rw-r--r--src/dev/simple_disk.hh2
-rw-r--r--src/dev/sinic.cc7
-rw-r--r--src/dev/sinic.hh2
-rw-r--r--src/dev/sinicreg.hh2
-rw-r--r--src/dev/tsunami.cc2
-rw-r--r--src/dev/tsunami.hh2
-rw-r--r--src/dev/tsunami_cchip.cc21
-rw-r--r--src/dev/tsunami_cchip.hh2
-rw-r--r--src/dev/tsunami_io.cc45
-rw-r--r--src/dev/tsunami_io.hh8
-rw-r--r--src/dev/tsunami_pchip.cc7
-rw-r--r--src/dev/tsunami_pchip.hh2
-rw-r--r--src/dev/tsunamireg.h2
-rw-r--r--src/dev/uart.cc2
-rw-r--r--src/dev/uart.hh2
-rw-r--r--src/dev/uart8250.cc6
-rw-r--r--src/dev/uart8250.hh2
-rw-r--r--src/kern/kernel_stats.cc43
-rw-r--r--src/kern/kernel_stats.hh95
-rw-r--r--src/kern/linux/events.cc13
-rw-r--r--src/kern/linux/events.hh5
-rw-r--r--src/kern/linux/linux.hh6
-rw-r--r--src/kern/linux/linux_syscalls.cc2
-rw-r--r--src/kern/linux/linux_syscalls.hh2
-rw-r--r--src/kern/linux/printk.cc3
-rw-r--r--src/kern/linux/printk.hh3
-rw-r--r--src/kern/linux/sched.hh3
-rw-r--r--src/kern/solaris/solaris.hh6
-rw-r--r--src/kern/system_events.cc56
-rw-r--r--src/kern/system_events.hh40
-rw-r--r--src/kern/tru64/dump_mbuf.cc14
-rw-r--r--src/kern/tru64/dump_mbuf.hh2
-rw-r--r--src/kern/tru64/mbuf.hh2
-rw-r--r--src/kern/tru64/printf.cc2
-rw-r--r--src/kern/tru64/printf.hh2
-rw-r--r--src/kern/tru64/tru64.hh225
-rw-r--r--src/kern/tru64/tru64_events.cc33
-rw-r--r--src/kern/tru64/tru64_events.hh13
-rw-r--r--src/kern/tru64/tru64_syscalls.cc2
-rw-r--r--src/kern/tru64/tru64_syscalls.hh2
-rw-r--r--src/mem/bridge.cc98
-rw-r--r--src/mem/bridge.hh11
-rw-r--r--src/mem/bus.cc32
-rw-r--r--src/mem/bus.hh18
-rw-r--r--src/mem/cache/base_cache.cc341
-rw-r--r--src/mem/cache/base_cache.hh505
-rw-r--r--src/mem/cache/cache.cc146
-rw-r--r--src/mem/cache/cache.hh279
-rw-r--r--src/mem/cache/cache_blk.hh198
-rw-r--r--src/mem/cache/cache_builder.cc480
-rw-r--r--src/mem/cache/cache_impl.hh660
-rw-r--r--src/mem/cache/coherence/coherence_protocol.cc567
-rw-r--r--src/mem/cache/coherence/coherence_protocol.hh263
-rw-r--r--src/mem/cache/coherence/simple_coherence.hh161
-rw-r--r--src/mem/cache/coherence/uni_coherence.cc86
-rw-r--r--src/mem/cache/coherence/uni_coherence.hh136
-rw-r--r--src/mem/cache/miss/blocking_buffer.cc245
-rw-r--r--src/mem/cache/miss/blocking_buffer.hh256
-rw-r--r--src/mem/cache/miss/miss_queue.cc757
-rw-r--r--src/mem/cache/miss/miss_queue.hh349
-rw-r--r--src/mem/cache/miss/mshr.cc181
-rw-r--r--src/mem/cache/miss/mshr.hh179
-rw-r--r--src/mem/cache/miss/mshr_queue.cc269
-rw-r--r--src/mem/cache/miss/mshr_queue.hh239
-rw-r--r--src/mem/cache/prefetch/base_prefetcher.cc249
-rw-r--r--src/mem/cache/prefetch/base_prefetcher.hh117
-rw-r--r--src/mem/cache/prefetch/ghb_prefetcher.cc54
-rw-r--r--src/mem/cache/prefetch/ghb_prefetcher.hh114
-rw-r--r--src/mem/cache/prefetch/stride_prefetcher.cc54
-rw-r--r--src/mem/cache/prefetch/stride_prefetcher.hh149
-rw-r--r--src/mem/cache/prefetch/tagged_prefetcher.hh71
-rw-r--r--src/mem/cache/prefetch/tagged_prefetcher_impl.hh6
-rw-r--r--src/mem/cache/tags/base_tags.cc91
-rw-r--r--src/mem/cache/tags/base_tags.hh143
-rw-r--r--src/mem/cache/tags/fa_lru.cc334
-rw-r--r--src/mem/cache/tags/fa_lru.hh346
-rw-r--r--src/mem/cache/tags/iic.cc880
-rw-r--r--src/mem/cache/tags/iic.hh574
-rw-r--r--src/mem/cache/tags/lru.cc310
-rw-r--r--src/mem/cache/tags/lru.hh327
-rw-r--r--src/mem/cache/tags/repl/gen.cc277
-rw-r--r--src/mem/cache/tags/repl/gen.hh247
-rw-r--r--src/mem/cache/tags/repl/repl.cc43
-rw-r--r--src/mem/cache/tags/repl/repl.hh129
-rw-r--r--src/mem/cache/tags/split.cc478
-rw-r--r--src/mem/cache/tags/split.hh335
-rw-r--r--src/mem/cache/tags/split_blk.hh68
-rw-r--r--src/mem/cache/tags/split_lifo.cc407
-rw-r--r--src/mem/cache/tags/split_lifo.hh350
-rw-r--r--src/mem/cache/tags/split_lru.cc333
-rw-r--r--src/mem/cache/tags/split_lru.hh333
-rw-r--r--src/mem/config/cache.hh42
-rw-r--r--src/mem/config/prefetch.hh2
-rw-r--r--src/mem/mem_object.cc2
-rw-r--r--src/mem/mem_object.hh4
-rw-r--r--src/mem/packet.cc30
-rw-r--r--src/mem/packet.hh245
-rw-r--r--src/mem/page_table.cc33
-rw-r--r--src/mem/page_table.hh13
-rw-r--r--src/mem/physical.cc9
-rw-r--r--src/mem/physical.hh4
-rw-r--r--src/mem/port.cc7
-rw-r--r--src/mem/port.hh54
-rw-r--r--src/mem/port_impl.hh53
-rw-r--r--src/mem/request.hh257
-rw-r--r--src/mem/translating_port.cc3
-rw-r--r--src/mem/translating_port.hh3
-rw-r--r--src/mem/vport.cc10
-rw-r--r--src/mem/vport.hh21
-rw-r--r--src/python/SConscript237
-rw-r--r--src/python/m5/__init__.py260
-rw-r--r--src/python/m5/config.py498
-rw-r--r--src/python/m5/convert.py2
-rw-r--r--src/python/m5/multidict.py26
-rw-r--r--src/python/m5/objects/AlphaConsole.py2
-rw-r--r--src/python/m5/objects/AlphaTLB.py2
-rw-r--r--src/python/m5/objects/BadDevice.py2
-rw-r--r--src/python/m5/objects/BaseCPU.py4
-rw-r--r--src/python/m5/objects/BaseCache.py14
-rw-r--r--src/python/m5/objects/Bridge.py4
-rw-r--r--src/python/m5/objects/Bus.py3
-rw-r--r--src/python/m5/objects/CoherenceProtocol.py2
-rw-r--r--src/python/m5/objects/Device.py4
-rw-r--r--src/python/m5/objects/DiskImage.py2
-rw-r--r--src/python/m5/objects/Ethernet.py3
-rw-r--r--src/python/m5/objects/FUPool.py5
-rw-r--r--src/python/m5/objects/FuncUnit.py17
-rw-r--r--src/python/m5/objects/Ide.py2
-rw-r--r--src/python/m5/objects/IntrControl.py2
-rw-r--r--src/python/m5/objects/MemObject.py2
-rw-r--r--src/python/m5/objects/MemTest.py2
-rw-r--r--src/python/m5/objects/O3CPU.py98
-rw-r--r--src/python/m5/objects/OzoneCPU.py88
-rw-r--r--src/python/m5/objects/Pci.py2
-rw-r--r--src/python/m5/objects/PhysicalMemory.py3
-rw-r--r--src/python/m5/objects/Platform.py2
-rw-r--r--src/python/m5/objects/Process.py2
-rw-r--r--src/python/m5/objects/Repl.py2
-rw-r--r--src/python/m5/objects/Root.py2
-rw-r--r--src/python/m5/objects/SimConsole.py2
-rw-r--r--src/python/m5/objects/SimpleDisk.py2
-rw-r--r--src/python/m5/objects/SimpleOzoneCPU.py (renamed from src/python/m5/objects/AlphaFullCPU.py)31
-rw-r--r--src/python/m5/objects/System.py5
-rw-r--r--src/python/m5/objects/Tsunami.py2
-rw-r--r--src/python/m5/objects/Uart.py3
-rw-r--r--src/python/m5/smartdict.py2
-rw-r--r--src/sim/async.hh3
-rw-r--r--src/sim/builder.cc24
-rw-r--r--src/sim/builder.hh28
-rw-r--r--src/sim/byteswap.hh50
-rw-r--r--src/sim/debug.cc7
-rw-r--r--src/sim/debug.hh2
-rw-r--r--src/sim/eventq.cc17
-rw-r--r--src/sim/eventq.hh11
-rw-r--r--src/sim/faults.cc19
-rw-r--r--src/sim/faults.hh13
-rw-r--r--src/sim/host.hh4
-rw-r--r--src/sim/main.cc563
-rw-r--r--src/sim/param.cc24
-rw-r--r--src/sim/param.hh12
-rw-r--r--src/sim/process.cc198
-rw-r--r--src/sim/process.hh40
-rw-r--r--src/sim/pseudo_inst.cc88
-rw-r--r--src/sim/pseudo_inst.hh38
-rw-r--r--src/sim/root.cc6
-rw-r--r--src/sim/serialize.cc130
-rw-r--r--src/sim/serialize.hh21
-rw-r--r--src/sim/sim_events.cc49
-rw-r--r--src/sim/sim_events.hh43
-rw-r--r--src/sim/sim_exit.hh20
-rw-r--r--src/sim/sim_object.cc69
-rw-r--r--src/sim/sim_object.hh32
-rw-r--r--src/sim/startup.cc3
-rw-r--r--src/sim/startup.hh2
-rw-r--r--src/sim/stat_control.cc5
-rw-r--r--src/sim/stat_control.hh2
-rw-r--r--src/sim/stats.hh2
-rw-r--r--src/sim/syscall_emul.cc188
-rw-r--r--src/sim/syscall_emul.hh208
-rw-r--r--src/sim/system.cc84
-rw-r--r--src/sim/system.hh21
-rw-r--r--src/sim/vptr.hh20
-rw-r--r--src/unittest/bitvectest.cc2
-rw-r--r--src/unittest/circletest.cc2
-rw-r--r--src/unittest/cprintftest.cc2
-rwxr-xr-xsrc/unittest/genini.py2
-rw-r--r--src/unittest/initest.cc3
-rw-r--r--src/unittest/lru_test.cc3
-rw-r--r--src/unittest/nmtest.cc2
-rw-r--r--src/unittest/offtest.cc2
-rw-r--r--src/unittest/paramtest.cc2
-rw-r--r--src/unittest/rangetest.cc2
-rw-r--r--src/unittest/sized_test.cc3
-rw-r--r--src/unittest/stattest.cc16
-rw-r--r--src/unittest/strnumtest.cc2
-rw-r--r--src/unittest/symtest.cc2
-rw-r--r--src/unittest/tokentest.cc2
-rw-r--r--src/unittest/tracetest.cc2
638 files changed, 59557 insertions, 13103 deletions
diff --git a/src/SConscript b/src/SConscript
index 558c447e9..0d0cb2486 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -25,6 +25,8 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
import os
import sys
@@ -46,9 +48,7 @@ Import('env')
base_sources = Split('''
base/circlebuf.cc
- base/copyright.cc
base/cprintf.cc
- base/embedfile.cc
base/fast_alloc.cc
base/fifo_buffer.cc
base/hostinfo.cc
@@ -62,7 +62,6 @@ base_sources = Split('''
base/range.cc
base/random.cc
base/sat_counter.cc
- base/serializer.cc
base/socket.cc
base/statistics.cc
base/str.cc
@@ -81,38 +80,62 @@ base_sources = Split('''
base/stats/visit.cc
base/stats/text.cc
+ cpu/activity.cc
cpu/base.cc
- cpu/cpu_exec_context.cc
+ cpu/cpuevent.cc
cpu/exetrace.cc
+ cpu/func_unit.cc
cpu/op_class.cc
cpu/pc_event.cc
+ cpu/quiesce_event.cc
cpu/static_inst.cc
cpu/sampler/sampler.cc
-
+ cpu/simple_thread.cc
+ cpu/thread_state.cc
+
mem/bridge.cc
mem/bus.cc
- mem/connector.cc
mem/mem_object.cc
mem/packet.cc
mem/physical.cc
mem/port.cc
- mem/request.cc
- python/pyconfig.cc
- python/embedded_py.cc
+ mem/cache/base_cache.cc
+ mem/cache/cache.cc
+ mem/cache/coherence/coherence_protocol.cc
+ mem/cache/coherence/uni_coherence.cc
+ mem/cache/miss/blocking_buffer.cc
+ mem/cache/miss/miss_queue.cc
+ mem/cache/miss/mshr.cc
+ mem/cache/miss/mshr_queue.cc
+ mem/cache/prefetch/base_prefetcher.cc
+ mem/cache/prefetch/ghb_prefetcher.cc
+ mem/cache/prefetch/prefetcher.cc
+ mem/cache/prefetch/stride_prefetcher.cc
+ mem/cache/prefetch/tagged_prefetcher.cc
+ mem/cache/tags/base_tags.cc
+ mem/cache/tags/cache_tags.cc
+ mem/cache/tags/fa_lru.cc
+ mem/cache/tags/iic.cc
+ mem/cache/tags/lru.cc
+ mem/cache/tags/repl/gen.cc
+ mem/cache/tags/repl/repl.cc
+ mem/cache/tags/split.cc
+ mem/cache/tags/split_lifo.cc
+ mem/cache/tags/split_lru.cc
+
+ mem/cache/cache_builder.cc
sim/builder.cc
- sim/configfile.cc
sim/debug.cc
sim/eventq.cc
sim/faults.cc
sim/main.cc
+ python/swig/cc_main_wrap.cc
sim/param.cc
- sim/profile.cc
sim/root.cc
sim/serialize.cc
sim/sim_events.cc
- sim/sim_exit.cc
sim/sim_object.cc
sim/startup.cc
sim/stat_context.cc
@@ -217,7 +240,6 @@ full_system_sources = Split('''
dev/uart.cc
dev/uart8250.cc
- kern/kernel_binning.cc
kern/kernel_stats.cc
kern/system_events.cc
kern/linux/events.cc
@@ -284,14 +306,18 @@ memtest_sources = Split('''
cpu/memtest/memtest.cc
''')
+# Include file paths are rooted in this directory. SCons will
+# automatically expand '.' to refer to both the source directory and
+# the corresponding build directory to pick up generated include
+# files.
+env.Append(CPPPATH=Dir('.'))
+
# Add a flag defining what THE_ISA should be for all compilation
env.Append(CPPDEFINES=[('THE_ISA','%s_ISA' % env['TARGET_ISA'].upper())])
-arch_sources = SConscript('arch/SConscript',
- exports = 'env', duplicate = False)
+arch_sources = SConscript('arch/SConscript', exports = 'env')
-cpu_sources = SConscript('cpu/SConscript',
- exports = 'env', duplicate = False)
+cpu_sources = SConscript('cpu/SConscript', exports = 'env')
# This is outside of cpu/SConscript since the source directory isn't
# underneath 'cpu'.
@@ -326,7 +352,7 @@ env.Command(Split('base/traceflags.hh base/traceflags.cc'),
'base/traceflags.py',
'python $SOURCE $TARGET.base')
-SConscript('python/SConscript', exports = ['env'], duplicate=0)
+SConscript('python/SConscript', exports = ['env'])
# This function adds the specified sources to the given build
# environment, and returns a list of all the corresponding SCons
@@ -349,49 +375,45 @@ def make_objs(sources, env):
#
###################################################
-# Include file paths are rooted in this directory. SCons will
-# automatically expand '.' to refer to both the source directory and
-# the corresponding build directory to pick up generated include
-# files.
-env.Append(CPPPATH='.')
+# List of constructed environments to pass back to SConstruct
+envList = []
+
+# Function to create a new build environment as clone of current
+# environment 'env' with modified object suffix and optional stripped
+# 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(sources, newEnv))
+ if strip:
+ stripped_bin = bin + '.stripped'
+ newEnv.Command(stripped_bin, bin, 'strip $SOURCE -o $TARGET')
+ bin = stripped_bin
+ targets = newEnv.Concat(exe, [bin, 'python/m5py.zip'])
+ newEnv.M5Binary = targets[0]
+ envList.append(newEnv)
# Debug binary
-debugEnv = env.Copy(OBJSUFFIX='.do')
-debugEnv.Label = 'debug'
-debugEnv.Append(CCFLAGS=Split('-g3 -gdwarf-2 -O0'))
-debugEnv.Append(CPPDEFINES='DEBUG')
-tlist = debugEnv.Program(target = 'm5.debug',
- source = make_objs(sources, debugEnv))
-debugEnv.M5Binary = tlist[0]
+makeEnv('debug', '.do',
+ CCFLAGS = Split('-g3 -gdwarf-2 -O0'),
+ CPPDEFINES = 'DEBUG')
# Optimized binary
-optEnv = env.Copy()
-optEnv.Label = 'opt'
-optEnv.Append(CCFLAGS=Split('-g -O3'))
-tlist = optEnv.Program(target = 'm5.opt',
- source = make_objs(sources, optEnv))
-optEnv.M5Binary = tlist[0]
+makeEnv('opt', '.o',
+ CCFLAGS = Split('-g -O3'))
# "Fast" binary
-fastEnv = env.Copy(OBJSUFFIX='.fo')
-fastEnv.Label = 'fast'
-fastEnv.Append(CCFLAGS=Split('-O3'))
-fastEnv.Append(CPPDEFINES='NDEBUG')
-fastEnv.Program(target = 'm5.fast.unstripped',
- source = make_objs(sources, fastEnv))
-tlist = fastEnv.Command(target = 'm5.fast',
- source = 'm5.fast.unstripped',
- action = 'strip $SOURCE -o $TARGET')
-fastEnv.M5Binary = tlist[0]
+makeEnv('fast', '.fo', strip = True,
+ CCFLAGS = Split('-O3'),
+ CPPDEFINES = 'NDEBUG')
# Profiled binary
-profEnv = env.Copy(OBJSUFFIX='.po')
-profEnv.Label = 'prof'
-profEnv.Append(CCFLAGS=Split('-O3 -g -pg'), LINKFLAGS='-pg')
-tlist = profEnv.Program(target = 'm5.prof',
- source = make_objs(sources, profEnv))
-profEnv.M5Binary = tlist[0]
-
-envList = [debugEnv, optEnv, fastEnv, profEnv]
+makeEnv('prof', '.po',
+ CCFLAGS = Split('-O3 -g -pg'),
+ LINKFLAGS = '-pg')
Return('envList')
diff --git a/src/arch/SConscript b/src/arch/SConscript
index 9c193207f..bc517341a 100644
--- a/src/arch/SConscript
+++ b/src/arch/SConscript
@@ -25,8 +25,10 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
-import os.path
+import os.path, sys
# Import build environment variable from SConstruct.
Import('env')
@@ -126,13 +128,19 @@ isa_desc_gen_files = Split('decoder.cc decoder.hh')
isa_desc_gen_files += [CpuModel.dict[cpu].filename
for cpu in env['CPU_MODELS']]
+# Also include the CheckerCPU as one of the models if it is being
+# enabled via command line.
+if env['USE_CHECKER']:
+ isa_desc_gen_files += [CpuModel.dict['CheckerCPU'].filename]
+
# The emitter patches up the sources & targets to include the
# autogenerated files as targets and isa parser itself as a source.
def isa_desc_emitter(target, source, env):
return (isa_desc_gen_files, [isa_parser, cpu_models_file] + source)
# Pieces are in place, so create the builder.
-isa_desc_builder = Builder(action='python2.4 $SOURCES $TARGET.dir $CPU_MODELS',
+python = sys.executable # use same Python binary used to run scons
+isa_desc_builder = Builder(action=python + ' $SOURCES $TARGET.dir $CPU_MODELS',
emitter = isa_desc_emitter)
env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
@@ -144,7 +152,6 @@ env.Append(BUILDERS = { 'ISADesc' : isa_desc_builder })
isa = env['TARGET_ISA'] # someday this may be a list of ISAs
# Let the target architecture define what additional sources it needs
-sources += SConscript(os.path.join(isa, 'SConscript'),
- exports = 'env', duplicate = False)
+sources += SConscript(os.path.join(isa, 'SConscript'), exports = 'env')
Return('sources')
diff --git a/src/arch/alpha/SConscript b/src/arch/alpha/SConscript
index 1b20f8b1f..216c88cc7 100644
--- a/src/arch/alpha/SConscript
+++ b/src/arch/alpha/SConscript
@@ -25,6 +25,9 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+# Steve Reinhardt
import os
import sys
diff --git a/src/arch/alpha/aout_machdep.h b/src/arch/alpha/aout_machdep.h
index df9d9ac6a..58991256a 100644
--- a/src/arch/alpha/aout_machdep.h
+++ b/src/arch/alpha/aout_machdep.h
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __AOUT_MACHDEP_H__
diff --git a/src/arch/alpha/arguments.cc b/src/arch/alpha/arguments.cc
index adc371682..9f9002003 100644
--- a/src/arch/alpha/arguments.cc
+++ b/src/arch/alpha/arguments.cc
@@ -24,11 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "arch/alpha/arguments.hh"
#include "arch/alpha/vtophys.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/vport.hh"
using namespace AlphaISA;
@@ -54,14 +56,14 @@ AlphaArguments::getArg(bool fp)
{
if (number < 6) {
if (fp)
- return xc->readFloatRegBits(16 + number);
+ return tc->readFloatRegBits(16 + number);
else
- return xc->readIntReg(16 + number);
+ return tc->readIntReg(16 + number);
} else {
- Addr sp = xc->readIntReg(30);
- VirtualPort *vp = xc->getVirtPort(xc);
+ Addr sp = tc->readIntReg(30);
+ VirtualPort *vp = tc->getVirtPort(tc);
uint64_t arg = vp->read<uint64_t>(sp + (number-6) * sizeof(uint64_t));
- xc->delVirtPort(vp);
+ tc->delVirtPort(vp);
return arg;
}
}
diff --git a/src/arch/alpha/arguments.hh b/src/arch/alpha/arguments.hh
index bd1c6cb1d..d977d48d6 100644
--- a/src/arch/alpha/arguments.hh
+++ b/src/arch/alpha/arguments.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ARCH_ALPHA_ARGUMENTS_HH__
@@ -35,14 +37,14 @@
#include "base/refcnt.hh"
#include "sim/host.hh"
-class ExecContext;
+class ThreadContext;
namespace AlphaISA {
class AlphaArguments
{
protected:
- ExecContext *xc;
+ ThreadContext *tc;
int number;
uint64_t getArg(bool fp = false);
@@ -63,17 +65,17 @@ class AlphaArguments
RefCountingPtr<Data> data;
public:
- AlphaArguments(ExecContext *ctx, int n = 0)
- : xc(ctx), number(n), data(NULL)
+ AlphaArguments(ThreadContext *ctx, int n = 0)
+ : tc(ctx), number(n), data(NULL)
{ assert(number >= 0); data = new Data;}
AlphaArguments(const AlphaArguments &args)
- : xc(args.xc), number(args.number), data(args.data) {}
+ : tc(args.tc), number(args.number), data(args.data) {}
~AlphaArguments() {}
- ExecContext *getExecContext() const { return xc; }
+ ThreadContext *getThreadContext() const { return tc; }
const AlphaArguments &operator=(const AlphaArguments &args) {
- xc = args.xc;
+ tc = args.tc;
number = args.number;
data = args.data;
return *this;
@@ -118,7 +120,7 @@ class AlphaArguments
}
AlphaArguments operator[](int index) {
- return AlphaArguments(xc, index);
+ return AlphaArguments(tc, index);
}
template <class T>
@@ -131,13 +133,13 @@ class AlphaArguments
template <class T>
operator T *() {
T *buf = (T *)data->alloc(sizeof(T));
- CopyData(xc, buf, getArg(), sizeof(T));
+ CopyData(tc, buf, getArg(), sizeof(T));
return buf;
}
operator char *() {
char *buf = data->alloc(2048);
- CopyStringOut(xc, buf, getArg(), 2048);
+ CopyStringOut(tc, buf, getArg(), 2048);
return buf;
}
};
diff --git a/src/arch/alpha/ev5.cc b/src/arch/alpha/ev5.cc
index 12f7659e6..ae3b668ea 100644
--- a/src/arch/alpha/ev5.cc
+++ b/src/arch/alpha/ev5.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "arch/alpha/tlb.hh"
@@ -34,11 +37,11 @@
#include "base/stats/events.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
-#include "cpu/cpu_exec_context.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
#include "kern/kernel_stats.hh"
#include "sim/debug.hh"
-#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
#if FULL_SYSTEM
@@ -49,15 +52,19 @@ using namespace EV5;
// Machine dependent functions
//
void
-AlphaISA::initCPU(ExecContext *xc, int cpuId)
+AlphaISA::initCPU(ThreadContext *tc, int cpuId)
{
- initIPRs(xc, cpuId);
+ initIPRs(tc, cpuId);
+
+ tc->setIntReg(16, cpuId);
+ tc->setIntReg(0, cpuId);
- xc->setIntReg(16, cpuId);
- xc->setIntReg(0, cpuId);
+ AlphaFault *reset = new ResetFault;
- xc->setPC(xc->readMiscReg(IPR_PAL_BASE) + (new ResetFault)->vect());
- xc->setNextPC(xc->readPC() + sizeof(MachInst));
+ tc->setPC(tc->readMiscReg(IPR_PAL_BASE) + reset->vect());
+ tc->setNextPC(tc->readPC() + sizeof(MachInst));
+
+ delete reset;
}
////////////////////////////////////////////////////////////////////////
@@ -65,15 +72,15 @@ AlphaISA::initCPU(ExecContext *xc, int cpuId)
//
//
void
-AlphaISA::initIPRs(ExecContext *xc, int cpuId)
+AlphaISA::initIPRs(ThreadContext *tc, int cpuId)
{
for (int i = 0; i < NumInternalProcRegs; ++i) {
- xc->setMiscReg(i, 0);
+ tc->setMiscReg(i, 0);
}
- xc->setMiscReg(IPR_PAL_BASE, PalBase);
- xc->setMiscReg(IPR_MCSR, 0x6);
- xc->setMiscReg(IPR_PALtemp16, cpuId);
+ tc->setMiscReg(IPR_PAL_BASE, PalBase);
+ tc->setMiscReg(IPR_MCSR, 0x6);
+ tc->setMiscReg(IPR_PALtemp16, cpuId);
}
@@ -132,12 +139,12 @@ AlphaISA::zeroRegisters(CPU *cpu)
// Insure ISA semantics
// (no longer very clean due to the change in setIntReg() in the
// cpu model. Consider changing later.)
- cpu->cpuXC->setIntReg(ZeroReg, 0);
- cpu->cpuXC->setFloatReg(ZeroReg, 0.0);
+ cpu->thread->setIntReg(ZeroReg, 0);
+ cpu->thread->setFloatReg(ZeroReg, 0.0);
}
Fault
-CPUExecContext::hwrei()
+SimpleThread::hwrei()
{
if (!inPalMode())
return new UnimplementedOpcodeFault;
@@ -145,7 +152,8 @@ CPUExecContext::hwrei()
setNextPC(readMiscReg(AlphaISA::IPR_EXC_ADDR));
if (!misspeculating()) {
- cpu->kernelStats->hwrei();
+ if (kernelStats)
+ kernelStats->hwrei();
cpu->checkInterrupts = true;
}
@@ -167,7 +175,7 @@ AlphaISA::MiscRegFile::getDataAsid()
}
AlphaISA::MiscReg
-AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc)
+AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ThreadContext *tc)
{
uint64_t retval = 0; // return value, default 0
@@ -221,7 +229,7 @@ AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc)
case AlphaISA::IPR_CC:
retval |= ipr[idx] & ULL(0xffffffff00000000);
- retval |= xc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff);
+ retval |= tc->getCpuPtr()->curCycle() & ULL(0x00000000ffffffff);
break;
case AlphaISA::IPR_VA:
@@ -238,7 +246,7 @@ AlphaISA::MiscRegFile::readIpr(int idx, Fault &fault, ExecContext *xc)
case AlphaISA::IPR_DTB_PTE:
{
- AlphaISA::PTE &pte = xc->getDTBPtr()->index(!xc->misspeculating());
+ AlphaISA::PTE &pte = tc->getDTBPtr()->index(!tc->misspeculating());
retval |= ((u_int64_t)pte.ppn & ULL(0x7ffffff)) << 32;
retval |= ((u_int64_t)pte.xre & ULL(0xf)) << 8;
@@ -278,11 +286,11 @@ int break_ipl = -1;
#endif
Fault
-AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
+AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ThreadContext *tc)
{
uint64_t old;
- if (xc->misspeculating())
+ if (tc->misspeculating())
return NoFault;
switch (idx) {
@@ -335,7 +343,8 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// write entire quad w/ no side-effect
old = ipr[idx];
ipr[idx] = val;
- xc->getCpuPtr()->kernelStats->context(old, val, xc);
+ if (tc->getKernelStats())
+ tc->getKernelStats()->context(old, val, tc);
break;
case AlphaISA::IPR_DTB_PTE:
@@ -362,14 +371,18 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// only write least significant five bits - interrupt level
ipr[idx] = val & 0x1f;
- xc->getCpuPtr()->kernelStats->swpipl(ipr[idx]);
+ if (tc->getKernelStats())
+ tc->getKernelStats()->swpipl(ipr[idx]);
break;
case AlphaISA::IPR_DTB_CM:
- if (val & 0x18)
- xc->getCpuPtr()->kernelStats->mode(Kernel::user, xc);
- else
- xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
+ if (val & 0x18) {
+ if (tc->getKernelStats())
+ tc->getKernelStats()->mode(Kernel::user, tc);
+ } else {
+ if (tc->getKernelStats())
+ tc->getKernelStats()->mode(Kernel::kernel, tc);
+ }
case AlphaISA::IPR_ICM:
// only write two mode bits - processor mode
@@ -443,21 +456,21 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// really a control write
ipr[idx] = 0;
- xc->getDTBPtr()->flushAll();
+ tc->getDTBPtr()->flushAll();
break;
case AlphaISA::IPR_DTB_IAP:
// really a control write
ipr[idx] = 0;
- xc->getDTBPtr()->flushProcesses();
+ tc->getDTBPtr()->flushProcesses();
break;
case AlphaISA::IPR_DTB_IS:
// really a control write
ipr[idx] = val;
- xc->getDTBPtr()->flushAddr(val,
+ tc->getDTBPtr()->flushAddr(val,
DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]));
break;
@@ -481,7 +494,7 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
pte.asn = DTB_ASN_ASN(ipr[AlphaISA::IPR_DTB_ASN]);
// insert new TAG/PTE value into data TLB
- xc->getDTBPtr()->insert(val, pte);
+ tc->getDTBPtr()->insert(val, pte);
}
break;
@@ -505,7 +518,7 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
pte.asn = ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]);
// insert new TAG/PTE value into data TLB
- xc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
+ tc->getITBPtr()->insert(ipr[AlphaISA::IPR_ITB_TAG], pte);
}
break;
@@ -513,21 +526,21 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
// really a control write
ipr[idx] = 0;
- xc->getITBPtr()->flushAll();
+ tc->getITBPtr()->flushAll();
break;
case AlphaISA::IPR_ITB_IAP:
// really a control write
ipr[idx] = 0;
- xc->getITBPtr()->flushProcesses();
+ tc->getITBPtr()->flushProcesses();
break;
case AlphaISA::IPR_ITB_IS:
// really a control write
ipr[idx] = val;
- xc->getITBPtr()->flushAddr(val,
+ tc->getITBPtr()->flushAddr(val,
ITB_ASN_ASN(ipr[AlphaISA::IPR_ITB_ASN]));
break;
@@ -541,7 +554,7 @@ AlphaISA::MiscRegFile::setIpr(int idx, uint64_t val, ExecContext *xc)
}
void
-AlphaISA::copyIprs(ExecContext *src, ExecContext *dest)
+AlphaISA::copyIprs(ThreadContext *src, ThreadContext *dest)
{
for (int i = IPR_Base_DepTag; i < NumInternalProcRegs; ++i) {
dest->setMiscReg(i, src->readMiscReg(i));
@@ -553,15 +566,16 @@ AlphaISA::copyIprs(ExecContext *src, ExecContext *dest)
* If return value is false, actual PAL call will be suppressed.
*/
bool
-CPUExecContext::simPalCheck(int palFunc)
+SimpleThread::simPalCheck(int palFunc)
{
- cpu->kernelStats->callpal(palFunc, proxy);
+ if (kernelStats)
+ kernelStats->callpal(palFunc, tc);
switch (palFunc) {
case PAL::halt:
halt();
if (--System::numSystemsRunning == 0)
- new SimExitEvent("all cpus halted");
+ exitSimLoop("all cpus halted");
break;
case PAL::bpt:
diff --git a/src/arch/alpha/ev5.hh b/src/arch/alpha/ev5.hh
index 7c8465cfb..4dd225786 100644
--- a/src/arch/alpha/ev5.hh
+++ b/src/arch/alpha/ev5.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __ARCH_ALPHA_EV5_HH__
diff --git a/src/arch/alpha/faults.cc b/src/arch/alpha/faults.cc
index 0083aa9f3..eef4361fd 100644
--- a/src/arch/alpha/faults.cc
+++ b/src/arch/alpha/faults.cc
@@ -24,14 +24,20 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#include "arch/alpha/faults.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "base/trace.hh"
#if FULL_SYSTEM
#include "arch/alpha/ev5.hh"
+#else
+#include "sim/process.hh"
+#include "mem/page_table.hh"
#endif
namespace AlphaISA
@@ -53,6 +59,12 @@ FaultName ArithmeticFault::_name = "arith";
FaultVect ArithmeticFault::_vect = 0x0501;
FaultStat ArithmeticFault::_count;
+#if !FULL_SYSTEM
+FaultName PageTableFault::_name = "page_table_fault";
+FaultVect PageTableFault::_vect = 0x0000;
+FaultStat PageTableFault::_count;
+#endif
+
FaultName InterruptFault::_name = "interrupt";
FaultVect InterruptFault::_vect = 0x0101;
FaultStat InterruptFault::_count;
@@ -107,67 +119,91 @@ FaultStat IntegerOverflowFault::_count;
#if FULL_SYSTEM
-void AlphaFault::invoke(ExecContext * xc)
+void AlphaFault::invoke(ThreadContext * tc)
{
- FaultBase::invoke(xc);
+ FaultBase::invoke(tc);
countStat()++;
// exception restart address
- if (setRestartAddress() || !xc->inPalMode())
- xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->readPC());
+ if (setRestartAddress() || !tc->inPalMode())
+ tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, tc->readPC());
if (skipFaultingInstruction()) {
// traps... skip faulting instruction.
- xc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
- xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
+ tc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
+ tc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
}
- xc->setPC(xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect());
- xc->setNextPC(xc->readPC() + sizeof(MachInst));
+ tc->setPC(tc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect());
+ tc->setNextPC(tc->readPC() + sizeof(MachInst));
}
-void ArithmeticFault::invoke(ExecContext * xc)
+void ArithmeticFault::invoke(ThreadContext * tc)
{
- FaultBase::invoke(xc);
+ FaultBase::invoke(tc);
panic("Arithmetic traps are unimplemented!");
}
-void DtbFault::invoke(ExecContext * xc)
+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 (!xc->misspeculating()
+ if (!tc->misspeculating()
&& !(reqFlags & VPTE) && !(reqFlags & NO_FAULT)) {
// set VA register with faulting address
- xc->setMiscReg(AlphaISA::IPR_VA, vaddr);
+ tc->setMiscReg(AlphaISA::IPR_VA, vaddr);
// set MM_STAT register flags
- xc->setMiscReg(AlphaISA::IPR_MM_STAT,
- (((EV5::Opcode(xc->getInst()) & 0x3f) << 11)
- | ((EV5::Ra(xc->getInst()) & 0x1f) << 6)
+ tc->setMiscReg(AlphaISA::IPR_MM_STAT,
+ (((EV5::Opcode(tc->getInst()) & 0x3f) << 11)
+ | ((EV5::Ra(tc->getInst()) & 0x1f) << 6)
| (flags & 0x3f)));
// set VA_FORM register with faulting formatted address
- xc->setMiscReg(AlphaISA::IPR_VA_FORM,
- xc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
+ tc->setMiscReg(AlphaISA::IPR_VA_FORM,
+ tc->readMiscReg(AlphaISA::IPR_MVPTBR) | (vaddr.vpn() << 3));
}
- AlphaFault::invoke(xc);
+ AlphaFault::invoke(tc);
}
-void ItbFault::invoke(ExecContext * xc)
+void ItbFault::invoke(ThreadContext * tc)
{
- if (!xc->misspeculating()) {
- xc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc);
- xc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM,
- xc->readMiscReg(AlphaISA::IPR_IVPTBR) |
+ if (!tc->misspeculating()) {
+ tc->setMiscReg(AlphaISA::IPR_ITB_TAG, pc);
+ tc->setMiscReg(AlphaISA::IPR_IFAULT_VA_FORM,
+ tc->readMiscReg(AlphaISA::IPR_IVPTBR) |
(AlphaISA::VAddr(pc).vpn() << 3));
}
- AlphaFault::invoke(xc);
+ AlphaFault::invoke(tc);
+}
+
+#else //!FULL_SYSTEM
+
+void PageTableFault::invoke(ThreadContext *tc)
+{
+ Process *p = tc->getProcessPtr();
+
+ // address is higher than the stack region or in the current stack region
+ if (vaddr > p->stack_base || vaddr > p->stack_min)
+ FaultBase::invoke(tc);
+
+ // We've accessed the next page
+ if (vaddr > p->stack_min - PageBytes) {
+ warn("Increasing stack %#x:%#x to %#x:%#x because of access to %#x",
+ p->stack_min, p->stack_base, p->stack_min - PageBytes,
+ p->stack_base, vaddr);
+ p->stack_min -= PageBytes;
+ if (p->stack_base - p->stack_min > 8*1024*1024)
+ fatal("Over max stack size for one thread\n");
+ p->pTable->allocate(p->stack_min, PageBytes);
+ } else {
+ FaultBase::invoke(tc);
+ }
}
#endif
diff --git a/src/arch/alpha/faults.hh b/src/arch/alpha/faults.hh
index e8ccc6b79..11a568174 100644
--- a/src/arch/alpha/faults.hh
+++ b/src/arch/alpha/faults.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#ifndef __ALPHA_FAULTS_HH__
@@ -46,7 +49,7 @@ class AlphaFault : public FaultBase
virtual bool setRestartAddress() {return true;}
public:
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
virtual FaultVect vect() = 0;
virtual FaultStat & countStat() = 0;
@@ -78,6 +81,29 @@ class AlignmentFault : public AlphaFault
bool isAlignmentFault() {return true;}
};
+#if !FULL_SYSTEM
+class PageTableFault : public AlphaFault
+{
+ private:
+ Addr vaddr;
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ PageTableFault(Addr va)
+ : vaddr(va) {}
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ void invoke(ThreadContext * tc);
+};
+
+static inline Fault genPageTableFault(Addr va)
+{
+ return new PageTableFault(va);
+}
+#endif
+
static inline Fault genMachineCheckFault()
{
return new MachineCheckFault;
@@ -113,7 +139,7 @@ class ArithmeticFault : public AlphaFault
FaultVect vect() {return _vect;}
FaultStat & countStat() {return _count;}
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
};
@@ -147,7 +173,7 @@ class DtbFault : public AlphaFault
FaultVect vect() = 0;
FaultStat & countStat() = 0;
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
};
@@ -248,7 +274,7 @@ class ItbFault : public AlphaFault
FaultVect vect() = 0;
FaultStat & countStat() = 0;
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
};
diff --git a/src/arch/alpha/freebsd/system.cc b/src/arch/alpha/freebsd/system.cc
index 3e50fb9a5..7cf68e0db 100644
--- a/src/arch/alpha/freebsd/system.cc
+++ b/src/arch/alpha/freebsd/system.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Ben Nash
*/
/**
@@ -36,7 +38,7 @@
#include "arch/alpha/system.hh"
#include "arch/alpha/freebsd/system.hh"
#include "base/loader/symtab.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/physical.hh"
#include "mem/port.hh"
#include "arch/isa_traits.hh"
@@ -70,13 +72,13 @@ FreebsdAlphaSystem::~FreebsdAlphaSystem()
void
-FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc)
+FreebsdAlphaSystem::doCalibrateClocks(ThreadContext *tc)
{
Addr ppc_vaddr = 0;
Addr timer_vaddr = 0;
- ppc_vaddr = (Addr)xc->readIntReg(ArgumentReg1);
- timer_vaddr = (Addr)xc->readIntReg(ArgumentReg2);
+ ppc_vaddr = (Addr)tc->readIntReg(ArgumentReg1);
+ timer_vaddr = (Addr)tc->readIntReg(ArgumentReg2);
virtPort.write(ppc_vaddr, (uint32_t)Clock::Frequency);
virtPort.write(timer_vaddr, (uint32_t)TIMER_FREQUENCY);
@@ -84,10 +86,10 @@ FreebsdAlphaSystem::doCalibrateClocks(ExecContext *xc)
void
-FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ExecContext *xc)
+FreebsdAlphaSystem::SkipCalibrateClocksEvent::process(ThreadContext *tc)
{
- SkipFuncEvent::process(xc);
- ((FreebsdAlphaSystem *)xc->getSystemPtr())->doCalibrateClocks(xc);
+ SkipFuncEvent::process(tc);
+ ((FreebsdAlphaSystem *)tc->getSystemPtr())->doCalibrateClocks(tc);
}
@@ -107,10 +109,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
Param<uint64_t> system_type;
Param<uint64_t> system_rev;
- Param<bool> bin;
- VectorParam<string> binned_fns;
- Param<bool> bin_int;
-
END_DECLARE_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
@@ -125,10 +123,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
- INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
- INIT_PARAM_DFLT(bin, "is this system to be binned", false),
- INIT_PARAM(binned_fns, "functions to be broken down and binned"),
- INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10)
END_INIT_SIM_OBJECT_PARAMS(FreebsdAlphaSystem)
@@ -146,9 +141,6 @@ CREATE_SIM_OBJECT(FreebsdAlphaSystem)
p->readfile = readfile;
p->system_type = system_type;
p->system_rev = system_rev;
- p->bin = bin;
- p->binned_fns = binned_fns;
- p->bin_int = bin_int;
return new FreebsdAlphaSystem(p);
}
diff --git a/src/arch/alpha/freebsd/system.hh b/src/arch/alpha/freebsd/system.hh
index 5d996955e..e0d874e8f 100644
--- a/src/arch/alpha/freebsd/system.hh
+++ b/src/arch/alpha/freebsd/system.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Ben Nash
*/
#ifndef __KERN_FREEBSD_FREEBSD_SYSTEM_HH__
@@ -40,7 +42,7 @@ class FreebsdAlphaSystem : public AlphaSystem
SkipCalibrateClocksEvent(PCEventQueue *q, const std::string &desc,
Addr addr)
: SkipFuncEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
SkipFuncEvent *skipDelayEvent;
@@ -49,7 +51,7 @@ class FreebsdAlphaSystem : public AlphaSystem
public:
FreebsdAlphaSystem(Params *p);
~FreebsdAlphaSystem();
- void doCalibrateClocks(ExecContext *xc);
+ void doCalibrateClocks(ThreadContext *tc);
};
diff --git a/src/arch/alpha/isa/branch.isa b/src/arch/alpha/isa/branch.isa
index b528df938..7438e7e18 100644
--- a/src/arch/alpha/isa/branch.isa
+++ b/src/arch/alpha/isa/branch.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Control transfer instructions
+//
output header {{
@@ -99,7 +106,7 @@ output header {{
{
}
- Addr branchTarget(ExecContext *xc) const;
+ Addr branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@@ -114,10 +121,10 @@ output decoder {{
}
Addr
- Jump::branchTarget(ExecContext *xc) const
+ Jump::branchTarget(ThreadContext *tc) const
{
- Addr NPC = xc->readPC() + 4;
- uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+ Addr NPC = tc->readPC() + 4;
+ uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
return (Rb & ~3) | (NPC & 1);
}
diff --git a/src/arch/alpha/isa/decoder.isa b/src/arch/alpha/isa/decoder.isa
index 1adcfb948..f449d2d69 100644
--- a/src/arch/alpha/isa/decoder.isa
+++ b/src/arch/alpha/isa/decoder.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// The actual decoder specification
+//
decode OPCODE default Unknown::unknown() {
@@ -40,9 +47,11 @@ decode OPCODE default Unknown::unknown() {
0x23: ldt({{ Fa = Mem.df; }});
0x2a: ldl_l({{ Ra.sl = Mem.sl; }}, mem_flags = LOCKED);
0x2b: ldq_l({{ Ra.uq = Mem.uq; }}, mem_flags = LOCKED);
+#ifdef USE_COPY
0x20: MiscPrefetch::copy_load({{ EA = Ra; }},
{{ fault = xc->copySrcTranslate(EA); }},
inst_flags = [IsMemRef, IsLoad, IsCopy]);
+#endif
}
format LoadOrPrefetch {
@@ -62,9 +71,11 @@ decode OPCODE default Unknown::unknown() {
0x0f: stq_u({{ Mem.uq = Ra.uq; }}, {{ EA = (Rb + disp) & ~7; }});
0x26: sts({{ Mem.ul = t_to_s(Fa.uq); }});
0x27: stt({{ Mem.df = Fa; }});
+#ifdef USE_COPY
0x24: MiscPrefetch::copy_store({{ EA = Rb; }},
{{ fault = xc->copy(EA); }},
inst_flags = [IsMemRef, IsStore, IsCopy]);
+#endif
}
format StoreCond {
@@ -73,7 +84,7 @@ decode OPCODE default Unknown::unknown() {
uint64_t tmp = write_result;
// see stq_c
Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
- }}, mem_flags = LOCKED);
+ }}, mem_flags = LOCKED, inst_flags = IsStoreConditional);
0x2f: stq_c({{ Mem.uq = Ra; }},
{{
uint64_t tmp = write_result;
@@ -85,7 +96,7 @@ decode OPCODE default Unknown::unknown() {
// mailbox access, and we don't update the
// result register at all.
Ra = (tmp == 0 || tmp == 1) ? tmp : Ra;
- }}, mem_flags = LOCKED);
+ }}, mem_flags = LOCKED, inst_flags = IsStoreConditional);
}
format IntegerOperate {
@@ -591,8 +602,8 @@ decode OPCODE default Unknown::unknown() {
0x02e: fcmovle({{ Fc = (Fa <= 0) ? Fb : Fc; }});
0x02f: fcmovgt({{ Fc = (Fa > 0) ? Fb : Fc; }});
- 0x024: mt_fpcr({{ FPCR = Fa.uq; }});
- 0x025: mf_fpcr({{ Fa.uq = FPCR; }});
+ 0x024: mt_fpcr({{ FPCR = Fa.uq; }}, IsIprAccess);
+ 0x025: mf_fpcr({{ Fa.uq = FPCR; }}, IsIprAccess);
}
}
@@ -623,7 +634,7 @@ decode OPCODE default Unknown::unknown() {
#else
Ra = curTick;
#endif
- }});
+ }}, IsUnverifiable);
// All of the barrier instructions below do nothing in
// their execute() methods (hence the empty code blocks).
@@ -641,8 +652,8 @@ decode OPCODE default Unknown::unknown() {
// a barrier on integer and FP traps. "EXCB is thus a
// superset of TRAPB." (Alpha ARM, Sec 4.11.4) We treat
// them the same though.
- 0x0000: trapb({{ }}, IsSerializing, No_OpClass);
- 0x0400: excb({{ }}, IsSerializing, No_OpClass);
+ 0x0000: trapb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass);
+ 0x0400: excb({{ }}, IsSerializing, IsSerializeBefore, No_OpClass);
0x4000: mb({{ }}, IsMemBarrier, MemReadOp);
0x4400: wmb({{ }}, IsWriteBarrier, MemWriteOp);
}
@@ -652,11 +663,11 @@ decode OPCODE default Unknown::unknown() {
0xe000: rc({{
Ra = xc->readIntrFlag();
xc->setIntrFlag(0);
- }}, IsNonSpeculative);
+ }}, IsNonSpeculative, IsUnverifiable);
0xf000: rs({{
Ra = xc->readIntrFlag();
xc->setIntrFlag(1);
- }}, IsNonSpeculative);
+ }}, IsNonSpeculative, IsUnverifiable);
}
#else
format FailUnimpl {
@@ -690,15 +701,15 @@ decode OPCODE default Unknown::unknown() {
0x00: decode PALFUNC {
format EmulatedCallPal {
0x00: halt ({{
- SimExit(curTick, "halt instruction encountered");
+ exitSimLoop(curTick, "halt instruction encountered");
}}, IsNonSpeculative);
0x83: callsys({{
xc->syscall(R0);
- }}, IsNonSpeculative);
+ }}, IsSerializeAfter, IsNonSpeculative);
// Read uniq reg into ABI return value register (r0)
- 0x9e: rduniq({{ R0 = Runiq; }});
+ 0x9e: rduniq({{ R0 = Runiq; }}, IsIprAccess);
// Write uniq reg with value from ABI arg register (r16)
- 0x9f: wruniq({{ Runiq = R16; }});
+ 0x9f: wruniq({{ Runiq = R16; }}, IsIprAccess);
}
}
#endif
@@ -735,7 +746,7 @@ decode OPCODE default Unknown::unknown() {
format HwMoveIPR {
1: hw_mfpr({{
Ra = xc->readMiscRegWithEffect(ipr_index, fault);
- }});
+ }}, IsIprAccess);
}
}
@@ -745,69 +756,69 @@ decode OPCODE default Unknown::unknown() {
1: hw_mtpr({{
xc->setMiscRegWithEffect(ipr_index, Ra);
if (traceData) { traceData->setData(Ra); }
- }});
+ }}, IsIprAccess);
}
}
format BasicOperate {
0x1e: decode PALMODE {
0: OpcdecFault::hw_rei();
- 1:hw_rei({{ xc->hwrei(); }}, IsSerializing);
+ 1:hw_rei({{ xc->hwrei(); }}, IsSerializing, IsSerializeBefore);
}
// M5 special opcodes use the reserved 0x01 opcode space
0x01: decode M5FUNC {
0x00: arm({{
- AlphaPseudo::arm(xc->xcBase());
+ AlphaPseudo::arm(xc->tcBase());
}}, IsNonSpeculative);
0x01: quiesce({{
- AlphaPseudo::quiesce(xc->xcBase());
- }}, IsNonSpeculative);
+ AlphaPseudo::quiesce(xc->tcBase());
+ }}, IsNonSpeculative, IsQuiesce);
0x02: quiesceNs({{
- AlphaPseudo::quiesceNs(xc->xcBase(), R16);
- }}, IsNonSpeculative);
+ AlphaPseudo::quiesceNs(xc->tcBase(), R16);
+ }}, IsNonSpeculative, IsQuiesce);
0x03: quiesceCycles({{
- AlphaPseudo::quiesceCycles(xc->xcBase(), R16);
- }}, IsNonSpeculative);
+ AlphaPseudo::quiesceCycles(xc->tcBase(), R16);
+ }}, IsNonSpeculative, IsQuiesce);
0x04: quiesceTime({{
- R0 = AlphaPseudo::quiesceTime(xc->xcBase());
+ R0 = AlphaPseudo::quiesceTime(xc->tcBase());
}}, IsNonSpeculative);
0x10: ivlb({{
- AlphaPseudo::ivlb(xc->xcBase());
+ AlphaPseudo::ivlb(xc->tcBase());
}}, No_OpClass, IsNonSpeculative);
0x11: ivle({{
- AlphaPseudo::ivle(xc->xcBase());
+ AlphaPseudo::ivle(xc->tcBase());
}}, No_OpClass, IsNonSpeculative);
0x20: m5exit_old({{
- AlphaPseudo::m5exit_old(xc->xcBase());
+ AlphaPseudo::m5exit_old(xc->tcBase());
}}, No_OpClass, IsNonSpeculative);
0x21: m5exit({{
- AlphaPseudo::m5exit(xc->xcBase(), R16);
+ AlphaPseudo::m5exit(xc->tcBase(), R16);
}}, No_OpClass, IsNonSpeculative);
- 0x30: initparam({{ Ra = xc->xcBase()->getCpuPtr()->system->init_param; }});
+ 0x30: initparam({{ Ra = xc->tcBase()->getCpuPtr()->system->init_param; }});
0x40: resetstats({{
- AlphaPseudo::resetstats(xc->xcBase(), R16, R17);
+ AlphaPseudo::resetstats(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
0x41: dumpstats({{
- AlphaPseudo::dumpstats(xc->xcBase(), R16, R17);
+ AlphaPseudo::dumpstats(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
0x42: dumpresetstats({{
- AlphaPseudo::dumpresetstats(xc->xcBase(), R16, R17);
+ AlphaPseudo::dumpresetstats(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
0x43: m5checkpoint({{
- AlphaPseudo::m5checkpoint(xc->xcBase(), R16, R17);
+ AlphaPseudo::m5checkpoint(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
0x50: m5readfile({{
- R0 = AlphaPseudo::readfile(xc->xcBase(), R16, R17, R18);
+ R0 = AlphaPseudo::readfile(xc->tcBase(), R16, R17, R18);
}}, IsNonSpeculative);
0x51: m5break({{
- AlphaPseudo::debugbreak(xc->xcBase());
+ AlphaPseudo::debugbreak(xc->tcBase());
}}, IsNonSpeculative);
0x52: m5switchcpu({{
- AlphaPseudo::switchcpu(xc->xcBase());
+ AlphaPseudo::switchcpu(xc->tcBase());
}}, IsNonSpeculative);
0x53: m5addsymbol({{
- AlphaPseudo::addsymbol(xc->xcBase(), R16, R17);
+ AlphaPseudo::addsymbol(xc->tcBase(), R16, R17);
}}, IsNonSpeculative);
0x54: m5panic({{
panic("M5 panic instruction called at pc=%#x.", xc->readPC());
diff --git a/src/arch/alpha/isa/fp.isa b/src/arch/alpha/isa/fp.isa
index f34c13c42..b4339a1b7 100644
--- a/src/arch/alpha/isa/fp.isa
+++ b/src/arch/alpha/isa/fp.isa
@@ -25,6 +25,17 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Floating-point instructions
+//
+// Note that many FP-type instructions which do not support all the
+// various rounding & trapping modes use the simpler format
+// BasicOperateWithNopCheck.
+//
output exec {{
/// Check "FP enabled" machine status bit. Called when executing any FP
diff --git a/src/arch/alpha/isa/int.isa b/src/arch/alpha/isa/int.isa
index 17ecc1a51..45e096ebd 100644
--- a/src/arch/alpha/isa/int.isa
+++ b/src/arch/alpha/isa/int.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
output header {{
/**
diff --git a/src/arch/alpha/isa/main.isa b/src/arch/alpha/isa/main.isa
index 03a8e1ff5..1270bf8d8 100644
--- a/src/arch/alpha/isa/main.isa
+++ b/src/arch/alpha/isa/main.isa
@@ -25,6 +25,20 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Alpha ISA description file.
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Output include file directives.
+//
output header {{
#include <sstream>
@@ -42,7 +56,7 @@ output decoder {{
#include "base/fenv.hh"
#include "base/loader/symtab.hh"
#include "config/ss_compatible_fp.hh"
-#include "cpu/exec_context.hh" // for Jump::branchTarget()
+#include "cpu/thread_context.hh" // for Jump::branchTarget()
#include <math.h>
diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa
index 98c7ba979..08a0a2343 100644
--- a/src/arch/alpha/isa/mem.isa
+++ b/src/arch/alpha/isa/mem.isa
@@ -25,6 +25,14 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+// Kevin Lim
+
+////////////////////////////////////////////////////////////////////
+//
+// Memory-format instructions: LoadAddress, Load, Store
+//
output header {{
/**
diff --git a/src/arch/alpha/isa/opcdec.isa b/src/arch/alpha/isa/opcdec.isa
index bb2f91e5c..d279ae050 100644
--- a/src/arch/alpha/isa/opcdec.isa
+++ b/src/arch/alpha/isa/opcdec.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// OPCDEC fault instructions
+//
output header {{
/**
diff --git a/src/arch/alpha/isa/pal.isa b/src/arch/alpha/isa/pal.isa
index e07bea5a8..f4c10da1d 100644
--- a/src/arch/alpha/isa/pal.isa
+++ b/src/arch/alpha/isa/pal.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// PAL calls & PAL-specific instructions
+//
output header {{
/**
@@ -259,9 +266,11 @@ output decoder {{
}
}};
-def format HwMoveIPR(code) {{
+def format HwMoveIPR(code, *flags) {{
+ all_flags = ['IprAccessOp']
+ all_flags += flags
iop = InstObjParams(name, Name, 'HwMoveIPR', CodeBlock(code),
- ['IprAccessOp'])
+ all_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
diff --git a/src/arch/alpha/isa/unimp.isa b/src/arch/alpha/isa/unimp.isa
index 392522801..6cfaa6991 100644
--- a/src/arch/alpha/isa/unimp.isa
+++ b/src/arch/alpha/isa/unimp.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Unimplemented instructions
+//
output header {{
/**
diff --git a/src/arch/alpha/isa/unknown.isa b/src/arch/alpha/isa/unknown.isa
index 47d166255..1e95ccf68 100644
--- a/src/arch/alpha/isa/unknown.isa
+++ b/src/arch/alpha/isa/unknown.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Unknown instructions
+//
output decoder {{
std::string
diff --git a/src/arch/alpha/isa/util.isa b/src/arch/alpha/isa/util.isa
index 9fbbf6636..8700d1e0b 100644
--- a/src/arch/alpha/isa/util.isa
+++ b/src/arch/alpha/isa/util.isa
@@ -25,6 +25,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Utility functions for execute methods
+//
output exec {{
diff --git a/src/arch/alpha/isa_traits.hh b/src/arch/alpha/isa_traits.hh
index 65c72115b..663b144ab 100644
--- a/src/arch/alpha/isa_traits.hh
+++ b/src/arch/alpha/isa_traits.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ARCH_ALPHA_ISA_TRAITS_HH__
diff --git a/src/arch/alpha/linux/aligned.hh b/src/arch/alpha/linux/aligned.hh
index cabecb283..c4687e348 100644
--- a/src/arch/alpha/linux/aligned.hh
+++ b/src/arch/alpha/linux/aligned.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __ARCH_ALPHA_LINUX_ALIGNED_HH__
diff --git a/src/arch/alpha/linux/linux.cc b/src/arch/alpha/linux/linux.cc
index f123ae1fe..bc0d48e0d 100644
--- a/src/arch/alpha/linux/linux.cc
+++ b/src/arch/alpha/linux/linux.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/alpha/linux/linux.hh"
diff --git a/src/arch/alpha/linux/linux.hh b/src/arch/alpha/linux/linux.hh
index f04e2bfa8..09988bab2 100644
--- a/src/arch/alpha/linux/linux.hh
+++ b/src/arch/alpha/linux/linux.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ALPHA_ALPHA_LINUX_HH
diff --git a/src/arch/alpha/linux/process.cc b/src/arch/alpha/linux/process.cc
index 9f4f65db8..997c78ac9 100644
--- a/src/arch/alpha/linux/process.cc
+++ b/src/arch/alpha/linux/process.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/alpha/linux/linux.hh"
@@ -31,7 +34,7 @@
#include "arch/alpha/isa_traits.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/linux/linux.hh"
#include "sim/process.hh"
@@ -45,9 +48,9 @@ using namespace AlphaISA;
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -55,7 +58,7 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
strcpy(name->machine, "alpha");
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
@@ -64,18 +67,18 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
/// different in practice from those used by Tru64 processes.
static SyscallReturn
osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
- // unsigned nbytes = xc->getSyscallArg(2);
+ unsigned op = tc->getSyscallArg(0);
+ // unsigned nbytes = tc->getSyscallArg(2);
switch (op) {
case 45: { // GSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
// I don't think this exactly matches the HW FPCR
*fpcr = 0;
- fpcr.copyOut(xc->getMemPort());
+ fpcr.copyOut(tc->getMemPort());
return 0;
}
@@ -91,17 +94,17 @@ osf_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target osf_setsysinfo() handler.
static SyscallReturn
osf_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
- // unsigned nbytes = xc->getSyscallArg(2);
+ unsigned op = tc->getSyscallArg(0);
+ // unsigned nbytes = tc->getSyscallArg(2);
switch (op) {
case 14: { // SSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
// I don't think this exactly matches the HW FPCR
- fpcr.copyIn(xc->getMemPort());
+ fpcr.copyIn(tc->getMemPort());
DPRINTFR(SyscallVerbose, "osf_setsysinfo(SSI_IEEE_FP_CONTROL): "
" setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr));
return 0;
diff --git a/src/arch/alpha/linux/process.hh b/src/arch/alpha/linux/process.hh
index 2e0566665..9cc7dc7b6 100644
--- a/src/arch/alpha/linux/process.hh
+++ b/src/arch/alpha/linux/process.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ALPHA_LINUX_PROCESS_HH__
diff --git a/src/arch/alpha/linux/system.cc b/src/arch/alpha/linux/system.cc
index cdb96096c..9fe63c390 100644
--- a/src/arch/alpha/linux/system.cc
+++ b/src/arch/alpha/linux/system.cc
@@ -24,6 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
+ * Nathan Binkert
+ * Steve Reinhardt
*/
/**
@@ -41,7 +46,7 @@
#include "arch/alpha/linux/threadinfo.hh"
#include "arch/alpha/system.hh"
#include "base/loader/symtab.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "dev/platform.hh"
#include "kern/linux/printk.hh"
@@ -132,24 +137,6 @@ LinuxAlphaSystem::LinuxAlphaSystem(Params *p)
} else {
printThreadEvent = NULL;
}
-
- if (params()->bin_int) {
- intStartEvent = addPalFuncEvent<InterruptStartEvent>("sys_int_21");
- if (!intStartEvent)
- panic("could not find symbol: sys_int_21\n");
-
- intEndEvent = addPalFuncEvent<InterruptEndEvent>("rti_to_kern");
- if (!intEndEvent)
- panic("could not find symbol: rti_to_kern\n");
-
- intEndEvent2 = addPalFuncEvent<InterruptEndEvent>("rti_to_user");
- if (!intEndEvent2)
- panic("could not find symbol: rti_to_user\n");
-
- intEndEvent3 = addKernelFuncEvent<InterruptEndEvent>("do_softirq");
- if (!intEndEvent3)
- panic("could not find symbol: do_softirq\n");
- }
}
LinuxAlphaSystem::~LinuxAlphaSystem()
@@ -163,37 +150,37 @@ LinuxAlphaSystem::~LinuxAlphaSystem()
delete debugPrintkEvent;
delete idleStartEvent;
delete printThreadEvent;
- delete intStartEvent;
- delete intEndEvent;
- delete intEndEvent2;
}
void
-LinuxAlphaSystem::setDelayLoop(ExecContext *xc)
+LinuxAlphaSystem::setDelayLoop(ThreadContext *tc)
{
Addr addr = 0;
if (kernelSymtab->findAddress("loops_per_jiffy", addr)) {
- Tick cpuFreq = xc->getCpuPtr()->frequency();
+ Tick cpuFreq = tc->getCpuPtr()->frequency();
Tick intrFreq = platform->intrFrequency();
- xc->getVirtPort(xc)->write(addr,
- (uint32_t)((cpuFreq / intrFreq) * 0.9988));
+ VirtualPort *vp;
+
+ vp = tc->getVirtPort();
+ vp->writeHtoG(addr, (uint32_t)((cpuFreq / intrFreq) * 0.9988));
+ tc->delVirtPort(vp);
}
}
void
-LinuxAlphaSystem::SkipDelayLoopEvent::process(ExecContext *xc)
+LinuxAlphaSystem::SkipDelayLoopEvent::process(ThreadContext *tc)
{
- SkipFuncEvent::process(xc);
+ SkipFuncEvent::process(tc);
// calculate and set loops_per_jiffy
- ((LinuxAlphaSystem *)xc->getSystemPtr())->setDelayLoop(xc);
+ ((LinuxAlphaSystem *)tc->getSystemPtr())->setDelayLoop(tc);
}
void
-LinuxAlphaSystem::PrintThreadInfo::process(ExecContext *xc)
+LinuxAlphaSystem::PrintThreadInfo::process(ThreadContext *tc)
{
- Linux::ThreadInfo ti(xc);
+ Linux::ThreadInfo ti(tc);
DPRINTF(Thread, "Currently Executing Thread %s, pid %d, started at: %d\n",
ti.curTaskName(), ti.curTaskPID(), ti.curTaskStart());
@@ -216,10 +203,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
Param<uint64_t> system_type;
Param<uint64_t> system_rev;
- Param<bool> bin;
- VectorParam<string> binned_fns;
- Param<bool> bin_int;
-
END_DECLARE_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
@@ -234,10 +217,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
- INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
- INIT_PARAM_DFLT(bin, "is this system to be binned", false),
- INIT_PARAM(binned_fns, "functions to be broken down and binned"),
- INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10)
END_INIT_SIM_OBJECT_PARAMS(LinuxAlphaSystem)
@@ -255,9 +235,6 @@ CREATE_SIM_OBJECT(LinuxAlphaSystem)
p->readfile = readfile;
p->system_type = system_type;
p->system_rev = system_rev;
- p->bin = bin;
- p->binned_fns = binned_fns;
- p->bin_int = bin_int;
return new LinuxAlphaSystem(p);
}
diff --git a/src/arch/alpha/linux/system.hh b/src/arch/alpha/linux/system.hh
index 0c1fb037e..6921ba820 100644
--- a/src/arch/alpha/linux/system.hh
+++ b/src/arch/alpha/linux/system.hh
@@ -24,12 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
+ * Nathan Binkert
*/
#ifndef __ARCH_ALPHA_LINUX_SYSTEM_HH__
#define __ARCH_ALPHA_LINUX_SYSTEM_HH__
-class ExecContext;
+class ThreadContext;
class BreakPCEvent;
class IdleStartEvent;
@@ -41,7 +45,7 @@ using namespace AlphaISA;
using namespace Linux;
/**
- * This class contains linux specific system code (Loading, Events, Binning).
+ * This class contains linux specific system code (Loading, Events).
* It points to objects that are the system binaries to load and patches them
* appropriately to work in simulator.
*/
@@ -53,7 +57,7 @@ class LinuxAlphaSystem : public AlphaSystem
public:
SkipDelayLoopEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: SkipFuncEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
class PrintThreadInfo : public PCEvent
@@ -61,7 +65,7 @@ class LinuxAlphaSystem : public AlphaSystem
public:
PrintThreadInfo(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
@@ -120,18 +124,6 @@ class LinuxAlphaSystem : public AlphaSystem
*/
PrintThreadInfo *printThreadEvent;
- /**
- * Event to bin Interrupts seperately from kernel code
- */
- InterruptStartEvent *intStartEvent;
-
- /**
- * Event to bin Interrupts seperately from kernel code
- */
- InterruptEndEvent *intEndEvent;
- InterruptEndEvent *intEndEvent2;
- InterruptEndEvent *intEndEvent3;
-
/** Grab the PCBB of the idle process when it starts */
IdleStartEvent *idleStartEvent;
@@ -139,7 +131,7 @@ class LinuxAlphaSystem : public AlphaSystem
LinuxAlphaSystem(Params *p);
~LinuxAlphaSystem();
- void setDelayLoop(ExecContext *xc);
+ void setDelayLoop(ThreadContext *tc);
};
#endif // __ARCH_ALPHA_LINUX_SYSTEM_HH__
diff --git a/src/arch/alpha/linux/thread_info.hh b/src/arch/alpha/linux/thread_info.hh
index 88791b00d..78257da56 100644
--- a/src/arch/alpha/linux/thread_info.hh
+++ b/src/arch/alpha/linux/thread_info.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __ARCH_ALPHA_LINUX_THREAD_INFO_H__
diff --git a/src/arch/alpha/linux/threadinfo.hh b/src/arch/alpha/linux/threadinfo.hh
index 8f03c9314..caeb69f15 100644
--- a/src/arch/alpha/linux/threadinfo.hh
+++ b/src/arch/alpha/linux/threadinfo.hh
@@ -24,13 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__
#define __ARCH_ALPHA_LINUX_LINUX_TREADNIFO_HH__
#include "arch/alpha/linux/thread_info.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/linux/sched.hh"
#include "sim/vptr.hh"
@@ -39,10 +42,10 @@ namespace Linux {
class ThreadInfo
{
private:
- ExecContext *xc;
+ ThreadContext *tc;
public:
- ThreadInfo(ExecContext *exec) : xc(exec) {}
+ ThreadInfo(ThreadContext *_tc) : tc(_tc) {}
~ThreadInfo() {}
inline VPtr<thread_info>
@@ -54,15 +57,15 @@ class ThreadInfo
* thread_info struct. So we can get the address by masking off
* the lower 14 bits.
*/
- current = xc->readIntReg(TheISA::StackPointerReg) & ~0x3fff;
- return VPtr<thread_info>(xc, current);
+ current = tc->readIntReg(TheISA::StackPointerReg) & ~0x3fff;
+ return VPtr<thread_info>(tc, current);
}
inline VPtr<task_struct>
curTaskInfo()
{
Addr task = curThreadInfo()->task;
- return VPtr<task_struct>(xc, task);
+ return VPtr<task_struct>(tc, task);
}
std::string
diff --git a/src/arch/alpha/osfpal.cc b/src/arch/alpha/osfpal.cc
index a48bd28d9..ed1d255a6 100644
--- a/src/arch/alpha/osfpal.cc
+++ b/src/arch/alpha/osfpal.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "arch/alpha/osfpal.hh"
diff --git a/src/arch/alpha/osfpal.hh b/src/arch/alpha/osfpal.hh
index f46d2bce1..cf3940b85 100644
--- a/src/arch/alpha/osfpal.hh
+++ b/src/arch/alpha/osfpal.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __OSFPAL_HH__
diff --git a/src/arch/alpha/process.cc b/src/arch/alpha/process.cc
index 25ee79692..970292cd8 100644
--- a/src/arch/alpha/process.cc
+++ b/src/arch/alpha/process.cc
@@ -24,59 +24,22 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/alpha/constants.hh"
#include "arch/alpha/process.hh"
-#include "arch/alpha/linux/process.hh"
-#include "arch/alpha/tru64/process.hh"
#include "base/loader/object_file.hh"
#include "base/misc.hh"
-#include "cpu/exec_context.hh"
-#include "sim/builder.hh"
+#include "cpu/thread_context.hh"
#include "sim/system.hh"
using namespace AlphaISA;
using namespace std;
-AlphaLiveProcess *
-AlphaLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
- int stdout_fd, int stderr_fd, std::string executable,
- std::vector<std::string> &argv, std::vector<std::string> &envp)
-{
- AlphaLiveProcess *process = NULL;
-
- ObjectFile *objFile = createObjectFile(executable);
- if (objFile == NULL) {
- fatal("Can't load object file %s", executable);
- }
-
-
- if (objFile->getArch() != ObjectFile::Alpha)
- fatal("Object file does not match architecture.");
- switch (objFile->getOpSys()) {
- case ObjectFile::Tru64:
- process = new AlphaTru64Process(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
- break;
-
- case ObjectFile::Linux:
- process = new AlphaLinuxProcess(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
- break;
-
- default:
- fatal("Unknown/unsupported operating system.");
- }
-
- if (process == NULL)
- fatal("Unknown error creating process object.");
- return process;
-}
-
AlphaLiveProcess::AlphaLiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv, std::vector<std::string> &envp)
@@ -104,64 +67,7 @@ AlphaLiveProcess::startup()
{
argsInit(MachineBytes, VMPageSize);
- execContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer());
+ threadContexts[0]->setIntReg(GlobalPointerReg, objFile->globalPointer());
}
-
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess)
-
- VectorParam<string> cmd;
- Param<string> executable;
- Param<string> input;
- Param<string> output;
- VectorParam<string> env;
- SimObjectParam<System *> system;
-
-END_DECLARE_SIM_OBJECT_PARAMS(AlphaLiveProcess)
-
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess)
-
- INIT_PARAM(cmd, "command line (executable plus arguments)"),
- INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
- INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
- INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
- INIT_PARAM(env, "environment settings"),
- INIT_PARAM(system, "system")
-
-END_INIT_SIM_OBJECT_PARAMS(AlphaLiveProcess)
-
-
-CREATE_SIM_OBJECT(AlphaLiveProcess)
-{
- string in = input;
- string out = output;
-
- // initialize file descriptors to default: same as simulator
- int stdin_fd, stdout_fd, stderr_fd;
-
- if (in == "stdin" || in == "cin")
- stdin_fd = STDIN_FILENO;
- else
- stdin_fd = Process::openInputFile(input);
-
- if (out == "stdout" || out == "cout")
- stdout_fd = STDOUT_FILENO;
- else if (out == "stderr" || out == "cerr")
- stdout_fd = STDERR_FILENO;
- else
- stdout_fd = Process::openOutputFile(out);
-
- stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
-
- return AlphaLiveProcess::create(getInstanceName(), system,
- stdin_fd, stdout_fd, stderr_fd,
- (string)executable == "" ? cmd[0] : executable,
- cmd, env);
-}
-
-
-REGISTER_SIM_OBJECT("AlphaLiveProcess", AlphaLiveProcess)
-
diff --git a/src/arch/alpha/process.hh b/src/arch/alpha/process.hh
index d97b36e2d..5d5c9a52e 100644
--- a/src/arch/alpha/process.hh
+++ b/src/arch/alpha/process.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __ALPHA_PROCESS_HH__
@@ -46,18 +49,6 @@ class AlphaLiveProcess : public LiveProcess
std::vector<std::string> &envp);
void startup();
-
- public:
- // this function is used to create the LiveProcess object, since
- // we can't tell which subclass of LiveProcess to use until we
- // open and look at the object file.
- static AlphaLiveProcess *create(const std::string &nm,
- System *_system,
- int stdin_fd, int stdout_fd, int stderr_fd,
- std::string executable,
- std::vector<std::string> &argv,
- std::vector<std::string> &envp);
-
};
diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh
index af01b7829..1025412cd 100644
--- a/src/arch/alpha/regfile.hh
+++ b/src/arch/alpha/regfile.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_REGFILE_HH__
@@ -34,7 +36,7 @@
#include "sim/faults.hh"
class Checkpoint;
-class ExecContext;
+class ThreadContext;
namespace AlphaISA
{
@@ -60,6 +62,8 @@ namespace AlphaISA
void unserialize(Checkpoint *cp, const std::string &section);
+ void clear()
+ { bzero(regs, sizeof(regs)); }
};
class FloatRegFile
@@ -75,6 +79,8 @@ namespace AlphaISA
void unserialize(Checkpoint *cp, const std::string &section);
+ void clear()
+ { bzero(d, sizeof(d)); }
};
class MiscRegFile {
@@ -88,7 +94,7 @@ namespace AlphaISA
MiscReg readReg(int misc_reg);
MiscReg readRegWithEffect(int misc_reg, Fault &fault,
- ExecContext *xc);
+ ThreadContext *tc);
//These functions should be removed once the simplescalar cpu model
//has been replaced.
@@ -98,8 +104,14 @@ namespace AlphaISA
Fault setReg(int misc_reg, const MiscReg &val);
Fault setRegWithEffect(int misc_reg, const MiscReg &val,
- ExecContext *xc);
+ ThreadContext *tc);
+ void clear()
+ {
+ fpcr = uniq = 0;
+ lock_flag = 0;
+ lock_addr = 0;
+ }
#if FULL_SYSTEM
protected:
typedef uint64_t InternalProcReg;
@@ -107,9 +119,9 @@ namespace AlphaISA
InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
private:
- InternalProcReg readIpr(int idx, Fault &fault, ExecContext *xc);
+ InternalProcReg readIpr(int idx, Fault &fault, ThreadContext *tc);
- Fault setIpr(int idx, InternalProcReg val, ExecContext *xc);
+ Fault setIpr(int idx, InternalProcReg val, ThreadContext *tc);
#endif
friend class RegFile;
};
@@ -169,9 +181,9 @@ namespace AlphaISA
void clear()
{
- bzero(&intRegFile, sizeof(intRegFile));
- bzero(&floatRegFile, sizeof(floatRegFile));
- bzero(&miscRegFile, sizeof(miscRegFile));
+ intRegFile.clear();
+ floatRegFile.clear();
+ miscRegFile.clear();
}
MiscReg readMiscReg(int miscReg)
@@ -180,10 +192,10 @@ namespace AlphaISA
}
MiscReg readMiscRegWithEffect(int miscReg,
- Fault &fault, ExecContext *xc)
+ Fault &fault, ThreadContext *tc)
{
fault = NoFault;
- return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ return miscRegFile.readRegWithEffect(miscReg, fault, tc);
}
Fault setMiscReg(int miscReg, const MiscReg &val)
@@ -192,9 +204,9 @@ namespace AlphaISA
}
Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
- ExecContext * xc)
+ ThreadContext * tc)
{
- return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ return miscRegFile.setRegWithEffect(miscReg, val, tc);
}
FloatReg readFloatReg(int floatReg)
@@ -266,12 +278,12 @@ namespace AlphaISA
}
};
- void copyRegs(ExecContext *src, ExecContext *dest);
+ void copyRegs(ThreadContext *src, ThreadContext *dest);
- void copyMiscRegs(ExecContext *src, ExecContext *dest);
+ void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
#if FULL_SYSTEM
- void copyIprs(ExecContext *src, ExecContext *dest);
+ void copyIprs(ThreadContext *src, ThreadContext *dest);
#endif
} // namespace AlphaISA
diff --git a/src/arch/alpha/stacktrace.cc b/src/arch/alpha/stacktrace.cc
index 8691e12dc..d70a4d6dd 100644
--- a/src/arch/alpha/stacktrace.cc
+++ b/src/arch/alpha/stacktrace.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <string>
@@ -34,36 +36,42 @@
#include "base/bitfield.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "sim/system.hh"
using namespace std;
using namespace AlphaISA;
-ProcessInfo::ProcessInfo(ExecContext *_xc)
- : xc(_xc)
+ProcessInfo::ProcessInfo(ThreadContext *_tc)
+ : tc(_tc)
{
Addr addr = 0;
- if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
+ VirtualPort *vp;
+
+ vp = tc->getVirtPort();
+
+ if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_size", addr))
panic("thread info not compiled into kernel\n");
- thread_info_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+ thread_info_size = vp->readGtoH<int32_t>(addr);
- if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
+ if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_size", addr))
panic("thread info not compiled into kernel\n");
- task_struct_size = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+ task_struct_size = vp->readGtoH<int32_t>(addr);
- if (!xc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
+ if (!tc->getSystemPtr()->kernelSymtab->findAddress("thread_info_task", addr))
panic("thread info not compiled into kernel\n");
- task_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+ task_off = vp->readGtoH<int32_t>(addr);
- if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
+ if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_pid", addr))
panic("thread info not compiled into kernel\n");
- pid_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+ pid_off = vp->readGtoH<int32_t>(addr);
- if (!xc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
+ if (!tc->getSystemPtr()->kernelSymtab->findAddress("task_struct_comm", addr))
panic("thread info not compiled into kernel\n");
- name_off = gtoh(xc->getVirtPort()->read<int32_t>(addr));
+ name_off = vp->readGtoH<int32_t>(addr);
+
+ tc->delVirtPort(vp);
}
Addr
@@ -73,7 +81,15 @@ ProcessInfo::task(Addr ksp) const
if (base == ULL(0xfffffc0000000000))
return 0;
- return gtoh(xc->getVirtPort()->read<Addr>(base + task_off));
+ Addr tsk;
+
+ VirtualPort *vp;
+
+ vp = tc->getVirtPort();
+ tsk = vp->readGtoH<Addr>(base + task_off);
+ tc->delVirtPort(vp);
+
+ return tsk;
}
int
@@ -83,7 +99,15 @@ ProcessInfo::pid(Addr ksp) const
if (!task)
return -1;
- return gtoh(xc->getVirtPort()->read<uint16_t>(task + pid_off));
+ uint16_t pd;
+
+ VirtualPort *vp;
+
+ vp = tc->getVirtPort();
+ pd = vp->readGtoH<uint16_t>(task + pid_off);
+ tc->delVirtPort(vp);
+
+ return pd;
}
string
@@ -94,7 +118,7 @@ ProcessInfo::name(Addr ksp) const
return "console";
char comm[256];
- CopyStringOut(xc, comm, task + name_off, sizeof(comm));
+ CopyStringOut(tc, comm, task + name_off, sizeof(comm));
if (!comm[0])
return "startup";
@@ -102,14 +126,14 @@ ProcessInfo::name(Addr ksp) const
}
StackTrace::StackTrace()
- : xc(0), stack(64)
+ : tc(0), stack(64)
{
}
-StackTrace::StackTrace(ExecContext *_xc, StaticInstPtr inst)
- : xc(0), stack(64)
+StackTrace::StackTrace(ThreadContext *_tc, StaticInstPtr inst)
+ : tc(0), stack(64)
{
- trace(_xc, inst);
+ trace(_tc, inst);
}
StackTrace::~StackTrace()
@@ -117,15 +141,15 @@ StackTrace::~StackTrace()
}
void
-StackTrace::trace(ExecContext *_xc, bool is_call)
+StackTrace::trace(ThreadContext *_tc, bool is_call)
{
- xc = _xc;
+ tc = _tc;
- bool usermode = (xc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
+ bool usermode = (tc->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
- Addr pc = xc->readNextPC();
- bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
- pc <= xc->getSystemPtr()->kernelEnd;
+ Addr pc = tc->readNextPC();
+ bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
+ pc <= tc->getSystemPtr()->kernelEnd;
if (usermode) {
stack.push_back(user);
@@ -137,8 +161,8 @@ StackTrace::trace(ExecContext *_xc, bool is_call)
return;
}
- SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
- Addr ksp = xc->readIntReg(TheISA::StackPointerReg);
+ SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
+ Addr ksp = tc->readIntReg(TheISA::StackPointerReg);
Addr bottom = ksp & ~0x3fff;
Addr addr;
@@ -147,7 +171,7 @@ StackTrace::trace(ExecContext *_xc, bool is_call)
panic("could not find address %#x", pc);
stack.push_back(addr);
- pc = xc->readPC();
+ pc = tc->readPC();
}
Addr ra;
@@ -179,8 +203,8 @@ StackTrace::trace(ExecContext *_xc, bool is_call)
return;
}
- bool kernel = xc->getSystemPtr()->kernelStart <= pc &&
- pc <= xc->getSystemPtr()->kernelEnd;
+ bool kernel = tc->getSystemPtr()->kernelStart <= pc &&
+ pc <= tc->getSystemPtr()->kernelEnd;
if (!kernel)
return;
@@ -194,22 +218,22 @@ StackTrace::trace(ExecContext *_xc, bool is_call)
bool
StackTrace::isEntry(Addr addr)
{
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp12))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp12))
return true;
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp7))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp7))
return true;
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp11))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp11))
return true;
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp21))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp21))
return true;
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp9))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp9))
return true;
- if (addr == xc->readMiscReg(AlphaISA::IPR_PALtemp2))
+ if (addr == tc->readMiscReg(AlphaISA::IPR_PALtemp2))
return true;
return false;
@@ -294,7 +318,7 @@ StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
for (Addr pc = func; pc < callpc; pc += sizeof(MachInst)) {
MachInst inst;
- CopyOut(xc, (uint8_t *)&inst, pc, sizeof(MachInst));
+ CopyOut(tc, (uint8_t *)&inst, pc, sizeof(MachInst));
int reg, disp;
if (decodeStack(inst, disp)) {
@@ -305,7 +329,7 @@ StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
size += disp;
} else if (decodeSave(inst, reg, disp)) {
if (!ra && reg == ReturnAddressReg) {
- CopyOut(xc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
+ CopyOut(tc, (uint8_t *)&ra, sp + disp, sizeof(Addr));
if (!ra) {
// panic("no return address value pc=%#x\n", pc);
return false;
@@ -321,8 +345,8 @@ StackTrace::decodePrologue(Addr sp, Addr callpc, Addr func,
void
StackTrace::dump()
{
- StringWrap name(xc->getCpuPtr()->name());
- SymbolTable *symtab = xc->getSystemPtr()->kernelSymtab;
+ StringWrap name(tc->getCpuPtr()->name());
+ SymbolTable *symtab = tc->getSystemPtr()->kernelSymtab;
DPRINTFN("------ Stack ------\n");
diff --git a/src/arch/alpha/stacktrace.hh b/src/arch/alpha/stacktrace.hh
index 1d8d97a79..d12aee211 100644
--- a/src/arch/alpha/stacktrace.hh
+++ b/src/arch/alpha/stacktrace.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ARCH_ALPHA_STACKTRACE_HH__
@@ -32,13 +34,13 @@
#include "base/trace.hh"
#include "cpu/static_inst.hh"
-class ExecContext;
+class ThreadContext;
class StackTrace;
class ProcessInfo
{
private:
- ExecContext *xc;
+ ThreadContext *tc;
int thread_info_size;
int task_struct_size;
@@ -47,7 +49,7 @@ class ProcessInfo
int name_off;
public:
- ProcessInfo(ExecContext *_xc);
+ ProcessInfo(ThreadContext *_tc);
Addr task(Addr ksp) const;
int pid(Addr ksp) const;
@@ -59,7 +61,7 @@ class StackTrace
protected:
typedef TheISA::MachInst MachInst;
private:
- ExecContext *xc;
+ ThreadContext *tc;
std::vector<Addr> stack;
private:
@@ -68,21 +70,21 @@ class StackTrace
bool decodeSave(MachInst inst, int &reg, int &disp);
bool decodeStack(MachInst inst, int &disp);
- void trace(ExecContext *xc, bool is_call);
+ void trace(ThreadContext *tc, bool is_call);
public:
StackTrace();
- StackTrace(ExecContext *xc, StaticInstPtr inst);
+ StackTrace(ThreadContext *tc, StaticInstPtr inst);
~StackTrace();
void clear()
{
- xc = 0;
+ tc = 0;
stack.clear();
}
- bool valid() const { return xc != NULL; }
- bool trace(ExecContext *xc, StaticInstPtr inst);
+ bool valid() const { return tc != NULL; }
+ bool trace(ThreadContext *tc, StaticInstPtr inst);
public:
const std::vector<Addr> &getstack() const { return stack; }
@@ -104,7 +106,7 @@ class StackTrace
};
inline bool
-StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+StackTrace::trace(ThreadContext *tc, StaticInstPtr inst)
{
if (!inst->isCall() && !inst->isReturn())
return false;
@@ -112,7 +114,7 @@ StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
if (valid())
clear();
- trace(xc, !inst->isReturn());
+ trace(tc, !inst->isReturn());
return true;
}
diff --git a/src/arch/alpha/system.cc b/src/arch/alpha/system.cc
index 4234019cd..dce7365aa 100644
--- a/src/arch/alpha/system.cc
+++ b/src/arch/alpha/system.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#include "arch/alpha/ev5.hh"
@@ -230,10 +233,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem)
Param<uint64_t> system_type;
Param<uint64_t> system_rev;
- Param<bool> bin;
- VectorParam<std::string> binned_fns;
- Param<bool> bin_int;
-
END_DECLARE_SIM_OBJECT_PARAMS(AlphaSystem)
BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
@@ -248,10 +247,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 34),
- INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10),
- INIT_PARAM_DFLT(bin, "is this system to be binned", false),
- INIT_PARAM(binned_fns, "functions to be broken down and binned"),
- INIT_PARAM_DFLT(bin_int, "is interrupt code binned seperately?", true)
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 1<<10)
END_INIT_SIM_OBJECT_PARAMS(AlphaSystem)
@@ -269,9 +265,6 @@ CREATE_SIM_OBJECT(AlphaSystem)
p->readfile = readfile;
p->system_type = system_type;
p->system_rev = system_rev;
- p->bin = bin;
- p->binned_fns = binned_fns;
- p->bin_int = bin_int;
return new AlphaSystem(p);
}
diff --git a/src/arch/alpha/system.hh b/src/arch/alpha/system.hh
index 924e16826..0f4f64581 100644
--- a/src/arch/alpha/system.hh
+++ b/src/arch/alpha/system.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __ARCH_ALPHA_SYSTEM_HH__
diff --git a/src/arch/alpha/tlb.cc b/src/arch/alpha/tlb.cc
index 05b02d74b..c6684274b 100644
--- a/src/arch/alpha/tlb.cc
+++ b/src/arch/alpha/tlb.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Andrew Schultz
*/
#include <string>
@@ -34,7 +38,7 @@
#include "base/str.hh"
#include "base/trace.hh"
#include "config/alpha_tlaser.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "sim/builder.hh"
using namespace std;
@@ -282,7 +286,7 @@ AlphaITB::regStats()
Fault
-AlphaITB::translate(RequestPtr &req, ExecContext *xc) const
+AlphaITB::translate(RequestPtr &req, ThreadContext *tc) const
{
if (AlphaISA::PcPAL(req->getVaddr())) {
// strip off PAL PC marker (lsb is 1)
@@ -304,13 +308,13 @@ AlphaITB::translate(RequestPtr &req, ExecContext *xc) const
// VA<42:41> == 2, VA<39:13> maps directly to PA<39:13> for EV5
// VA<47:41> == 0x7e, VA<40:13> maps directly to PA<40:13> for EV6
#if ALPHA_TLASER
- if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
+ if ((MCSR_SP(tc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
VAddrSpaceEV5(req->getVaddr()) == 2) {
#else
if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) {
#endif
// only valid in kernel mode
- if (ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM)) !=
+ if (ICM_CM(tc->readMiscReg(AlphaISA::IPR_ICM)) !=
AlphaISA::mode_kernel) {
acv++;
return new ItbAcvFault(req->getVaddr());
@@ -328,7 +332,7 @@ AlphaITB::translate(RequestPtr &req, ExecContext *xc) const
} else {
// not a physical address: need to look up pte
- int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN));
+ int asn = DTB_ASN_ASN(tc->readMiscReg(AlphaISA::IPR_DTB_ASN));
AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(),
asn);
@@ -343,7 +347,7 @@ AlphaITB::translate(RequestPtr &req, ExecContext *xc) const
// check permissions for this access
if (!(pte->xre &
- (1 << ICM_CM(xc->readMiscReg(AlphaISA::IPR_ICM))))) {
+ (1 << ICM_CM(tc->readMiscReg(AlphaISA::IPR_ICM))))) {
// instruction access fault
acv++;
return new ItbAcvFault(req->getVaddr());
@@ -439,12 +443,12 @@ AlphaDTB::regStats()
}
Fault
-AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const
+AlphaDTB::translate(RequestPtr &req, ThreadContext *tc, bool write) const
{
- Addr pc = xc->readPC();
+ Addr pc = tc->readPC();
AlphaISA::mode_type mode =
- (AlphaISA::mode_type)DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM));
+ (AlphaISA::mode_type)DTB_CM_CM(tc->readMiscReg(AlphaISA::IPR_DTB_CM));
/**
@@ -460,7 +464,7 @@ AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const
if (pc & 0x1) {
mode = (req->getFlags() & ALTMODE) ?
(AlphaISA::mode_type)ALT_MODE_AM(
- xc->readMiscReg(AlphaISA::IPR_ALT_MODE))
+ tc->readMiscReg(AlphaISA::IPR_ALT_MODE))
: AlphaISA::mode_kernel;
}
@@ -478,14 +482,14 @@ AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const
// Check for "superpage" mapping
#if ALPHA_TLASER
- if ((MCSR_SP(xc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
+ if ((MCSR_SP(tc->readMiscReg(AlphaISA::IPR_MCSR)) & 2) &&
VAddrSpaceEV5(req->getVaddr()) == 2) {
#else
if (VAddrSpaceEV6(req->getVaddr()) == 0x7e) {
#endif
// only valid in kernel mode
- if (DTB_CM_CM(xc->readMiscReg(AlphaISA::IPR_DTB_CM)) !=
+ if (DTB_CM_CM(tc->readMiscReg(AlphaISA::IPR_DTB_CM)) !=
AlphaISA::mode_kernel) {
if (write) { write_acv++; } else { read_acv++; }
uint64_t flags = ((write ? MM_STAT_WR_MASK : 0) |
@@ -509,7 +513,7 @@ AlphaDTB::translate(RequestPtr &req, ExecContext *xc, bool write) const
else
read_accesses++;
- int asn = DTB_ASN_ASN(xc->readMiscReg(AlphaISA::IPR_DTB_ASN));
+ int asn = DTB_ASN_ASN(tc->readMiscReg(AlphaISA::IPR_DTB_ASN));
// not a physical address: need to look up pte
AlphaISA::PTE *pte = lookup(AlphaISA::VAddr(req->getVaddr()).vpn(),
diff --git a/src/arch/alpha/tlb.hh b/src/arch/alpha/tlb.hh
index f6256020e..07d01fa5c 100644
--- a/src/arch/alpha/tlb.hh
+++ b/src/arch/alpha/tlb.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __ALPHA_MEMORY_HH__
@@ -38,7 +41,7 @@
#include "mem/request.hh"
#include "sim/sim_object.hh"
-class ExecContext;
+class ThreadContext;
class AlphaTLB : public SimObject
{
@@ -92,7 +95,7 @@ class AlphaITB : public AlphaTLB
AlphaITB(const std::string &name, int size);
virtual void regStats();
- Fault translate(RequestPtr &req, ExecContext *xc) const;
+ Fault translate(RequestPtr &req, ThreadContext *tc) const;
};
class AlphaDTB : public AlphaTLB
@@ -115,7 +118,7 @@ class AlphaDTB : public AlphaTLB
AlphaDTB(const std::string &name, int size);
virtual void regStats();
- Fault translate(RequestPtr &req, ExecContext *xc, bool write) const;
+ Fault translate(RequestPtr &req, ThreadContext *tc, bool write) const;
};
#endif // __ALPHA_MEMORY_HH__
diff --git a/src/arch/alpha/tru64/process.cc b/src/arch/alpha/tru64/process.cc
index 55f75f7d0..82e44b9e7 100644
--- a/src/arch/alpha/tru64/process.cc
+++ b/src/arch/alpha/tru64/process.cc
@@ -24,13 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/alpha/tru64/tru64.hh"
#include "arch/alpha/isa_traits.hh"
#include "arch/alpha/tru64/process.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/tru64/tru64.hh"
#include "sim/process.hh"
@@ -42,9 +45,9 @@ using namespace AlphaISA;
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<AlphaTru64::utsname> name(xc->getSyscallArg(0));
+ TypedBufferArg<AlphaTru64::utsname> name(tc->getSyscallArg(0));
strcpy(name->sysname, "OSF1");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -52,43 +55,43 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
strcpy(name->version, "732");
strcpy(name->machine, "alpha");
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
/// Target getsysyinfo() handler.
static SyscallReturn
getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
- unsigned nbytes = xc->getSyscallArg(2);
+ unsigned op = tc->getSyscallArg(0);
+ unsigned nbytes = tc->getSyscallArg(2);
switch (op) {
case AlphaTru64::GSI_MAX_CPU: {
- TypedBufferArg<uint32_t> max_cpu(xc->getSyscallArg(1));
+ TypedBufferArg<uint32_t> max_cpu(tc->getSyscallArg(1));
*max_cpu = htog((uint32_t)process->numCpus());
- max_cpu.copyOut(xc->getMemPort());
+ max_cpu.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_CPUS_IN_BOX: {
- TypedBufferArg<uint32_t> cpus_in_box(xc->getSyscallArg(1));
+ TypedBufferArg<uint32_t> cpus_in_box(tc->getSyscallArg(1));
*cpus_in_box = htog((uint32_t)process->numCpus());
- cpus_in_box.copyOut(xc->getMemPort());
+ cpus_in_box.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_PHYSMEM: {
- TypedBufferArg<uint64_t> physmem(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> physmem(tc->getSyscallArg(1));
*physmem = htog((uint64_t)1024 * 1024); // physical memory in KB
- physmem.copyOut(xc->getMemPort());
+ physmem.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_CPU_INFO: {
- TypedBufferArg<AlphaTru64::cpu_info> infop(xc->getSyscallArg(1));
+ TypedBufferArg<AlphaTru64::cpu_info> infop(tc->getSyscallArg(1));
infop->current_cpu = htog(0);
infop->cpus_in_box = htog(process->numCpus());
@@ -100,30 +103,30 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
infop->cpu_ex_binding = htog(0);
infop->mhz = htog(667);
- infop.copyOut(xc->getMemPort());
+ infop.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_PROC_TYPE: {
- TypedBufferArg<uint64_t> proc_type(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> proc_type(tc->getSyscallArg(1));
*proc_type = htog((uint64_t)11);
- proc_type.copyOut(xc->getMemPort());
+ proc_type.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_PLATFORM_NAME: {
- BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
strncpy((char *)bufArg.bufferPtr(),
"COMPAQ Professional Workstation XP1000",
nbytes);
- bufArg.copyOut(xc->getMemPort());
+ bufArg.copyOut(tc->getMemPort());
return 1;
}
case AlphaTru64::GSI_CLK_TCK: {
- TypedBufferArg<uint64_t> clk_hz(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> clk_hz(tc->getSyscallArg(1));
*clk_hz = htog((uint64_t)1024);
- clk_hz.copyOut(xc->getMemPort());
+ clk_hz.copyOut(tc->getMemPort());
return 1;
}
@@ -138,14 +141,14 @@ getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target setsysyinfo() handler.
static SyscallReturn
setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
+ unsigned op = tc->getSyscallArg(0);
switch (op) {
case AlphaTru64::SSI_IEEE_FP_CONTROL:
warn("setsysinfo: ignoring ieee_set_fp_control() arg 0x%x\n",
- xc->getSyscallArg(1));
+ tc->getSyscallArg(1));
break;
default:
@@ -160,22 +163,22 @@ setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target table() handler.
static
SyscallReturn tableFunc(SyscallDesc *desc, int callnum,Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
using namespace TheISA;
- int id = xc->getSyscallArg(0); // table ID
- int index = xc->getSyscallArg(1); // index into table
+ int id = tc->getSyscallArg(0); // table ID
+ int index = tc->getSyscallArg(1); // index into table
// arg 2 is buffer pointer; type depends on table ID
- int nel = xc->getSyscallArg(3); // number of elements
- int lel = xc->getSyscallArg(4); // expected element size
+ int nel = tc->getSyscallArg(3); // number of elements
+ int lel = tc->getSyscallArg(4); // expected element size
switch (id) {
case AlphaTru64::TBL_SYSINFO: {
if (index != 0 || nel != 1 || lel != sizeof(Tru64::tbl_sysinfo))
return -EINVAL;
- TypedBufferArg<Tru64::tbl_sysinfo> elp(xc->getSyscallArg(2));
+ TypedBufferArg<Tru64::tbl_sysinfo> elp(tc->getSyscallArg(2));
const int clk_hz = one_million;
elp->si_user = htog(curTick / (Clock::Frequency / clk_hz));
@@ -187,7 +190,7 @@ SyscallReturn tableFunc(SyscallDesc *desc, int callnum,Process *process,
elp->si_phz = htog(clk_hz);
elp->si_boottime = htog(seconds_since_epoch); // seconds since epoch?
elp->si_max_procs = htog(process->numCpus());
- elp.copyOut(xc->getMemPort());
+ elp.copyOut(tc->getMemPort());
return 0;
}
diff --git a/src/arch/alpha/tru64/process.hh b/src/arch/alpha/tru64/process.hh
index 1cde4cac0..5d91f6ac1 100644
--- a/src/arch/alpha/tru64/process.hh
+++ b/src/arch/alpha/tru64/process.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ALPHA_TRU64_PROCESS_HH__
diff --git a/src/arch/alpha/tru64/system.cc b/src/arch/alpha/tru64/system.cc
index 2ad06d679..6c0edc1ee 100644
--- a/src/arch/alpha/tru64/system.cc
+++ b/src/arch/alpha/tru64/system.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "arch/alpha/tru64/system.hh"
@@ -32,7 +35,7 @@
#include "base/loader/symtab.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/tru64/tru64_events.hh"
#include "kern/system_events.hh"
#include "mem/physical.hh"
@@ -104,9 +107,6 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
Param<uint64_t> system_type;
Param<uint64_t> system_rev;
- Param<bool> bin;
- VectorParam<string> binned_fns;
-
END_DECLARE_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
@@ -121,9 +121,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
INIT_PARAM_DFLT(readfile, "file to read startup script from", ""),
INIT_PARAM_DFLT(init_param, "numerical value to pass into simulator", 0),
INIT_PARAM_DFLT(system_type, "Type of system we are emulating", 12),
- INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1),
- INIT_PARAM_DFLT(bin, "is this system to be binned", false),
- INIT_PARAM(binned_fns, "functions to be broken down and binned")
+ INIT_PARAM_DFLT(system_rev, "Revision of system we are emulating", 2<<1)
END_INIT_SIM_OBJECT_PARAMS(Tru64AlphaSystem)
@@ -141,9 +139,6 @@ CREATE_SIM_OBJECT(Tru64AlphaSystem)
p->readfile = readfile;
p->system_type = system_type;
p->system_rev = system_rev;
- p->bin = bin;
- p->binned_fns = binned_fns;
- p->bin_int = false;
return new Tru64AlphaSystem(p);
}
diff --git a/src/arch/alpha/tru64/system.hh b/src/arch/alpha/tru64/system.hh
index 0e0cc1bc8..947e92f50 100644
--- a/src/arch/alpha/tru64/system.hh
+++ b/src/arch/alpha/tru64/system.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ARCH_ALPHA_TRU64_SYSTEM_HH__
@@ -33,7 +36,7 @@
#include "arch/isa_traits.hh"
#include "sim/system.hh"
-class ExecContext;
+class ThreadContext;
class BreakPCEvent;
class BadAddrEvent;
diff --git a/src/arch/alpha/tru64/tru64.cc b/src/arch/alpha/tru64/tru64.cc
index 4a3e653c1..56b04846f 100644
--- a/src/arch/alpha/tru64/tru64.cc
+++ b/src/arch/alpha/tru64/tru64.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/alpha/tru64/tru64.hh"
diff --git a/src/arch/alpha/tru64/tru64.hh b/src/arch/alpha/tru64/tru64.hh
index 19343ba23..f0711b995 100644
--- a/src/arch/alpha/tru64/tru64.hh
+++ b/src/arch/alpha/tru64/tru64.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ALPHA_ALPHA_TRU64_HH
diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh
index d4cb482d8..5859052e9 100644
--- a/src/arch/alpha/types.hh
+++ b/src/arch/alpha/types.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __ARCH_ALPHA_TYPES_HH__
diff --git a/src/arch/alpha/utility.hh b/src/arch/alpha/utility.hh
index 6cc916307..ec136091c 100644
--- a/src/arch/alpha/utility.hh
+++ b/src/arch/alpha/utility.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __ARCH_ALPHA_UTILITY_HH__
@@ -106,10 +109,10 @@ namespace AlphaISA
/**
* Function to insure ISA semantics about 0 registers.
- * @param xc The execution context.
+ * @param tc The thread context.
*/
- template <class XC>
- void zeroRegisters(XC *xc);
+ template <class TC>
+ void zeroRegisters(TC *tc);
#if FULL_SYSTEM
// Alpha IPR register accessors
@@ -140,15 +143,15 @@ namespace AlphaISA
RoundPage(Addr addr)
{ return (addr + PageBytes - 1) & ~(PageBytes - 1); }
- void initCPU(ExecContext *xc, int cpuId);
- void initIPRs(ExecContext *xc, int cpuId);
+ void initCPU(ThreadContext *tc, int cpuId);
+ void initIPRs(ThreadContext *tc, int cpuId);
/**
* Function to check for and process any interrupts.
- * @param xc The execution context.
+ * @param tc The thread context.
*/
- template <class XC>
- void processInterrupts(XC *xc);
+ template <class TC>
+ void processInterrupts(TC *tc);
#endif
} // namespace AlphaISA
diff --git a/src/arch/alpha/vtophys.cc b/src/arch/alpha/vtophys.cc
index 41e9b80a3..f7fd92c15 100644
--- a/src/arch/alpha/vtophys.cc
+++ b/src/arch/alpha/vtophys.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <string>
@@ -32,7 +36,7 @@
#include "arch/alpha/vtophys.hh"
#include "base/chunk_generator.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/vport.hh"
using namespace std;
@@ -81,10 +85,10 @@ AlphaISA::vtophys(Addr vaddr)
}
Addr
-AlphaISA::vtophys(ExecContext *xc, Addr addr)
+AlphaISA::vtophys(ThreadContext *tc, Addr addr)
{
AlphaISA::VAddr vaddr = addr;
- Addr ptbr = xc->readMiscReg(AlphaISA::IPR_PALtemp20);
+ Addr ptbr = tc->readMiscReg(AlphaISA::IPR_PALtemp20);
Addr paddr = 0;
//@todo Andrew couldn't remember why he commented some of this code
//so I put it back in. Perhaps something to do with gdb debugging?
@@ -97,7 +101,7 @@ AlphaISA::vtophys(ExecContext *xc, Addr addr)
paddr = vaddr;
} else {
AlphaISA::PageTableEntry pte =
- kernel_pte_lookup(xc->getPhysPort(), ptbr, vaddr);
+ kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr);
if (pte.valid())
paddr = pte.paddr() | vaddr.offset();
}
@@ -111,52 +115,52 @@ AlphaISA::vtophys(ExecContext *xc, Addr addr)
void
-AlphaISA::CopyOut(ExecContext *xc, void *dest, Addr src, size_t cplen)
+AlphaISA::CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen)
{
uint8_t *dst = (uint8_t *)dest;
- VirtualPort *vp = xc->getVirtPort(xc);
+ VirtualPort *vp = tc->getVirtPort(tc);
vp->readBlob(src, dst, cplen);
- xc->delVirtPort(vp);
+ tc->delVirtPort(vp);
}
void
-AlphaISA::CopyIn(ExecContext *xc, Addr dest, void *source, size_t cplen)
+AlphaISA::CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen)
{
uint8_t *src = (uint8_t *)source;
- VirtualPort *vp = xc->getVirtPort(xc);
+ VirtualPort *vp = tc->getVirtPort(tc);
vp->writeBlob(dest, src, cplen);
- xc->delVirtPort(vp);
+ tc->delVirtPort(vp);
}
void
-AlphaISA::CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen)
+AlphaISA::CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen)
{
int len = 0;
- VirtualPort *vp = xc->getVirtPort(xc);
+ VirtualPort *vp = tc->getVirtPort(tc);
do {
vp->readBlob(vaddr++, (uint8_t*)dst++, 1);
len++;
} while (len < maxlen && dst[len] != 0 );
- xc->delVirtPort(vp);
+ tc->delVirtPort(vp);
dst[len] = 0;
}
void
-AlphaISA::CopyStringIn(ExecContext *xc, char *src, Addr vaddr)
+AlphaISA::CopyStringIn(ThreadContext *tc, char *src, Addr vaddr)
{
- VirtualPort *vp = xc->getVirtPort(xc);
+ VirtualPort *vp = tc->getVirtPort(tc);
for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done();
gen.next())
{
vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size());
src += gen.size();
}
- xc->delVirtPort(vp);
+ tc->delVirtPort(vp);
}
diff --git a/src/arch/alpha/vtophys.hh b/src/arch/alpha/vtophys.hh
index 7ab14bc5b..472c694ff 100644
--- a/src/arch/alpha/vtophys.hh
+++ b/src/arch/alpha/vtophys.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __ARCH_ALPHA_VTOPHYS_H__
@@ -31,7 +34,7 @@
#include "arch/alpha/isa_traits.hh"
-class ExecContext;
+class ThreadContext;
class FunctionalPort;
namespace AlphaISA {
@@ -40,12 +43,12 @@ PageTableEntry
kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr);
Addr vtophys(Addr vaddr);
-Addr vtophys(ExecContext *xc, Addr vaddr);
+Addr vtophys(ThreadContext *tc, Addr vaddr);
-void CopyOut(ExecContext *xc, void *dst, Addr src, size_t len);
-void CopyIn(ExecContext *xc, Addr dst, void *src, size_t len);
-void CopyStringOut(ExecContext *xc, char *dst, Addr vaddr, size_t maxlen);
-void CopyStringIn(ExecContext *xc, char *src, Addr vaddr);
+void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len);
+void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len);
+void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen);
+void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr);
};
#endif // __ARCH_ALPHA_VTOPHYS_H__
diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py
index c0758da50..4d522e18a 100755
--- a/src/arch/isa_parser.py
+++ b/src/arch/isa_parser.py
@@ -23,6 +23,9 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
+# Korey Sewell
import os
import sys
@@ -1179,6 +1182,11 @@ class IntRegOperand(Operand):
if (self.size == self.dflt_size):
return '%s = xc->readIntReg(this, %d);\n' % \
(self.base_name, self.src_reg_idx)
+ elif (self.size > self.dflt_size):
+ int_reg_val = 'xc->readIntReg(this, %d)' % (self.src_reg_idx)
+ if (self.is_signed):
+ int_reg_val = 'sext<%d>(%s)' % (self.dflt_size, int_reg_val)
+ return '%s = %s;\n' % (self.base_name, int_reg_val)
else:
return '%s = bits(xc->readIntReg(this, %d), %d, 0);\n' % \
(self.base_name, self.src_reg_idx, self.size-1)
diff --git a/src/arch/isa_specific.hh b/src/arch/isa_specific.hh
index 91c9ffb68..181e81302 100644
--- a/src/arch/isa_specific.hh
+++ b/src/arch/isa_specific.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_ISA_SPECIFIC_HH__
diff --git a/src/arch/mips/SConscript b/src/arch/mips/SConscript
index ef1ef25d6..8353bcde7 100644
--- a/src/arch/mips/SConscript
+++ b/src/arch/mips/SConscript
@@ -25,6 +25,10 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+# Steve Reinhardt
+# Korey Sewell
import os
import sys
@@ -43,16 +47,12 @@ Import('env')
base_sources = Split('''
faults.cc
isa_traits.cc
+ utility.cc
''')
# Full-system sources
full_system_sources = Split('''
- memory.cc
- arguments.cc
- mips34k.cc
- osfpal.cc
- stacktrace.cc
- vtophys.cc
+ #Insert Full-System Files Here
''')
# Syscall emulation (non-full-system) sources
diff --git a/src/arch/mips/faults.cc b/src/arch/mips/faults.cc
index 1b31dfa69..cfeb045eb 100644
--- a/src/arch/mips/faults.cc
+++ b/src/arch/mips/faults.cc
@@ -24,12 +24,18 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#include "arch/mips/faults.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "base/trace.hh"
+#if !FULL_SYSTEM
+#include "sim/process.hh"
+#include "mem/page_table.hh"
+#endif
namespace MipsISA
{
@@ -50,6 +56,12 @@ FaultName ArithmeticFault::_name = "arith";
FaultVect ArithmeticFault::_vect = 0x0501;
FaultStat ArithmeticFault::_count;
+#if !FULL_SYSTEM
+FaultName PageTableFault::_name = "page_table_fault";
+FaultVect PageTableFault::_vect = 0x0000;
+FaultStat PageTableFault::_count;
+#endif
+
FaultName InterruptFault::_name = "interrupt";
FaultVect InterruptFault::_vect = 0x0101;
FaultStat InterruptFault::_count;
@@ -100,32 +112,53 @@ FaultStat IntegerOverflowFault::_count;
#if FULL_SYSTEM
-void MipsFault::invoke(ExecContext * xc)
+void MipsFault::invoke(ThreadContext * tc)
{
- FaultBase::invoke(xc);
+ FaultBase::invoke(tc);
countStat()++;
// exception restart address
- if (setRestartAddress() || !xc->inPalMode())
- xc->setMiscReg(MipsISA::IPR_EXC_ADDR, xc->readPC());
+ if (setRestartAddress() || !tc->inPalMode())
+ tc->setMiscReg(MipsISA::IPR_EXC_ADDR, tc->readPC());
if (skipFaultingInstruction()) {
// traps... skip faulting instruction.
- xc->setMiscReg(MipsISA::IPR_EXC_ADDR,
- xc->readMiscReg(MipsISA::IPR_EXC_ADDR) + 4);
+ tc->setMiscReg(MipsISA::IPR_EXC_ADDR,
+ tc->readMiscReg(MipsISA::IPR_EXC_ADDR) + 4);
}
- xc->setPC(xc->readMiscReg(MipsISA::IPR_PAL_BASE) + vect());
- xc->setNextPC(xc->readPC() + sizeof(MachInst));
+ tc->setPC(tc->readMiscReg(MipsISA::IPR_PAL_BASE) + vect());
+ tc->setNextPC(tc->readPC() + sizeof(MachInst));
}
-void ArithmeticFault::invoke(ExecContext * xc)
+void ArithmeticFault::invoke(ThreadContext * tc)
{
- FaultBase::invoke(xc);
+ FaultBase::invoke(tc);
panic("Arithmetic traps are unimplemented!");
}
-#endif
+#else //!FULL_SYSTEM
+void PageTableFault::invoke(ThreadContext *tc)
+{
+ Process *p = tc->getProcessPtr();
+
+ // address is higher than the stack region or in the current stack region
+ if (vaddr > p->stack_base || vaddr > p->stack_min)
+ FaultBase::invoke(tc);
+
+ // We've accessed the next page
+ if (vaddr > p->stack_min - PageBytes) {
+ p->stack_min -= PageBytes;
+ if (p->stack_base - p->stack_min > 8*1024*1024)
+ fatal("Over max stack size for one thread\n");
+ p->pTable->allocate(p->stack_min, PageBytes);
+ warn("Increasing stack size by one page.");
+ } else {
+ FaultBase::invoke(tc);
+ }
+}
+
+#endif
} // namespace MipsISA
diff --git a/src/arch/mips/faults.hh b/src/arch/mips/faults.hh
index 0bdabe29e..95c61cfbc 100644
--- a/src/arch/mips/faults.hh
+++ b/src/arch/mips/faults.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __MIPS_FAULTS_HH__
@@ -45,7 +47,7 @@ class MipsFault : public FaultBase
virtual bool setRestartAddress() {return true;}
public:
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
virtual FaultVect vect() = 0;
virtual FaultStat & countStat() = 0;
@@ -77,6 +79,30 @@ class AlignmentFault : public MipsFault
bool isAlignmentFault() {return true;}
};
+#if !FULL_SYSTEM
+class PageTableFault : public MipsFault
+{
+ private:
+ Addr vaddr;
+ static FaultName _name;
+ static FaultVect _vect;
+ static FaultStat _count;
+ public:
+ PageTableFault(Addr va)
+ : vaddr(va) {}
+ FaultName name() {return _name;}
+ FaultVect vect() {return _vect;}
+ FaultStat & countStat() {return _count;}
+ void invoke(ThreadContext * tc);
+};
+
+static inline Fault genPageTableFault(Addr va)
+{
+ return new PageTableFault(va);
+}
+#endif
+
+
static inline Fault genMachineCheckFault()
{
return new MachineCheckFault;
@@ -112,7 +138,7 @@ class ArithmeticFault : public MipsFault
FaultVect vect() {return _vect;}
FaultStat & countStat() {return _count;}
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
};
diff --git a/src/arch/mips/isa/base.isa b/src/arch/mips/isa/base.isa
index b2a31c018..f07b06e03 100644
--- a/src/arch/mips/isa/base.isa
+++ b/src/arch/mips/isa/base.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Base class for MIPS instructions, and some support functions
@@ -10,7 +38,6 @@ output header {{
using namespace MipsISA;
-
/**
* Base class for all MIPS static instructions.
*/
@@ -18,16 +45,6 @@ output header {{
{
protected:
- /// Make MipsISA register dependence tags directly visible in
- /// this class and derived classes. Maybe these should really
- /// live here and not in the MipsISA namespace.
- /*enum DependenceTags {
- FP_Base_DepTag = MipsISA::FP_Base_DepTag,
- Fpcr_DepTag = MipsISA::Fpcr_DepTag,
- Uniq_DepTag = MipsISA::Uniq_DepTag,
- IPR_Base_DepTag = MipsISA::IPR_Base_DepTag
- };*/
-
// Constructor
MipsStaticInst(const char *mnem, MachInst _machInst, OpClass __opClass)
: StaticInst(mnem, _machInst, __opClass)
@@ -67,12 +84,12 @@ output decoder {{
}
if(_numSrcRegs > 0) {
- ss << ",";
+ ss << ", ";
printReg(ss, _srcRegIdx[0]);
}
if(_numSrcRegs > 1) {
- ss << ",";
+ ss << ", ";
printReg(ss, _srcRegIdx[1]);
}
diff --git a/src/arch/mips/isa/bitfields.isa b/src/arch/mips/isa/bitfields.isa
index e1124a591..35815bf1f 100644
--- a/src/arch/mips/isa/bitfields.isa
+++ b/src/arch/mips/isa/bitfields.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Bitfield definitions.
@@ -17,20 +45,19 @@ def bitfield FUNCTION < 5: 0>;
def bitfield FUNCTION_HI < 5: 3>;
def bitfield FUNCTION_LO < 2: 0>;
-// Integer operate format
-def bitfield RT <20:16>;
-def bitfield RT_HI <20:19>;
-def bitfield RT_LO <18:16>;
-
def bitfield RS <25:21>;
def bitfield RS_MSB <25:25>;
def bitfield RS_HI <25:24>;
def bitfield RS_LO <23:21>;
-def bitfield RS_SRL <25:22>;
-
+def bitfield RS_SRL <25:22>;
+def bitfield RS_RT <25:16>;
+def bitfield RT <20:16>;
+def bitfield RT_HI <20:19>;
+def bitfield RT_LO <18:16>;
+def bitfield RT_RD <20:11>;
def bitfield RD <15:11>;
-def bitfield INTIMM <15: 0>; // integer immediate (literal)
+def bitfield INTIMM <15: 0>;
// Floating-point operate format
def bitfield FMT <25:21>;
@@ -67,5 +94,9 @@ def bitfield HINT <10: 6>;
def bitfield SYSCALLCODE <25: 6>;
def bitfield TRAPCODE <15:13>;
+// EXT/INS instructions
+def bitfield MSB <15:11>;
+def bitfield LSB <10: 6>;
+
// M5 instructions
def bitfield M5FUNC <7:0>;
diff --git a/src/arch/mips/isa/decoder.isa b/src/arch/mips/isa/decoder.isa
index 1454aba39..9ac982e34 100644
--- a/src/arch/mips/isa/decoder.isa
+++ b/src/arch/mips/isa/decoder.isa
@@ -1,4 +1,32 @@
- // -*- mode:c++ -*-
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
////////////////////////////////////////////////////////////////////
//
@@ -6,41 +34,33 @@
// -----------------------------
// The following instructions are specified in the MIPS32 ISA
// Specification. Decoding closely follows the style specified
-// in the MIPS32 ISAthe specification document starting with Table
+// in the MIPS32 ISA specification document starting with Table
// A-2 (document available @ www.mips.com)
//
-//@todo: Distinguish "unknown/future" use insts from "reserved"
-// ones
decode OPCODE_HI default Unknown::unknown() {
-
- // Derived From ... Table A-2 MIPS32 ISA Manual
+ //Table A-2
0x0: decode OPCODE_LO {
-
0x0: decode FUNCTION_HI {
0x0: decode FUNCTION_LO {
0x1: decode MOVCI {
format BasicOp {
- 0: movf({{ if (getFPConditionCode(FCSR, CC) == 0) Rd = Rs}});
- 1: movt({{ if (getFPConditionCode(FCSR, CC) == 1) Rd = Rs}});
+ 0: movf({{ Rd = (getCondCode(FCSR, CC) == 0) ? Rd : Rs; }});
+ 1: movt({{ Rd = (getCondCode(FCSR, CC) == 1) ? Rd : Rs; }});
}
}
format BasicOp {
-
- //Table A-3 Note: "1. Specific encodings of the rt, rd, and sa fields
- //are used to distinguish among the SLL, NOP, SSNOP and EHB functions.
+ //Table A-3 Note: "Specific encodings of the rd, rs, and
+ //rt fields are used to distinguish SLL, SSNOP, and EHB
+ //functions
0x0: decode RS {
- 0x0: decode RT { //fix Nop traditional vs. Nop converted disassembly later
- 0x0: decode RD default Nop::nop(){
- 0x0: decode SA {
- 0x1: ssnop({{ ; }}); //really sll r0,r0,1
- 0x3: ehb({{ ; }}); //really sll r0,r0,3
- }
- }
-
- default: sll({{ Rd = Rt.uw << SA; }});
+ 0x0: decode RT_RD {
+ 0x0: decode SA default Nop::nop(){
+ 0x1: WarnUnimpl::ssnop();
+ 0x3: WarnUnimpl::ehb();
+ }
+ default: sll({{ Rd = Rt.uw << SA; }});
}
-
}
0x2: decode RS_SRL {
@@ -55,7 +75,6 @@ decode OPCODE_HI default Unknown::unknown() {
0x3: decode RS {
0x0: sra({{
uint32_t temp = Rt >> SA;
-
if ( (Rt & 0x80000000) > 0 ) {
uint32_t mask = 0x80000000;
for(int i=0; i < SA; i++) {
@@ -63,7 +82,6 @@ decode OPCODE_HI default Unknown::unknown() {
mask = mask >> 1;
}
}
-
Rd = temp;
}});
}
@@ -96,37 +114,36 @@ decode OPCODE_HI default Unknown::unknown() {
}
0x1: decode FUNCTION_LO {
-
- //Table A-3 Note: "Specific encodings of the hint field are used
- //to distinguish JR from JR.HB and JALR from JALR.HB"
+ //Table A-3 Note: "Specific encodings of the hint field are
+ //used to distinguish JR from JR.HB and JALR from JALR.HB"
format Jump {
0x0: decode HINT {
- 0:jr({{ NNPC = Rs & ~1; }},IsReturn);
-
- 1:jr_hb({{ NNPC = Rs & ~1; clear_exe_inst_hazards(); }},IsReturn);
+ 0x1: jr_hb({{ NNPC = Rs & ~1; }}, IsReturn, ClearHazards);
+ default: jr({{ NNPC = Rs & ~1; }}, IsReturn);
}
0x1: decode HINT {
- 0: jalr({{ Rd = NNPC; NNPC = Rs; }},IsCall,IsReturn);
-
- 1: jalr_hb({{ Rd = NNPC; NNPC = Rs; clear_exe_inst_hazards();}},IsCall,IsReturn);
+ 0x1: jalr_hb({{ Rd = NNPC; NNPC = Rs; }}, IsCall, Link
+ , ClearHazards);
+ default: jalr({{ Rd = NNPC; NNPC = Rs; }}, IsCall,
+ Link);
}
}
format BasicOp {
- 0x2: movz({{ if (Rt == 0) Rd = Rs; }});
- 0x3: movn({{ if (Rt != 0) Rd = Rs; }});
+ 0x2: movz({{ Rd = (Rt == 0) ? Rs : Rd; }});
+ 0x3: movn({{ Rd = (Rt != 0) ? Rs : Rd; }});
+ 0x4: syscall({{ xc->syscall(R2); }}, IsNonSpeculative);
+ 0x7: sync({{ ; }}, IsMemBarrier);
}
- format BasicOp {
- 0x4: syscall({{ xc->syscall(R2); }},IsNonSpeculative);
- 0x5: break({{ panic("Not implemented break yet"); }},IsNonSpeculative);
- 0x7: sync({{ panic("Not implemented sync yet"); }},IsNonSpeculative);
+ format FailUnimpl {
+ 0x5: break();
}
}
0x2: decode FUNCTION_LO {
- format BasicOp {
+ format HiLoMiscOp {
0x0: mfhi({{ Rd = HI; }});
0x1: mthi({{ HI = Rs; }});
0x2: mflo({{ Rd = LO; }});
@@ -135,28 +152,22 @@ decode OPCODE_HI default Unknown::unknown() {
}
0x3: decode FUNCTION_LO {
- format IntOp {
- 0x0: mult({{
- int64_t temp1 = Rs.sd * Rt.sd;
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
-
- 0x1: multu({{
- uint64_t temp1 = Rs.ud * Rt.ud;
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
-
- 0x2: div({{
- HI = Rs.sd % Rt.sd;
- LO = Rs.sd / Rt.sd;
- }});
+ format HiLoOp {
+ 0x0: mult({{ val = Rs.sd * Rt.sd; }});
+ 0x1: multu({{ val = Rs.ud * Rt.ud; }});
+ }
- 0x3: divu({{
- HI = Rs.ud % Rt.ud;
- LO = Rs.ud / Rt.ud;
- }});
+ format HiLoMiscOp {
+ 0x2: div({{ if (Rt.sd != 0) {
+ HI = Rs.sd % Rt.sd;
+ LO = Rs.sd / Rt.sd;
+ }
+ }});
+ 0x3: divu({{ if (Rt.ud != 0) {
+ HI = Rs.ud % Rt.ud;
+ LO = Rs.ud / Rt.ud;
+ }
+ }});
}
}
@@ -201,11 +212,8 @@ decode OPCODE_HI default Unknown::unknown() {
format Branch {
0x0: bltz({{ cond = (Rs.sw < 0); }});
0x1: bgez({{ cond = (Rs.sw >= 0); }});
- }
-
- format BranchLikely {
- 0x2: bltzl({{ cond = (Rs.sw < 0); }});
- 0x3: bgezl({{ cond = (Rs.sw >= 0); }});
+ 0x2: bltzl({{ cond = (Rs.sw < 0); }}, Likely);
+ 0x3: bgezl({{ cond = (Rs.sw >= 0); }}, Likely);
}
}
@@ -222,13 +230,13 @@ decode OPCODE_HI default Unknown::unknown() {
0x2: decode REGIMM_LO {
format Branch {
- 0x0: bltzal({{ cond = (Rs.sw < 0); }}, IsCall,IsReturn);
- 0x1: bgezal({{ cond = (Rs.sw >= 0); }}, IsCall,IsReturn);
- }
-
- format BranchLikely {
- 0x2: bltzall({{ cond = (Rs.sw < 0); }}, IsCall, IsReturn);
- 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, IsCall, IsReturn);
+ 0x0: bltzal({{ cond = (Rs.sw < 0); }}, Link);
+ 0x1: decode RS {
+ 0x0: bal ({{ cond = 1; }}, IsCall, Link);
+ default: bgezal({{ cond = (Rs.sw >= 0); }}, Link);
+ }
+ 0x2: bltzall({{ cond = (Rs.sw < 0); }}, Link, Likely);
+ 0x3: bgezall({{ cond = (Rs.sw >= 0); }}, Link, Likely);
}
}
@@ -241,25 +249,23 @@ decode OPCODE_HI default Unknown::unknown() {
format Jump {
0x2: j({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2);}});
-
- 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }},IsCall,IsReturn);
+ 0x3: jal({{ NNPC = (NPC & 0xF0000000) | (JMPTARG << 2); }}, IsCall,
+ Link);
}
format Branch {
- 0x4: beq({{ cond = (Rs.sw == Rt.sw); }});
- 0x5: bne({{ cond = (Rs.sw != Rt.sw); }});
- 0x6: decode RT {
- 0x0: blez({{ cond = (Rs.sw <= 0); }});
- }
-
- 0x7: decode RT {
- 0x0: bgtz({{ cond = (Rs.sw > 0); }});
+ 0x4: decode RS_RT {
+ 0x0: b({{ cond = 1; }});
+ default: beq({{ cond = (Rs.sw == Rt.sw); }});
}
+ 0x5: bne({{ cond = (Rs.sw != Rt.sw); }});
+ 0x6: blez({{ cond = (Rs.sw <= 0); }});
+ 0x7: bgtz({{ cond = (Rs.sw > 0); }});
}
}
0x1: decode OPCODE_LO {
- format IntOp {
+ format IntImmOp {
0x0: addi({{ Rt.sw = Rs.sw + imm; /*Trap If Overflow*/}});
0x1: addiu({{ Rt.sw = Rs.sw + imm;}});
0x2: slti({{ Rt.sw = ( Rs.sw < imm) ? 1 : 0 }});
@@ -275,112 +281,47 @@ decode OPCODE_HI default Unknown::unknown() {
}
0x2: decode OPCODE_LO {
-
//Table A-11 MIPS32 COP0 Encoding of rs Field
0x0: decode RS_MSB {
0x0: decode RS {
- format System {
- 0x0: mfc0({{
- //uint64_t reg_num = Rd.uw;
-
- Rt = xc->readMiscReg(RD << 5 | SEL);
- }});
-
- 0x4: mtc0({{
- //uint64_t reg_num = Rd.uw;
-
- xc->setMiscReg(RD << 5 | SEL,Rt);
- }});
-
- 0x8: mftr({{
- //The contents of the coprocessor 0 register specified by the
- //combination of rd and sel are loaded into general register
- //rt. Note that not all coprocessor 0 registers support the
- //sel field. In those instances, the sel field must be zero.
-
- //MT Code Needed Here
-
- }});
-
- 0xC: mttr({{
- //The contents of the coprocessor 0 register specified by the
- //combination of rd and sel are loaded into general register
- //rt. Note that not all coprocessor 0 registers support the
- //sel field. In those instances, the sel field must be zero.
-
- //MT Code Needed Here
- }});
-
-
- 0xA: rdpgpr({{
- //Accessing Previous Shadow Set Register Number
- //uint64_t prev = xc->readMiscReg(SRSCtl)/*[PSS]*/;
- //uint64_t reg_num = Rt.uw;
-
- //Rd = xc->regs.IntRegFile[prev];
- //Rd = xc->shadowIntRegFile[prev][reg_num];
- }});
+ format CP0Control {
+ 0x0: mfc0({{ Rt = xc->readMiscReg(RD << 5 | SEL); }});
+ 0x4: mtc0({{ xc->setMiscReg(RD << 5 | SEL, Rt); }});
+ }
+ format MipsMT {
+ 0x8: mftr();
+ 0xC: mttr();
0xB: decode RD {
-
0x0: decode SC {
- 0x0: dvpe({{
- Rt.sw = xc->readMiscReg(MVPControl);
- xc->setMiscReg(MVPControl,0);
- }});
-
- 0x1: evpe({{
- Rt.sw = xc->readMiscReg(MVPControl);
- xc->setMiscReg(MVPControl,1);
- }});
+ 0x0: dvpe();
+ 0x1: evpe();
}
-
0x1: decode SC {
- 0x0: dmt({{
- Rt.sw = xc->readMiscReg(VPEControl);
- xc->setMiscReg(VPEControl,0);
- }});
-
- 0x1: emt({{
- Rt.sw = xc->readMiscReg(VPEControl);
- xc->setMiscReg(VPEControl,1);
- }});
- }
-
- 0xC: decode SC {
- 0x0: di({{
- Rt.sw = xc->readMiscReg(Status);
- xc->setMiscReg(Status,0);
- }});
-
- 0x1: ei({{
- Rt.sw = xc->readMiscReg(Status);
- xc->setMiscReg(Status,1);
- }});
+ 0x0: dmt();
+ 0x1: emt();
+ 0xC: decode SC {
+ 0x0: di();
+ 0x1: ei();
+ }
}
}
+ }
- 0xE: wrpgpr({{
- //Accessing Previous Shadow Set Register Number
- //uint64_t prev = xc->readMiscReg(SRSCtl/*[PSS]*/);
- //uint64_t reg_num = Rd.uw;
-
- //xc->regs.IntRegFile[prev];
- //xc->shadowIntRegFile[prev][reg_num] = Rt;
- }});
+ format FailUnimpl {
+ 0xA: rdpgpr();
+ 0xE: wrpgpr();
}
}
//Table A-12 MIPS32 COP0 Encoding of Function Field When rs=CO
0x1: decode FUNCTION {
- format System {
- 0x01: tlbr({{ }});
- 0x02: tlbwi({{ }});
- 0x06: tlbwr({{ }});
- 0x08: tlbp({{ }});
- }
+ format FailUnimpl {
+ 0x01: tlbr();
+ 0x02: tlbwi();
+ 0x06: tlbwr();
+ 0x08: tlbp();
- format WarnUnimpl {
0x18: eret();
0x1F: deret();
0x20: wait();
@@ -393,18 +334,9 @@ decode OPCODE_HI default Unknown::unknown() {
0x0: decode RS_HI {
0x0: decode RS_LO {
- format FloatOp {
- 0x0: mfc1 ({{ Rt.uw = Fs.uw<31:0>; }});
- 0x3: mfhc1({{ Rt.uw = Fs.ud<63:32>;}});
- 0x4: mtc1 ({{ Fs.uw = Rt.uw; }});
- 0x7: mthc1({{
- uint64_t fs_hi = Rt.uw;
- uint64_t fs_lo = Fs.ud & 0x0000FFFF;
- Fs.ud = fs_hi << 32 | fs_lo;
- }});
- }
+ format CP1Control {
+ 0x0: mfc1 ({{ Rt.uw = Fs.uw; }});
- format System {
0x2: cfc1({{
switch (FS)
{
@@ -424,11 +356,14 @@ decode OPCODE_HI default Unknown::unknown() {
Rt = FCSR;
break;
default:
- panic("FP Control Value (%d) Not Available. Ignoring Access to"
- "Floating Control Status Register",FS);
+ panic("FP Control Value (%d) Not Valid");
}
}});
+ 0x3: mfhc1({{ Rt.uw = Fs.ud<63:32>;}});
+
+ 0x4: mtc1 ({{ Fs.uw = Rt.uw; }});
+
0x6: ctc1({{
switch (FS)
{
@@ -464,21 +399,29 @@ decode OPCODE_HI default Unknown::unknown() {
"Floating Control Status Register", FS);
}
}});
+
+ 0x7: mthc1({{
+ uint64_t fs_hi = Rt.uw;
+ uint64_t fs_lo = Fs.ud & 0x0FFFFFFFF;
+ Fs.ud = (fs_hi << 32) | fs_lo;
+ }});
+
}
}
0x1: decode ND {
- 0x0: decode TF {
- format Branch {
- 0x0: bc1f({{ cond = (getFPConditionCode(FCSR,CC) == 0); }});
- 0x1: bc1t({{ cond = (getFPConditionCode(FCSR,CC) == 1); }});
+ format Branch {
+ 0x0: decode TF {
+ 0x0: bc1f({{ cond = getCondCode(FCSR, BRANCH_CC) == 0;
+ }});
+ 0x1: bc1t({{ cond = getCondCode(FCSR, BRANCH_CC) == 1;
+ }});
}
- }
-
- 0x1: decode TF {
- format BranchLikely {
- 0x0: bc1fl({{ cond = (getFPConditionCode(FCSR,CC) == 0); }});
- 0x1: bc1tl({{ cond = (getFPConditionCode(FCSR,CC) == 1); }});
+ 0x1: decode TF {
+ 0x0: bc1fl({{ cond = getCondCode(FCSR, BRANCH_CC) == 0;
+ }}, Likely);
+ 0x1: bc1tl({{ cond = getCondCode(FCSR, BRANCH_CC) == 1;
+ }}, Likely);
}
}
}
@@ -486,9 +429,8 @@ decode OPCODE_HI default Unknown::unknown() {
0x1: decode RS_HI {
0x2: decode RS_LO {
-
//Table A-14 MIPS32 COP1 Encoding of Function Field When rs=S
- //(( single-word ))
+ //(( single-precision floating point))
0x0: decode FUNCTION_HI {
0x0: decode FUNCTION_LO {
format FloatOp {
@@ -498,195 +440,104 @@ decode OPCODE_HI default Unknown::unknown() {
0x3: div_s({{ Fd.sf = Fs.sf / Ft.sf;}});
0x4: sqrt_s({{ Fd.sf = sqrt(Fs.sf);}});
0x5: abs_s({{ Fd.sf = fabs(Fs.sf);}});
- 0x6: mov_s({{ Fd.sf = Fs.sf;}});
- 0x7: neg_s({{ Fd.sf = -1 * Fs.sf;}});
+ 0x7: neg_s({{ Fd.sf = -Fs.sf;}});
}
+
+ 0x6: BasicOp::mov_s({{ Fd.sf = Fs.sf;}});
}
0x1: decode FUNCTION_LO {
- format Float64Op {
- 0x0: round_l_s({{
- Fd.ud = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_LONG);
- }});
-
- 0x1: trunc_l_s({{
- Fd.ud = fpConvert(truncFP(Fs.sf), SINGLE_TO_LONG);
- }});
-
- 0x2: ceil_l_s({{
- Fd.ud = fpConvert(ceil(Fs.sf), SINGLE_TO_LONG);
- }});
-
- 0x3: floor_l_s({{
- Fd.ud = fpConvert(floor(Fs.sf), SINGLE_TO_LONG);
- }});
- }
-
- format FloatOp {
- 0x4: round_w_s({{
- Fd.uw = fpConvert(roundFP(Fs.sf,0), SINGLE_TO_WORD);
- }});
-
- 0x5: trunc_w_s({{
- Fd.uw = fpConvert(truncFP(Fs.sf), SINGLE_TO_WORD);
- }});
-
- 0x6: ceil_w_s({{
- Fd.uw = fpConvert(ceil(Fs.sf), SINGLE_TO_WORD);
- }});
-
- 0x7: floor_w_s({{
- Fd.uw = fpConvert(floor(Fs.sf), SINGLE_TO_WORD);
- }});
+ format FloatConvertOp {
+ 0x0: round_l_s({{ val = Fs.sf; }}, ToLong,
+ Round);
+ 0x1: trunc_l_s({{ val = Fs.sf; }}, ToLong,
+ Trunc);
+ 0x2: ceil_l_s({{ val = Fs.sf; }}, ToLong,
+ Ceil);
+ 0x3: floor_l_s({{ val = Fs.sf; }}, ToLong,
+ Floor);
+ 0x4: round_w_s({{ val = Fs.sf; }}, ToWord,
+ Round);
+ 0x5: trunc_w_s({{ val = Fs.sf; }}, ToWord,
+ Trunc);
+ 0x6: ceil_w_s({{ val = Fs.sf; }}, ToWord,
+ Ceil);
+ 0x7: floor_w_s({{ val = Fs.sf; }}, ToWord,
+ Floor);
}
}
0x2: decode FUNCTION_LO {
0x1: decode MOVCF {
- format FloatOp {
- 0x0: movf_s({{if (getFPConditionCode(FCSR,CC) == 0) Fd = Fs;}});
- 0x1: movt_s({{if (getFPConditionCode(FCSR,CC) == 1) Fd = Fs;}});
+ format BasicOp {
+ 0x0: movf_s({{ Fd = (getCondCode(FCSR,CC) == 0) ? Fs : Fd; }});
+ 0x1: movt_s({{ Fd = (getCondCode(FCSR,CC) == 1) ? Fs : Fd; }});
}
}
+ format BasicOp {
+ 0x2: movz_s({{ Fd = (Rt == 0) ? Fs : Fd; }});
+ 0x3: movn_s({{ Fd = (Rt != 0) ? Fs : Fd; }});
+ }
+
format FloatOp {
- 0x2: movz_s({{ if (Rt == 0) Fd = Fs; }});
- 0x3: movn_s({{ if (Rt != 0) Fd = Fs; }});
0x5: recip_s({{ Fd = 1 / Fs; }});
0x6: rsqrt_s({{ Fd = 1 / sqrt(Fs);}});
}
}
0x4: decode FUNCTION_LO {
-
format FloatConvertOp {
- 0x1: cvt_d_s({{
- Fd.ud = fpConvert(Fs.sf, SINGLE_TO_DOUBLE);
- }});
-
- 0x4: cvt_w_s({{
- Fd.uw = fpConvert(Fs.sf, SINGLE_TO_WORD);
- }});
+ 0x1: cvt_d_s({{ val = Fs.sf; }}, ToDouble);
+ 0x4: cvt_w_s({{ val = Fs.sf; }}, ToWord);
+ 0x5: cvt_l_s({{ val = Fs.sf; }}, ToLong);
}
- format FloatConvertOp {
- 0x5: cvt_l_s({{
- Fd.ud = fpConvert(Fs.sf, SINGLE_TO_LONG);
- }});
-
- 0x6: cvt_ps_st({{
- Fd.ud = (uint64_t)Fs.uw << 32 | (uint64_t)Ft.uw;
+ 0x6: FloatOp::cvt_ps_s({{
+ Fd.ud = (uint64_t) Fs.uw << 32 |
+ (uint64_t) Ft.uw;
}});
- }
}
0x6: decode FUNCTION_LO {
format FloatCompareOp {
- 0x0: c_f_s({{ cond = 0; }});
-
- 0x1: c_un_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = 0;
- }});
-
- 0x2: c_eq_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf == Ft.sf);
- }});
-
- 0x3: c_ueq_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf == Ft.sf);
- }});
-
- 0x4: c_olt_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf < Ft.sf);
- }});
-
- 0x5: c_ult_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf < Ft.sf);
- }});
-
- 0x6: c_ole_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf <= Ft.sf);
- }});
-
- 0x7: c_ule_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf <= Ft.sf);
- }});
+ 0x0: c_f_s({{ cond = 0; }}, SinglePrecision,
+ UnorderedFalse);
+ 0x1: c_un_s({{ cond = 0; }}, SinglePrecision,
+ UnorderedTrue);
+ 0x2: c_eq_s({{ cond = (Fs.sf == Ft.sf); }},
+ UnorderedFalse);
+ 0x3: c_ueq_s({{ cond = (Fs.sf == Ft.sf); }},
+ UnorderedTrue);
+ 0x4: c_olt_s({{ cond = (Fs.sf < Ft.sf); }},
+ UnorderedFalse);
+ 0x5: c_ult_s({{ cond = (Fs.sf < Ft.sf); }},
+ UnorderedTrue);
+ 0x6: c_ole_s({{ cond = (Fs.sf <= Ft.sf); }},
+ UnorderedFalse);
+ 0x7: c_ule_s({{ cond = (Fs.sf <= Ft.sf); }},
+ UnorderedTrue);
}
}
0x7: decode FUNCTION_LO {
- format FloatCompareWithXcptOp {
- 0x0: c_sf_s({{ cond = 0; }});
-
- 0x1: c_ngle_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = 0;
- }});
-
- 0x2: c_seq_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf == Ft.sf);
- }});
-
- 0x3: c_ngl_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf == Ft.sf);
- }});
-
- 0x4: c_lt_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf < Ft.sf);
- }});
-
- 0x5: c_nge_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf < Ft.sf);
- }});
-
- 0x6: c_le_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 0;
- else
- cond = (Fs.sf <= Ft.sf);
- }});
-
- 0x7: c_ngt_s({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond = 1;
- else
- cond = (Fs.sf <= Ft.sf);
- }});
+ format FloatCompareOp {
+ 0x0: c_sf_s({{ cond = 0; }}, SinglePrecision,
+ UnorderedFalse, QnanException);
+ 0x1: c_ngle_s({{ cond = 0; }}, SinglePrecision,
+ UnorderedTrue, QnanException);
+ 0x2: c_seq_s({{ cond = (Fs.sf == Ft.sf);}},
+ UnorderedFalse, QnanException);
+ 0x3: c_ngl_s({{ cond = (Fs.sf == Ft.sf); }},
+ UnorderedTrue, QnanException);
+ 0x4: c_lt_s({{ cond = (Fs.sf < Ft.sf); }},
+ UnorderedFalse, QnanException);
+ 0x5: c_nge_s({{ cond = (Fs.sf < Ft.sf); }},
+ UnorderedTrue, QnanException);
+ 0x6: c_le_s({{ cond = (Fs.sf <= Ft.sf); }},
+ UnorderedFalse, QnanException);
+ 0x7: c_ngt_s({{ cond = (Fs.sf <= Ft.sf); }},
+ UnorderedTrue, QnanException);
}
}
}
@@ -695,197 +546,109 @@ decode OPCODE_HI default Unknown::unknown() {
0x1: decode FUNCTION_HI {
0x0: decode FUNCTION_LO {
format FloatOp {
- 0x0: add_d({{ Fd.df = Fs.df + Ft.df;}});
- 0x1: sub_d({{ Fd.df = Fs.df - Ft.df;}});
- 0x2: mul_d({{ Fd.df = Fs.df * Ft.df;}});
- 0x3: div_d({{ Fd.df = Fs.df / Ft.df;}});
- 0x4: sqrt_d({{ Fd.df = sqrt(Fs.df);}});
- 0x5: abs_d({{ Fd.df = fabs(Fs.df);}});
- 0x6: mov_d({{ Fd.ud = Fs.ud;}});
- 0x7: neg_d({{ Fd.df = -1 * Fs.df;}});
+ 0x0: add_d({{ Fd.df = Fs.df + Ft.df; }});
+ 0x1: sub_d({{ Fd.df = Fs.df - Ft.df; }});
+ 0x2: mul_d({{ Fd.df = Fs.df * Ft.df; }});
+ 0x3: div_d({{ Fd.df = Fs.df / Ft.df; }});
+ 0x4: sqrt_d({{ Fd.df = sqrt(Fs.df); }});
+ 0x5: abs_d({{ Fd.df = fabs(Fs.df); }});
+ 0x7: neg_d({{ Fd.df = -1 * Fs.df; }});
}
+
+ 0x6: BasicOp::mov_d({{ Fd.df = Fs.df; }});
}
0x1: decode FUNCTION_LO {
- format FloatOp {
- 0x0: round_l_d({{
- Fd.ud = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_LONG);
- }});
-
- 0x1: trunc_l_d({{
- Fd.ud = fpConvert(truncFP(Fs.df), DOUBLE_TO_LONG);
- }});
-
- 0x2: ceil_l_d({{
- Fd.ud = fpConvert(ceil(Fs.df), DOUBLE_TO_LONG);
- }});
-
- 0x3: floor_l_d({{
- Fd.ud = fpConvert(floor(Fs.df), DOUBLE_TO_LONG);
- }});
- }
-
- format FloatOp {
- 0x4: round_w_d({{
- Fd.uw = fpConvert(roundFP(Fs.df,0), DOUBLE_TO_WORD);
- }});
-
- 0x5: trunc_w_d({{
- Fd.uw = fpConvert(truncFP(Fs.df), DOUBLE_TO_WORD);
- }});
-
- 0x6: ceil_w_d({{
- Fd.uw = fpConvert(ceil(Fs.df), DOUBLE_TO_WORD);
- }});
-
- 0x7: floor_w_d({{
- Fd.uw = fpConvert(floor(Fs.df), DOUBLE_TO_WORD);
- }});
+ format FloatConvertOp {
+ 0x0: round_l_d({{ val = Fs.df; }}, ToLong,
+ Round);
+ 0x1: trunc_l_d({{ val = Fs.df; }}, ToLong,
+ Trunc);
+ 0x2: ceil_l_d({{ val = Fs.df; }}, ToLong,
+ Ceil);
+ 0x3: floor_l_d({{ val = Fs.df; }}, ToLong,
+ Floor);
+ 0x4: round_w_d({{ val = Fs.df; }}, ToWord,
+ Round);
+ 0x5: trunc_w_d({{ val = Fs.df; }}, ToWord,
+ Trunc);
+ 0x6: ceil_w_d({{ val = Fs.df; }}, ToWord,
+ Ceil);
+ 0x7: floor_w_d({{ val = Fs.df; }}, ToWord,
+ Floor);
}
}
0x2: decode FUNCTION_LO {
0x1: decode MOVCF {
- format FloatOp {
- 0x0: movf_d({{if (getFPConditionCode(FCSR,CC) == 0) Fd.df = Fs.df; }});
- 0x1: movt_d({{if (getFPConditionCode(FCSR,CC) == 1) Fd.df = Fs.df; }});
+ format BasicOp {
+ 0x0: movf_d({{ Fd.df = (getCondCode(FCSR,CC) == 0) ?
+ Fs.df : Fd.df;
+ }});
+ 0x1: movt_d({{ Fd.df = (getCondCode(FCSR,CC) == 1) ?
+ Fs.df : Fd.df;
+ }});
}
}
format BasicOp {
- 0x2: movz_d({{ if (Rt == 0) Fd.df = Fs.df; }});
- 0x3: movn_d({{ if (Rt != 0) Fd.df = Fs.df; }});
+ 0x2: movz_d({{ Fd.df = (Rt == 0) ? Fs.df : Fd.df; }});
+ 0x3: movn_d({{ Fd.df = (Rt != 0) ? Fs.df : Fd.df; }});
}
format FloatOp {
- 0x5: recip_d({{ Fd.df = 1 / Fs.df}});
+ 0x5: recip_d({{ Fd.df = 1 / Fs.df }});
0x6: rsqrt_d({{ Fd.df = 1 / sqrt(Fs.df) }});
}
}
0x4: decode FUNCTION_LO {
- format FloatOp {
- 0x0: cvt_s_d({{
- Fd.uw = fpConvert(Fs.df, DOUBLE_TO_SINGLE);
- }});
-
- 0x4: cvt_w_d({{
- Fd.uw = fpConvert(Fs.df, DOUBLE_TO_WORD);
- }});
-
- 0x5: cvt_l_d({{
- Fd.ud = fpConvert(Fs.df, DOUBLE_TO_LONG);
- }});
+ format FloatConvertOp {
+ 0x0: cvt_s_d({{ val = Fs.df; }}, ToSingle);
+ 0x4: cvt_w_d({{ val = Fs.df; }}, ToWord);
+ 0x5: cvt_l_d({{ val = Fs.df; }}, ToLong);
}
}
0x6: decode FUNCTION_LO {
format FloatCompareOp {
- 0x0: c_f_d({{ cond = 0; }});
-
- 0x1: c_un_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = 0;
- }});
-
- 0x2: c_eq_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df == Ft.df);
- }});
-
- 0x3: c_ueq_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df == Ft.df);
- }});
-
- 0x4: c_olt_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df < Ft.df);
- }});
-
- 0x5: c_ult_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df < Ft.df);
- }});
-
- 0x6: c_ole_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df <= Ft.df);
- }});
-
- 0x7: c_ule_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df <= Ft.df);
- }});
+ 0x0: c_f_d({{ cond = 0; }}, DoublePrecision,
+ UnorderedFalse);
+ 0x1: c_un_d({{ cond = 0; }}, DoublePrecision,
+ UnorderedTrue);
+ 0x2: c_eq_d({{ cond = (Fs.df == Ft.df); }},
+ UnorderedFalse);
+ 0x3: c_ueq_d({{ cond = (Fs.df == Ft.df); }},
+ UnorderedTrue);
+ 0x4: c_olt_d({{ cond = (Fs.df < Ft.df); }},
+ UnorderedFalse);
+ 0x5: c_ult_d({{ cond = (Fs.df < Ft.df); }},
+ UnorderedTrue);
+ 0x6: c_ole_d({{ cond = (Fs.df <= Ft.df); }},
+ UnorderedFalse);
+ 0x7: c_ule_d({{ cond = (Fs.df <= Ft.df); }},
+ UnorderedTrue);
}
}
0x7: decode FUNCTION_LO {
- format FloatCompareWithXcptOp {
- 0x0: c_sf_d({{ cond = 0; }});
-
- 0x1: c_ngle_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = 0;
- }});
-
- 0x2: c_seq_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df == Ft.df);
- }});
-
- 0x3: c_ngl_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df == Ft.df);
- }});
-
- 0x4: c_lt_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df < Ft.df);
- }});
-
- 0x5: c_nge_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df < Ft.df);
- }});
-
- 0x6: c_le_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 0;
- else
- cond = (Fs.df <= Ft.df);
- }});
-
- 0x7: c_ngt_d({{
- if (isnan(Fs.df) || isnan(Ft.df))
- cond = 1;
- else
- cond = (Fs.df <= Ft.df);
- }});
+ format FloatCompareOp {
+ 0x0: c_sf_d({{ cond = 0; }}, DoublePrecision,
+ UnorderedFalse, QnanException);
+ 0x1: c_ngle_d({{ cond = 0; }}, DoublePrecision,
+ UnorderedTrue, QnanException);
+ 0x2: c_seq_d({{ cond = (Fs.df == Ft.df); }},
+ UnorderedFalse, QnanException);
+ 0x3: c_ngl_d({{ cond = (Fs.df == Ft.df); }},
+ UnorderedTrue, QnanException);
+ 0x4: c_lt_d({{ cond = (Fs.df < Ft.df); }},
+ UnorderedFalse, QnanException);
+ 0x5: c_nge_d({{ cond = (Fs.df < Ft.df); }},
+ UnorderedTrue, QnanException);
+ 0x6: c_le_d({{ cond = (Fs.df <= Ft.df); }},
+ UnorderedFalse, QnanException);
+ 0x7: c_ngt_d({{ cond = (Fs.df <= Ft.df); }},
+ UnorderedTrue, QnanException);
}
}
}
@@ -893,19 +656,9 @@ decode OPCODE_HI default Unknown::unknown() {
//Table A-16 MIPS32 COP1 Encoding of Function Field When rs=W
0x4: decode FUNCTION {
format FloatConvertOp {
- 0x20: cvt_s_w({{
- Fd.uw = fpConvert(Fs.sf, WORD_TO_SINGLE);
- }});
-
- 0x21: cvt_d_w({{
- Fd.ud = fpConvert(Fs.sf, WORD_TO_DOUBLE);
- }});
- }
-
- format Float64ConvertOp {
- 0x26: cvt_ps_pw({{
- Fd.ud = fpConvert(Fs.ud, WORD_TO_PS);
- }});
+ 0x20: cvt_s_w({{ val = Fs.uw; }}, ToSingle);
+ 0x21: cvt_d_w({{ val = Fs.uw; }}, ToDouble);
+ 0x26: FailUnimpl::cvt_ps_w();
}
}
@@ -913,18 +666,10 @@ decode OPCODE_HI default Unknown::unknown() {
//Note: "1. Format type L is legal only if 64-bit floating point operations
//are enabled."
0x5: decode FUNCTION_HI {
- format Float64ConvertOp {
- 0x20: cvt_s_l({{
- Fd.uw = fpConvert(Fs.ud, LONG_TO_SINGLE);
- }});
-
- 0x21: cvt_d_l({{
- Fd.ud = fpConvert(Fs.ud, LONG_TO_DOUBLE);
- }});
-
- 0x26: cvt_ps_l({{
- Fd.ud = fpConvert(Fs.ud, LONG_TO_PS);
- }});
+ format FloatConvertOp {
+ 0x20: cvt_s_l({{ val = Fs.ud; }}, ToSingle);
+ 0x21: cvt_d_l({{ val = Fs.ud; }}, ToDouble);
+ 0x26: FailUnimpl::cvt_ps_l();
}
}
@@ -938,30 +683,25 @@ decode OPCODE_HI default Unknown::unknown() {
Fd1.sf = Fs1.sf + Ft2.sf;
Fd2.sf = Fs2.sf + Ft2.sf;
}});
-
0x1: sub_ps({{
Fd1.sf = Fs1.sf - Ft2.sf;
Fd2.sf = Fs2.sf - Ft2.sf;
}});
-
0x2: mul_ps({{
Fd1.sf = Fs1.sf * Ft2.sf;
Fd2.sf = Fs2.sf * Ft2.sf;
}});
-
0x5: abs_ps({{
Fd1.sf = fabs(Fs1.sf);
Fd2.sf = fabs(Fs2.sf);
}});
-
0x6: mov_ps({{
Fd1.sf = Fs1.sf;
Fd2.sf = Fs2.sf;
}});
-
0x7: neg_ps({{
- Fd1.sf = -1 * Fs1.sf;
- Fd2.sf = -1 * Fs2.sf;
+ Fd1.sf = -(Fs1.sf);
+ Fd2.sf = -(Fs2.sf);
}});
}
}
@@ -970,236 +710,112 @@ decode OPCODE_HI default Unknown::unknown() {
0x1: decode MOVCF {
format Float64Op {
0x0: movf_ps({{
- if (getFPConditionCode(FCSR, CC) == 0)
- Fd1 = Fs1;
- if (getFPConditionCode(FCSR, CC+1) == 0)
- Fd2 = Fs2;
+ Fd1 = (getCondCode(FCSR, CC) == 0) ?
+ Fs1 : Fd1;
+ Fd2 = (getCondCode(FCSR, CC+1) == 0) ?
+ Fs2 : Fd2;
}});
-
0x1: movt_ps({{
- if (getFPConditionCode(FCSR, CC) == 1)
- Fd1 = Fs1;
- if (getFPConditionCode(FCSR, CC+1) == 1)
- Fd2 = Fs2;
+ Fd2 = (getCondCode(FCSR, CC) == 1) ?
+ Fs1 : Fd1;
+ Fd2 = (getCondCode(FCSR, CC+1) == 1) ?
+ Fs2 : Fd2;
}});
}
}
format Float64Op {
0x2: movz_ps({{
- if (getFPConditionCode(FCSR, CC) == 0)
- Fd1 = Fs1;
- if (getFPConditionCode(FCSR, CC) == 0)
- Fd2 = Fs2;
+ Fd1 = (getCondCode(FCSR, CC) == 0) ?
+ Fs1 : Fd1;
+ Fd2 = (getCondCode(FCSR, CC) == 0) ?
+ Fs2 : Fd2;
}});
-
0x3: movn_ps({{
- if (getFPConditionCode(FCSR, CC) == 1)
- Fd1 = Fs1;
- if (getFPConditionCode(FCSR, CC) == 1)
- Fd2 = Fs2;
+ Fd1 = (getCondCode(FCSR, CC) == 1) ?
+ Fs1 : Fd1;
+ Fd2 = (getCondCode(FCSR, CC) == 1) ?
+ Fs2 : Fd2;
}});
}
}
0x4: decode FUNCTION_LO {
- 0x0: Float64Op::cvt_s_pu({{
- Fd.uw = fpConvert(Fs2.uw, PU_TO_SINGLE);
- }});
+ 0x0: FloatOp::cvt_s_pu({{ Fd.sf = Fs2.sf; }});
}
0x5: decode FUNCTION_LO {
- format Float64Op {
- 0x0: cvt_s_pl({{
- Fd.uw = fpConvert(Fs1.uw, PL_TO_SINGLE);
- }});
+ 0x0: FloatOp::cvt_s_pl({{ Fd.sf = Fs1.sf; }});
- 0x4: pll({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft1.uw; }});
- 0x5: plu({{ Fd.ud = (uint64_t) Fs1.uw << 32 | Ft2.uw; }});
- 0x6: pul({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft1.uw; }});
- 0x7: puu({{ Fd.ud = (uint64_t) Fs2.uw << 32 | Ft2.uw; }});
+ format Float64Op {
+ 0x4: pll({{ Fd.ud = (uint64_t) Fs1.uw << 32 |
+ Ft1.uw;
+ }});
+ 0x5: plu({{ Fd.ud = (uint64_t) Fs1.uw << 32 |
+ Ft2.uw;
+ }});
+ 0x6: pul({{ Fd.ud = (uint64_t) Fs2.uw << 32 |
+ Ft1.uw;
+ }});
+ 0x7: puu({{ Fd.ud = (uint64_t) Fs2.uw << 32 |
+ Ft2.uw;
+ }});
}
}
0x6: decode FUNCTION_LO {
format FloatPSCompareOp {
- 0x0: c_f_ps({{ cond1 = 0; cond2 = 0; }});
-
- 0x1: c_un_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = 0;
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = 0;
-
- }});
-
- 0x2: c_eq_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 0;
- else
- cond1 = (Fs1.sf == Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf == Ft2.sf);
- }});
-
- 0x3: c_ueq_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs1.sf == Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf == Ft2.sf);
- }});
-
- 0x4: c_olt_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 0;
- else
- cond1 = (Fs1.sf < Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf < Ft2.sf);
- }});
-
- 0x5: c_ult_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs.sf < Ft.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf < Ft2.sf);
- }});
-
- 0x6: c_ole_ps({{
- if (isnan(Fs.sf) || isnan(Ft.sf))
- cond1 = 0;
- else
- cond1 = (Fs.sf <= Ft.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf <= Ft2.sf);
- }});
-
- 0x7: c_ule_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs1.sf <= Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf <= Ft2.sf);
- }});
+ 0x0: c_f_ps({{ cond1 = 0; }}, {{ cond2 = 0; }},
+ UnorderedFalse);
+ 0x1: c_un_ps({{ cond1 = 0; }}, {{ cond2 = 0; }},
+ UnorderedTrue);
+ 0x2: c_eq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }},
+ {{ cond2 = (Fs2.sf == Ft2.sf); }},
+ UnorderedFalse);
+ 0x3: c_ueq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }},
+ {{ cond2 = (Fs2.sf == Ft2.sf); }},
+ UnorderedTrue);
+ 0x4: c_olt_ps({{ cond1 = (Fs1.sf < Ft1.sf); }},
+ {{ cond2 = (Fs2.sf < Ft2.sf); }},
+ UnorderedFalse);
+ 0x5: c_ult_ps({{ cond1 = (Fs.sf < Ft.sf); }},
+ {{ cond2 = (Fs2.sf < Ft2.sf); }},
+ UnorderedTrue);
+ 0x6: c_ole_ps({{ cond1 = (Fs.sf <= Ft.sf); }},
+ {{ cond2 = (Fs2.sf <= Ft2.sf); }},
+ UnorderedFalse);
+ 0x7: c_ule_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }},
+ {{ cond2 = (Fs2.sf <= Ft2.sf); }},
+ UnorderedTrue);
}
}
0x7: decode FUNCTION_LO {
- format FloatPSCompareWithXcptOp {
- 0x0: c_sf_ps({{ cond1 = 0; cond2 = 0; }});
-
- 0x1: c_ngle_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = 0;
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = 0;
- }});
-
- 0x2: c_seq_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 0;
- else
- cond1 = (Fs1.sf == Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf == Ft2.sf);
- }});
-
- 0x3: c_ngl_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs1.sf == Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf == Ft2.sf);
- }});
-
- 0x4: c_lt_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 0;
- else
- cond1 = (Fs1.sf < Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf < Ft2.sf);
- }});
-
- 0x5: c_nge_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs1.sf < Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf < Ft2.sf);
- }});
-
- 0x6: c_le_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 0;
- else
- cond1 = (Fs1.sf <= Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 0;
- else
- cond2 = (Fs2.sf <= Ft2.sf);
- }});
-
- 0x7: c_ngt_ps({{
- if (isnan(Fs1.sf) || isnan(Ft1.sf))
- cond1 = 1;
- else
- cond1 = (Fs1.sf <= Ft1.sf);
-
- if (isnan(Fs2.sf) || isnan(Ft2.sf))
- cond2 = 1;
- else
- cond2 = (Fs2.sf <= Ft2.sf);
- }});
+ format FloatPSCompareOp {
+ 0x0: c_sf_ps({{ cond1 = 0; }}, {{ cond2 = 0; }},
+ UnorderedFalse, QnanException);
+ 0x1: c_ngle_ps({{ cond1 = 0; }},
+ {{ cond2 = 0; }},
+ UnorderedTrue, QnanException);
+ 0x2: c_seq_ps({{ cond1 = (Fs1.sf == Ft1.sf); }},
+ {{ cond2 = (Fs2.sf == Ft2.sf); }},
+ UnorderedFalse, QnanException);
+ 0x3: c_ngl_ps({{ cond1 = (Fs1.sf == Ft1.sf); }},
+ {{ cond2 = (Fs2.sf == Ft2.sf); }},
+ UnorderedTrue, QnanException);
+ 0x4: c_lt_ps({{ cond1 = (Fs1.sf < Ft1.sf); }},
+ {{ cond2 = (Fs2.sf < Ft2.sf); }},
+ UnorderedFalse, QnanException);
+ 0x5: c_nge_ps({{ cond1 = (Fs1.sf < Ft1.sf); }},
+ {{ cond2 = (Fs2.sf < Ft2.sf); }},
+ UnorderedTrue, QnanException);
+ 0x6: c_le_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }},
+ {{ cond2 = (Fs2.sf <= Ft2.sf); }},
+ UnorderedFalse, QnanException);
+ 0x7: c_ngt_ps({{ cond1 = (Fs1.sf <= Ft1.sf); }},
+ {{ cond2 = (Fs2.sf <= Ft2.sf); }},
+ UnorderedTrue, QnanException);
}
}
}
@@ -1209,9 +825,9 @@ decode OPCODE_HI default Unknown::unknown() {
//Table A-19 MIPS32 COP2 Encoding of rs Field
0x2: decode RS_MSB {
- 0x0: decode RS_HI {
- 0x0: decode RS_LO {
- format WarnUnimpl {
+ format FailUnimpl {
+ 0x0: decode RS_HI {
+ 0x0: decode RS_LO {
0x0: mfc2();
0x2: cfc2();
0x3: mfhc2();
@@ -1219,18 +835,14 @@ decode OPCODE_HI default Unknown::unknown() {
0x6: ctc2();
0x7: mftc2();
}
- }
- 0x1: decode ND {
- 0x0: decode TF {
- format WarnUnimpl {
+ 0x1: decode ND {
+ 0x0: decode TF {
0x0: bc2f();
0x1: bc2t();
}
- }
- 0x1: decode TF {
- format WarnUnimpl {
+ 0x1: decode TF {
0x0: bc2fl();
0x1: bc2tl();
}
@@ -1244,441 +856,242 @@ decode OPCODE_HI default Unknown::unknown() {
//operations are enabled."
0x3: decode FUNCTION_HI {
0x0: decode FUNCTION_LO {
- format LoadFloatMemory {
- 0x0: lwxc1({{ Ft.uw = Mem.uw;}}, {{ EA = Rs + Rt; }});
- 0x1: ldxc1({{ Ft.ud = Mem.ud;}}, {{ EA = Rs + Rt; }});
- 0x5: luxc1({{ Ft.uw = Mem.ud;}}, {{ EA = Rs + Rt; }});
+ format LoadIndexedMemory {
+ 0x0: lwxc1({{ Fd.uw = Mem.uw;}});
+ 0x1: ldxc1({{ Fd.ud = Mem.ud;}});
+ 0x5: luxc1({{ Fd.ud = Mem.ud;}},
+ {{ EA = (Rs + Rt) & ~7; }});
}
}
0x1: decode FUNCTION_LO {
- format StoreFloatMemory {
- 0x0: swxc1({{ Mem.uw = Ft.uw;}}, {{ EA = Rs + Rt; }});
- 0x1: sdxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }});
- 0x5: suxc1({{ Mem.ud = Ft.ud;}}, {{ EA = Rs + Rt; }});
+ format StoreIndexedMemory {
+ 0x0: swxc1({{ Mem.uw = Fs.uw;}});
+ 0x1: sdxc1({{ Mem.ud = Fs.ud;}});
+ 0x5: suxc1({{ Mem.ud = Fs.ud;}},
+ {{ EA = (Rs + Rt) & ~7; }});
}
- 0x7: WarnUnimpl::prefx();
+ 0x7: Prefetch::prefx({{ EA = Rs + Rt; }});
}
- format FloatOp {
- 0x3: WarnUnimpl::alnv_ps();
+ 0x3: decode FUNCTION_LO {
+ 0x6: Float64Op::alnv_ps({{ if (Rs<2:0> == 0) {
+ Fd.ud = Fs.ud;
+ } else if (Rs<2:0> == 4) {
+ #if BYTE_ORDER == BIG_ENDIAN
+ Fd.ud = Fs.ud<31:0> << 32 |
+ Ft.ud<63:32>;
+ #elif BYTE_ORDER == LITTLE_ENDIAN
+ Fd.ud = Ft.ud<31:0> << 32 |
+ Fs.ud<63:32>;
+ #endif
+ } else {
+ Fd.ud = Fd.ud;
+ }
+ }});
+ }
- format BasicOp {
- 0x4: decode FUNCTION_LO {
- 0x0: madd_s({{ Fd.sf = (Fs.sf * Ft.sf) + Fr.sf; }});
- 0x1: madd_d({{ Fd.df = (Fs.df * Ft.df) + Fr.df; }});
- 0x6: madd_ps({{
- Fd1.sf = (Fs1.df * Ft1.df) + Fr1.df;
- Fd2.sf = (Fs2.df * Ft2.df) + Fr2.df;
- }});
- }
+ format FloatAccOp {
+ 0x4: decode FUNCTION_LO {
+ 0x0: madd_s({{ Fd.sf = (Fs.sf * Ft.sf) + Fr.sf; }});
+ 0x1: madd_d({{ Fd.df = (Fs.df * Ft.df) + Fr.df; }});
+ 0x6: madd_ps({{
+ Fd1.sf = (Fs1.df * Ft1.df) + Fr1.df;
+ Fd2.sf = (Fs2.df * Ft2.df) + Fr2.df;
+ }});
+ }
- 0x5: decode FUNCTION_LO {
- 0x0: msub_s({{ Fd.sf = (Fs.sf * Ft.sf) - Fr.sf; }});
- 0x1: msub_d({{ Fd.df = (Fs.df * Ft.df) - Fr.df; }});
- 0x6: msub_ps({{
- Fd1.sf = (Fs1.df * Ft1.df) - Fr1.df;
- Fd2.sf = (Fs2.df * Ft2.df) - Fr2.df;
- }});
- }
+ 0x5: decode FUNCTION_LO {
+ 0x0: msub_s({{ Fd.sf = (Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: msub_d({{ Fd.df = (Fs.df * Ft.df) - Fr.df; }});
+ 0x6: msub_ps({{
+ Fd1.sf = (Fs1.df * Ft1.df) - Fr1.df;
+ Fd2.sf = (Fs2.df * Ft2.df) - Fr2.df;
+ }});
+ }
- 0x6: decode FUNCTION_LO {
- 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
- 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Ft.df) + Fr.df; }});
- 0x6: nmadd_ps({{
- Fd1.sf = -1 * ((Fs1.df * Ft1.df) + Fr1.df);
- Fd2.sf = -1 * ((Fs2.df * Ft2.df) + Fr2.df);
- }});
- }
+ 0x6: decode FUNCTION_LO {
+ 0x0: nmadd_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: nmadd_d({{ Fd.df = (-1 * Fs.df * Ft.df) + Fr.df; }});
+ 0x6: nmadd_ps({{
+ Fd1.sf = -((Fs1.df * Ft1.df) + Fr1.df);
+ Fd2.sf = -((Fs2.df * Ft2.df) + Fr2.df);
+ }});
+ }
- 0x7: decode FUNCTION_LO {
- 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
- 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Ft.df) - Fr.df; }});
- 0x6: nmsub_ps({{
- Fd1.sf = -1 * ((Fs1.df * Ft1.df) - Fr1.df);
- Fd2.sf = -1 * ((Fs2.df * Ft2.df) - Fr2.df);
- }});
- }
+ 0x7: decode FUNCTION_LO {
+ 0x0: nmsub_s({{ Fd.sf = (-1 * Fs.sf * Ft.sf) - Fr.sf; }});
+ 0x1: nmsub_d({{ Fd.df = (-1 * Fs.df * Ft.df) - Fr.df; }});
+ 0x6: nmsub_ps({{
+ Fd1.sf = -((Fs1.df * Ft1.df) - Fr1.df);
+ Fd2.sf = -((Fs2.df * Ft2.df) - Fr2.df);
+ }});
}
+
}
}
- format BranchLikely {
- 0x4: beql({{ cond = (Rs.sw == 0); }});
- 0x5: bnel({{ cond = (Rs.sw != 0); }});
- 0x6: blezl({{ cond = (Rs.sw <= 0); }});
- 0x7: bgtzl({{ cond = (Rs.sw > 0); }});
+ format Branch {
+ 0x4: beql({{ cond = (Rs.sw == Rt.sw); }}, Likely);
+ 0x5: bnel({{ cond = (Rs.sw != Rt.sw); }}, Likely);
+ 0x6: blezl({{ cond = (Rs.sw <= 0); }}, Likely);
+ 0x7: bgtzl({{ cond = (Rs.sw > 0); }}, Likely);
}
}
- 0x3: decode OPCODE_LO default FailUnimpl::reserved() {
-
+ 0x3: decode OPCODE_LO {
//Table A-5 MIPS32 SPECIAL2 Encoding of Function Field
0x4: decode FUNCTION_HI {
-
0x0: decode FUNCTION_LO {
- format IntOp {
- 0x0: madd({{
- int64_t temp1 = (int64_t) HI << 32 | LO;
- temp1 = temp1 + (Rs.sw * Rt.sw);
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
-
- 0x1: maddu({{
- int64_t temp1 = (int64_t) HI << 32 | LO;
- temp1 = temp1 + (Rs.uw * Rt.uw);
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
-
- 0x2: mul({{ Rd.sw = Rs.sw * Rt.sw; }});
-
- 0x4: msub({{
- int64_t temp1 = (int64_t) HI << 32 | LO;
- temp1 = temp1 - (Rs.sw * Rt.sw);
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
+ 0x2: IntOp::mul({{ int64_t temp1 = Rs.sd * Rt.sd;
+ Rd.sw = temp1<31:0>
+ }});
- 0x5: msubu({{
- int64_t temp1 = (int64_t) HI << 32 | LO;
- temp1 = temp1 - (Rs.uw * Rt.uw);
- HI = temp1<63:32>;
- LO = temp1<31:0>;
- }});
+ format HiLoOp {
+ 0x0: madd({{ val = ((int64_t) HI << 32 | LO) +
+ (Rs.sd * Rt.sd);
+ }});
+ 0x1: maddu({{ val = ((uint64_t) HI << 32 | LO) +
+ (Rs.ud * Rt.ud);
+ }});
+ 0x4: msub({{ val = ((int64_t) HI << 32 | LO) -
+ (Rs.sd * Rt.sd);
+ }});
+ 0x5: msubu({{ val = ((uint64_t) HI << 32 | LO) -
+ (Rs.ud * Rt.ud);
+ }});
}
}
0x4: decode FUNCTION_LO {
format BasicOp {
- 0x0: clz({{
- int cnt = 0;
- uint32_t mask = 0x80000000;
- for (int i=0; i < 32; i++) {
- if( (Rs & mask) == 0) {
- cnt++;
- } else {
- break;
- }
- }
- Rd.uw = cnt;
- }});
-
- 0x1: clo({{
- int cnt = 0;
- uint32_t mask = 0x80000000;
- for (int i=0; i < 32; i++) {
- if( (Rs & mask) != 0) {
- cnt++;
- } else {
- break;
- }
- }
- Rd.uw = cnt;
- }});
+ 0x0: clz({{ int cnt = 32;
+ for (int idx = 31; idx >= 0; idx--) {
+ if( Rs<idx:idx> == 1) {
+ cnt = 31 - idx;
+ break;
+ }
+ }
+ Rd.uw = cnt;
+ }});
+ 0x1: clo({{ int cnt = 32;
+ for (int idx = 31; idx >= 0; idx--) {
+ if( Rs<idx:idx> == 0) {
+ cnt = 31 - idx;
+ break;
+ }
+ }
+ Rd.uw = cnt;
+ }});
}
}
0x7: decode FUNCTION_LO {
- 0x7: WarnUnimpl::sdbbp();
+ 0x7: FailUnimpl::sdbbp();
}
}
- //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2 of the Architecture
+ //Table A-6 MIPS32 SPECIAL3 Encoding of Function Field for Release 2
+ //of the Architecture
0x7: decode FUNCTION_HI {
-
0x0: decode FUNCTION_LO {
- format FailUnimpl {
- 0x1: ext();
- 0x4: ins();
+ format BasicOp {
+ 0x0: ext({{ Rt.uw = bits(Rs.uw, MSB+LSB, LSB); }});
+ 0x4: ins({{ Rt.uw = bits(Rt.uw, 31, MSB+1) << (MSB+1) |
+ bits(Rs.uw, MSB-LSB, 0) << LSB |
+ bits(Rt.uw, LSB-1, 0);
+ }});
}
}
0x1: decode FUNCTION_LO {
- format FailUnimpl {
+ format MipsMT {
0x0: fork();
0x1: yield();
}
}
-
//Table A-10 MIPS32 BSHFL Encoding of sa Field
0x4: decode SA {
-
- 0x02: FailUnimpl::wsbh();
-
format BasicOp {
- 0x10: seb({{ Rd.sw = Rt.sw<7:0>}});
- 0x18: seh({{ Rd.sw = Rt.sw<15:0>}});
+ 0x02: wsbh({{ Rd.uw = Rt.uw<23:16> << 24 |
+ Rt.uw<31:24> << 16 |
+ Rt.uw<7:0> << 8 |
+ Rt.uw<15:8>;
+ }});
+ 0x10: seb({{ Rd.sw = Rt.sb; }});
+ 0x18: seh({{ Rd.sw = Rt.sh; }});
}
}
0x6: decode FUNCTION_LO {
- 0x7: FailUnimpl::rdhwr();//{{ /*Rt = xc->hwRegs[RD];*/ }}
+ 0x7: FailUnimpl::rdhwr();
}
}
}
- 0x4: decode OPCODE_LO default FailUnimpl::reserved() {
+ 0x4: decode OPCODE_LO {
format LoadMemory {
0x0: lb({{ Rt.sw = Mem.sb; }});
0x1: lh({{ Rt.sw = Mem.sh; }});
-
- 0x2: lwl({{
- uint32_t mem_word = Mem.uw;
- uint32_t unalign_addr = Rs + disp;
- uint32_t offset = unalign_addr & 0x00000003;
-#if BYTE_ORDER == BIG_ENDIAN
- switch(offset)
- {
- case 0:
- Rt = mem_word;
- break;
-
- case 1:
- Rt &= 0x000F;
- Rt |= (mem_word << 4);
- break;
-
- case 2:
- Rt &= 0x00FF;
- Rt |= (mem_word << 8);
- break;
-
- case 3:
- Rt &= 0x0FFF;
- Rt |= (mem_word << 12);
- break;
-
- default:
- panic("lwl: bad offset");
- }
-#elif BYTE_ORDER == LITTLE_ENDIAN
- switch(offset)
- {
- case 0:
- Rt &= 0x0FFF;
- Rt |= (mem_word << 12);
- break;
-
- case 1:
- Rt &= 0x00FF;
- Rt |= (mem_word << 8);
- break;
-
- case 2:
- Rt &= 0x000F;
- Rt |= (mem_word << 4);
- break;
-
- case 3:
- Rt = mem_word;
- break;
-
- default:
- panic("lwl: bad offset");
- }
-#endif
- }}, {{ EA = (Rs + disp) & ~3; }});
-
0x3: lw({{ Rt.sw = Mem.sw; }});
0x4: lbu({{ Rt.uw = Mem.ub; }});
0x5: lhu({{ Rt.uw = Mem.uh; }});
- 0x6: lwr({{
- uint32_t mem_word = Mem.uw;
- uint32_t unalign_addr = Rs + disp;
- uint32_t offset = unalign_addr & 0x00000003;
-
-#if BYTE_ORDER == BIG_ENDIAN
- switch(offset)
- {
- case 0: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break;
- case 1: Rt &= 0xFF00; Rt |= (mem_word >> 8); break;
- case 2: Rt &= 0xF000; Rt |= (mem_word >> 4); break;
- case 3: Rt = mem_word; break;
- default: panic("lwr: bad offset");
- }
-#elif BYTE_ORDER == LITTLE_ENDIAN
- switch(offset)
- {
- case 0: Rt = mem_word; break;
- case 1: Rt &= 0xF000; Rt |= (mem_word >> 4); break;
- case 2: Rt &= 0xFF00; Rt |= (mem_word >> 8); break;
- case 3: Rt &= 0xFFF0; Rt |= (mem_word >> 12); break;
- default: panic("lwr: bad offset");
- }
-#endif
- }},
- {{ EA = (Rs + disp) & ~3; }});
+ }
+
+ format LoadUnalignedMemory {
+ 0x2: lwl({{ uint32_t mem_shift = 24 - (8 * byte_offset);
+ Rt.uw = mem_word << 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;
+ }});
}
}
- 0x5: decode OPCODE_LO default FailUnimpl::reserved() {
+ 0x5: decode OPCODE_LO {
format StoreMemory {
0x0: sb({{ Mem.ub = Rt<7:0>; }});
0x1: sh({{ Mem.uh = Rt<15:0>; }});
- 0x2: swl({{
- uint32_t mem_word = 0;
- uint32_t aligned_addr = (Rs + disp) & ~3;
- uint32_t unalign_addr = Rs + disp;
- uint32_t offset = unalign_addr & 0x00000003;
-
- DPRINTF(IEW,"Execute: aligned=0x%x unaligned=0x%x\n offset=0x%x",
- aligned_addr,unalign_addr,offset);
-
- fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags);
-
-#if BYTE_ORDER == BIG_ENDIAN
- switch(offset)
- {
- case 0:
- Mem = Rt;
- break;
-
- case 1:
- mem_word &= 0xF000;
- mem_word |= (Rt >> 4);
- Mem = mem_word;
- break;
-
- case 2:
- mem_word &= 0xFF00;
- mem_word |= (Rt >> 8);
- Mem = mem_word;
- break;
-
- case 3:
- mem_word &= 0xFFF0;
- mem_word |= (Rt >> 12);
- Mem = mem_word;
- break;
-
- default:
- panic("swl: bad offset");
- }
-#elif BYTE_ORDER == LITTLE_ENDIAN
- switch(offset)
- {
- case 0:
- mem_word &= 0xFFF0;
- mem_word |= (Rt >> 12);
- Mem = mem_word;
- break;
-
- case 1:
- mem_word &= 0xFF00;
- mem_word |= (Rt >> 8);
- Mem = mem_word;
- break;
-
- case 2:
- mem_word &= 0xF000;
- mem_word |= (Rt >> 4);
- Mem = mem_word;
- break;
-
- case 3:
- Mem = Rt;
- break;
-
- default:
- panic("swl: bad offset");
- }
-#endif
- }},{{ EA = (Rs + disp) & ~3; }},mem_flags = NO_ALIGN_FAULT);
-
0x3: sw({{ Mem.uw = Rt<31:0>; }});
-
- 0x6: swr({{
- uint32_t mem_word = 0;
- uint32_t aligned_addr = (Rs + disp) & ~3;
- uint32_t unalign_addr = Rs + disp;
- uint32_t offset = unalign_addr & 0x00000003;
-
- fault = xc->read(aligned_addr, (uint32_t&)mem_word, memAccessFlags);
-
-#if BYTE_ORDER == BIG_ENDIAN
- switch(offset)
- {
- case 0:
- mem_word &= 0x0FFF;
- mem_word |= (Rt << 12);
- Mem = mem_word;
- break;
-
- case 1:
- mem_word &= 0x00FF;
- mem_word |= (Rt << 8);
- Mem = mem_word;
- break;
-
- case 2:
- mem_word &= 0x000F;
- mem_word |= (Rt << 4);
- Mem = mem_word;
- break;
-
- case 3:
- Mem = Rt;
- break;
-
- default:
- panic("swr: bad offset");
- }
-#elif BYTE_ORDER == LITTLE_ENDIAN
- switch(offset)
- {
- case 0:
- Mem = Rt;
- break;
-
- case 1:
- mem_word &= 0x000F;
- mem_word |= (Rt << 4);
- Mem = mem_word;
- break;
-
- case 2:
- mem_word &= 0x00FF;
- mem_word |= (Rt << 8);
- Mem = mem_word;
- break;
-
- case 3:
- mem_word &= 0x0FFF;
- mem_word |= (Rt << 12);
- Mem = mem_word;
- break;
-
- default:
- panic("swr: bad offset");
- }
-#endif
- }},{{ EA = (Rs + disp) & ~3;}},mem_flags = NO_ALIGN_FAULT);
}
- format WarnUnimpl {
- 0x7: cache();
+ 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;
+ }});
+ 0x6: swr({{ uint32_t reg_shift = 8 * byte_offset;
+ mem_word = Rt.uw << reg_shift |
+ mem_word & (mask(reg_shift));
+ }});
}
+ 0x7: FailUnimpl::cache();
}
- 0x6: decode OPCODE_LO default FailUnimpl::reserved() {
- 0x0: LoadMemory::ll({{Rt.uw = Mem.uw}},mem_flags=LOCKED);
-
- format LoadFloatMemory {
- 0x1: lwc1({{ Ft.uw = Mem.uw; }});
+ 0x6: decode OPCODE_LO {
+ format LoadMemory {
+ 0x0: ll({{ Rt.uw = Mem.uw; }}, mem_flags=LOCKED);
+ 0x1: lwc1({{ Ft.uw = Mem.uw; }});
0x5: ldc1({{ Ft.ud = Mem.ud; }});
}
+
+ 0x3: Prefetch::pref();
}
- 0x7: decode OPCODE_LO default FailUnimpl::reserved() {
- 0x0: StoreMemory::sc({{ Mem.uw = Rt.uw; Rt.uw = 1; }});
+ 0x7: decode OPCODE_LO {
+ 0x0: StoreCond::sc({{ Mem.uw = Rt.uw;}},
+ {{ uint64_t tmp = write_result;
+ Rt.uw = (tmp == 0 || tmp == 1) ? tmp : Rt.uw;
+ }}, mem_flags=LOCKED);
- format StoreFloatMemory {
+ format StoreMemory {
0x1: swc1({{ Mem.uw = Ft.uw; }});
0x5: sdc1({{ Mem.ud = Ft.ud; }});
}
diff --git a/src/arch/mips/isa/formats/basic.isa b/src/arch/mips/isa/formats/basic.isa
index c02af7ddc..29dafd541 100644
--- a/src/arch/mips/isa/formats/basic.isa
+++ b/src/arch/mips/isa/formats/basic.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
// Declarations for execute() methods.
def template BasicExecDeclare {{
Fault execute(%(CPU_exec_context)s *, Trace::InstRecord *) const;
@@ -12,11 +40,11 @@ def template BasicDeclare {{
*/
class %(class_name)s : public %(base_class)s
{
- public:
+ public:
/// Constructor.
%(class_name)s(MachInst machInst);
%(BasicExecDeclare)s
- };
+ };
}};
// Basic instruction class constructor template.
@@ -27,6 +55,7 @@ def template BasicConstructor {{
}
}};
+
// Basic instruction class execute method template.
def template BasicExecute {{
Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
diff --git a/src/arch/mips/isa/formats/branch.isa b/src/arch/mips/isa/formats/branch.isa
index 8cfa37a20..5230ce9cc 100644
--- a/src/arch/mips/isa/formats/branch.isa
+++ b/src/arch/mips/isa/formats/branch.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Control transfer instructions
@@ -68,29 +96,6 @@ output header {{
};
/**
- * Base class for branch likely branches (PC-relative control transfers),
- */
- class BranchLikely : public PCDependentDisassembly
- {
- protected:
- /// target address (signed) Displacement .
- int32_t disp;
-
- /// Constructor.
- BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass)
- : PCDependentDisassembly(mnem, _machInst, __opClass),
- disp(OFFSET << 2)
- {
-
- }
-
- Addr branchTarget(Addr branchPC) const;
-
- std::string
- generateDisassembly(Addr pc, const SymbolTable *symtab) const;
- };
-
- /**
* Base class for jumps (register-indirect control transfers). In
* the Mips ISA, these are always unconditional.
*/
@@ -111,7 +116,7 @@ output header {{
{
}
- Addr branchTarget(ExecContext *xc) const;
+ Addr branchTarget(ThreadContext *tc) const;
std::string
generateDisassembly(Addr pc, const SymbolTable *symtab) const;
@@ -126,16 +131,10 @@ output decoder {{
}
Addr
- BranchLikely::branchTarget(Addr branchPC) const
- {
- return branchPC + 4 + disp;
- }
-
- Addr
- Jump::branchTarget(ExecContext *xc) const
+ Jump::branchTarget(ThreadContext *tc) const
{
- Addr NPC = xc->readPC() + 4;
- uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
+ Addr NPC = tc->readPC() + 4;
+ uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
return (Rb & ~3) | (NPC & 1);
}
@@ -171,49 +170,12 @@ output decoder {{
// unconditional branches)
if (_numSrcRegs == 1) {
printReg(ss, _srcRegIdx[0]);
- ss << ",";
+ ss << ", ";
} else if(_numSrcRegs == 2) {
printReg(ss, _srcRegIdx[0]);
- ss << ",";
+ ss << ", ";
printReg(ss, _srcRegIdx[1]);
- ss << ",";
- }
-
- Addr target = pc + 4 + disp;
-
- std::string str;
- if (symtab && symtab->findSymbol(target, str))
- ss << str;
- else
- ccprintf(ss, "0x%x", target);
-
- string inst_name = mnemonic;
-
- if (inst_name.substr(inst_name.length()-2,inst_name.length()) == "al"){
- ccprintf(ss, " (r31=0x%x)",pc+8);
- }
-
- return ss.str();
- }
-
- std::string
- BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
- {
- std::stringstream ss;
-
- ccprintf(ss, "%-10s ", mnemonic);
-
- // There's only one register arg (RA), but it could be
- // either a source (the condition for conditional
- // branches) or a destination (the link reg for
- // unconditional branches)
- if (_numSrcRegs > 0) {
- printReg(ss, _srcRegIdx[0]);
- ss << ",";
- }
- else if (_numDestRegs > 0) {
- printReg(ss, _destRegIdx[0]);
- ss << ",";
+ ss << ", ";
}
Addr target = pc + 4 + disp;
@@ -247,72 +209,64 @@ output decoder {{
printReg(ss, _srcRegIdx[0]);
} else if(_numSrcRegs == 2) {
printReg(ss, _srcRegIdx[0]);
- ss << ",";
+ ss << ", ";
printReg(ss, _srcRegIdx[1]);
- } else {
- panic(">= 3 Source Registers!!!");
}
return ss.str();
}
}};
-def format Branch(code,*flags) {{
- #Add Link Code if Link instruction
- strlen = len(name)
- if name[strlen-2:] == 'al':
- code += 'R31 = NNPC;\n'
+def format Branch(code,*opt_flags) {{
+ not_taken_code = ' NNPC = NNPC;\n'
+ not_taken_code += '} \n'
+
+ #Build Instruction Flags
+ #Use Link & Likely Flags to Add Link/Condition Code
+ inst_flags = ('IsDirectControl', )
+ for x in opt_flags:
+ if x == 'Link':
+ code += 'R31 = NNPC;\n'
+ elif x == 'Likely':
+ not_taken_code = ' NPC = NNPC;\n'
+ not_taken_code += ' NNPC = NNPC + 4;\n'
+ not_taken_code += '} \n'
+ inst_flags = ('IsCondDelaySlot', )
+ else:
+ inst_flags += (x, )
+
+ if 'cond == 1' in code:
+ inst_flags += ('IsCondControl', )
+ else:
+ inst_flags += ('IsUncondControl', )
#Condition code
code = 'bool cond;\n' + code
code += 'if (cond) {\n'
code += ' NNPC = NPC + disp;\n'
code += '} else {\n'
- code += ' NNPC = NNPC;\n'
- code += '} \n'
-
- iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
- ('IsDirectControl', 'IsCondControl'))
-
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
-}};
-
-
-def format BranchLikely(code,*flags) {{
- #Add Link Code if Link instruction
- strlen = len(name)
- if name[strlen-3:] == 'all':
- code += 'R31 = NNPC;\n'
-
- #Condition code
- code = 'bool cond;\n' + code
- code += 'if (cond) {'
- code += 'NNPC = NPC + disp;\n'
- code += '} \n'
-
-
- iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
- ('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
+ code += not_taken_code
+ iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), inst_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
exec_output = BasicExecute.subst(iop)
}};
-def format Jump(code,*flags) {{
- #Add Link Code if Link instruction
- strlen = len(name)
- if strlen > 1 and name[1:] == 'al':
+def format Jump(code, *opt_flags) {{
+ #Build Instruction Flags
+ #Use Link Flag to Add Link Code
+ inst_flags = ('IsIndirectControl', 'IsUncondControl')
+ for x in opt_flags:
+ if x == 'Link':
code = 'R31 = NNPC;\n' + code
+ elif x == 'ClearHazards':
+ code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
+ else:
+ inst_flags += (x, )
-
- iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\
- ('IsIndirectControl', 'IsUncondControl'))
-
+ iop = InstObjParams(name, Name, 'Jump', CodeBlock(code), inst_flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
diff --git a/src/arch/mips/isa/formats/control.isa b/src/arch/mips/isa/formats/control.isa
new file mode 100644
index 000000000..6c7d396f3
--- /dev/null
+++ b/src/arch/mips/isa/formats/control.isa
@@ -0,0 +1,156 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
+////////////////////////////////////////////////////////////////////
+//
+// Integer operate instructions
+//
+
+//Outputs to decoder.hh
+output header {{
+
+ class Control : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ Control(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ class CP0Control : public Control
+ {
+ protected:
+
+ /// Constructor
+ CP0Control(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ Control(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ class CP1Control : public Control
+ {
+ protected:
+
+ /// Constructor
+ CP1Control(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ Control(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+}};
+
+//Outputs to decoder.cc
+output decoder {{
+ std::string Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ if (mnemonic == "mfc0" || mnemonic == "mtc0") {
+ ccprintf(ss, "%-10s %d,%d,%d", mnemonic,RT,RD,SEL);
+ } else {
+
+ // just print the first dest... if there's a second one,
+ // it's generally implicit
+ if (_numDestRegs > 0) {
+ printReg(ss, _destRegIdx[0]);
+ }
+
+ ss << ", ";
+
+ // just print the first two source regs... if there's
+ // a third one, it's a read-modify-write dest (Rc),
+ // e.g. for CMOVxx
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ if (_numSrcRegs > 1) {
+ ss << ", ";
+ printReg(ss, _srcRegIdx[1]);
+ }
+ }
+
+ return ss.str();
+ }
+
+ std::string CP0Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+ ccprintf(ss, "%-10s r%d, r%d, %d", mnemonic, RT, RD, SEL);
+ return ss.str();
+ }
+
+ std::string CP1Control::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+ ccprintf(ss, "%-10s r%d, f%d", mnemonic, RT, FS);
+ return ss.str();
+ }
+
+}};
+
+def format System(code, *flags) {{
+ iop = InstObjParams(name, Name, 'Control', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format CP0Control(code, *flags) {{
+ iop = InstObjParams(name, Name, 'CP0Control', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format CP1Control(code, *flags) {{
+ iop = InstObjParams(name, Name, 'CP1Control', CodeBlock(code), flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+
diff --git a/src/arch/mips/isa/formats/formats.isa b/src/arch/mips/isa/formats/formats.isa
index 7d493ffae..4c3eec132 100644
--- a/src/arch/mips/isa/formats/formats.isa
+++ b/src/arch/mips/isa/formats/formats.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2003-2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
//Templates from this format are used later
//Include the basic format
##include "basic.isa"
@@ -10,8 +38,8 @@
//Include utility functions
##include "util.isa"
-//Include the cop0 formats
-##include "cop0.isa"
+//Include the control/cp0/cp1 formats
+##include "control.isa"
//Include the integer formats
##include "int.isa"
@@ -22,6 +50,9 @@
//Include the mem format
##include "mem.isa"
+//Include the mem format
+##include "mt.isa"
+
//Include the trap format
##include "trap.isa"
diff --git a/src/arch/mips/isa/formats/fp.isa b/src/arch/mips/isa/formats/fp.isa
index 9f2c24755..1e5d62626 100644
--- a/src/arch/mips/isa/formats/fp.isa
+++ b/src/arch/mips/isa/formats/fp.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Floating Point operate instructions
@@ -18,49 +46,264 @@ output header {{
{
}
- std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ //std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
+ //needs function to check for fpEnable or not
+ };
+
+ class FPCompareOp : public FPOp
+ {
+ protected:
+ FPCompareOp(const char *mnem, MachInst _machInst, OpClass __opClass) : FPOp(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+
};
}};
output decoder {{
- std::string FPOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ std::string FPCompareOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
- return "Disassembly of integer instruction\n";
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ ccprintf(ss,"%d",CC);
+
+ if(_numSrcRegs > 0) {
+ ss << ", ";
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ if(_numSrcRegs > 1) {
+ ss << ", ";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ return ss.str();
}
}};
+output exec {{
-// Primary format for float operate instructions:
-def format FloatOp(code, *flags) {{
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
+ //If any operand is Nan return the appropriate QNaN
+ template <class T>
+ bool
+ fpNanOperands(FPOp *inst, %(CPU_exec_context)s *xc, const T &src_type,
+ Trace::InstRecord *traceData)
+ {
+ uint64_t mips_nan = 0;
+ T src_op = 0;
+ int size = sizeof(src_op) * 8;
+
+ for (int i = 0; i < inst->numSrcRegs(); i++) {
+ uint64_t src_bits = xc->readFloatRegBits(inst, 0, size);
+
+ if (isNan(&src_bits, size) ) {
+ if (isSnan(&src_bits, size)) {
+ switch (size)
+ {
+ case 32: mips_nan = MIPS32_QNAN; break;
+ case 64: mips_nan = MIPS64_QNAN; break;
+ default: panic("Unsupported Floating Point Size (%d)", size);
+ }
+ } else {
+ mips_nan = src_bits;
+ }
+
+ xc->setFloatRegBits(inst, 0, mips_nan, size);
+ if (traceData) { traceData->setData(mips_nan); }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ template <class T>
+ bool
+ fpInvalidOp(FPOp *inst, %(CPU_exec_context)s *cpu, const T dest_val,
+ Trace::InstRecord *traceData)
+ {
+ uint64_t mips_nan = 0;
+ T src_op = dest_val;
+ int size = sizeof(src_op) * 8;
+
+ if (isNan(&src_op, size)) {
+ switch (size)
+ {
+ case 32: mips_nan = MIPS32_QNAN; break;
+ case 64: mips_nan = MIPS64_QNAN; break;
+ default: panic("Unsupported Floating Point Size (%d)", size);
+ }
+
+ //Set value to QNAN
+ cpu->setFloatRegBits(inst, 0, mips_nan, size);
+
+ //Read FCSR from FloatRegFile
+ uint32_t fcsr_bits = cpu->tc->readFloatRegBits(FCSR);
+
+ //Write FCSR from FloatRegFile
+ cpu->tc->setFloatRegBits(FCSR, genInvalidVector(fcsr_bits));
+
+ if (traceData) { traceData->setData(mips_nan); }
+ return true;
+ }
+
+ return false;
+ }
+
+ void
+ fpResetCauseBits(%(CPU_exec_context)s *cpu)
+ {
+ //Read FCSR from FloatRegFile
+ uint32_t fcsr = cpu->tc->readFloatRegBits(FCSR);
+
+ fcsr = bits(fcsr, 31, 18) << 18 | bits(fcsr, 11, 0);
+
+ //Write FCSR from FloatRegFile
+ cpu->tc->setFloatRegBits(FCSR, fcsr);
+ }
}};
-def format FloatCompareOp(code, *flags) {{
- code = 'bool cond;\n' + code
- code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
+def template FloatingPointExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+
+ //When is the right time to reset cause bits?
+ //start of every instruction or every cycle?
+ fpResetCauseBits(xc);
+
+ %(op_decl)s;
+ %(op_rd)s;
+
+ //Check if any FP operand is a NaN value
+ if (!fpNanOperands((FPOp*)this, xc, Fd, traceData)) {
+ %(code)s;
+
+ //Change this code for Full-System/Sycall Emulation
+ //separation
+ //----
+ //Should Full System-Mode throw a fault here?
+ //----
+ //Check for IEEE 754 FP Exceptions
+ //fault = fpNanOperands((FPOp*)this, xc, Fd, traceData);
+ if (!fpInvalidOp((FPOp*)this, xc, Fd, traceData) &&
+ fault == NoFault)
+ {
+ %(op_wb)s;
+ }
+ }
+
+ return fault;
+ }
}};
-def format FloatCompareWithXcptOp(code, *flags) {{
- code = 'bool cond;\n' + code
- code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+// Primary format for float point operate instructions:
+def format FloatOp(code, *flags) {{
+ iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code), flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
+ exec_output = FloatingPointExecute.subst(iop)
+}};
+
+def format FloatCompareOp(cond_code, *flags) {{
+ import sys
+
+ code = 'bool cond;\n'
+ if '.sf' in cond_code or 'SinglePrecision' in flags:
+ if 'QnanException' in flags:
+ code += 'if (isQnan(&Fs.sf, 32) || isQnan(&Ft.sf, 32)) {\n'
+ code += '\tFCSR = genInvalidVector(FCSR);\n'
+ code += '\treturn NoFault;'
+ code += '}\n else '
+ code += 'if (isNan(&Fs.sf, 32) || isNan(&Ft.sf, 32)) {\n'
+ elif '.df' in cond_code or 'DoublePrecision' in flags:
+ if 'QnanException' in flags:
+ code += 'if (isQnan(&Fs.df, 64) || isQnan(&Ft.df, 64)) {\n'
+ code += '\tFCSR = genInvalidVector(FCSR);\n'
+ code += '\treturn NoFault;'
+ code += '}\n else '
+ code += 'if (isNan(&Fs.df, 64) || isNan(&Ft.df, 64)) {\n'
+ else:
+ sys.exit('Decoder Failed: Can\'t Determine Operand Type\n')
+
+ if 'UnorderedTrue' in flags:
+ code += 'cond = 1;\n'
+ elif 'UnorderedFalse' in flags:
+ code += 'cond = 0;\n'
+ else:
+ sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
+
+ code += '} else {\n'
+ code += cond_code + '}'
+ code += 'FCSR = genCCVector(FCSR, CC, cond);\n'
+
+ iop = InstObjParams(name, Name, 'FPCompareOp', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
}};
def format FloatConvertOp(code, *flags) {{
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
+ import sys
+
+ #Determine Source Type
+ convert = 'fpConvert('
+ if '.sf' in code:
+ code = 'float ' + code + '\n'
+ convert += 'SINGLE_TO_'
+ elif '.df' in code:
+ code = 'double ' + code + '\n'
+ convert += 'DOUBLE_TO_'
+ elif '.uw' in code:
+ code = 'uint32_t ' + code + '\n'
+ convert += 'WORD_TO_'
+ elif '.ud' in code:
+ code = 'uint64_t ' + code + '\n'
+ convert += 'LONG_TO_'
+ else:
+ sys.exit("Error Determining Source Type for Conversion")
+
+ #Determine Destination Type
+ if 'ToSingle' in flags:
+ code += 'Fd.uw = ' + convert + 'SINGLE, '
+ elif 'ToDouble' in flags:
+ code += 'Fd.ud = ' + convert + 'DOUBLE, '
+ elif 'ToWord' in flags:
+ code += 'Fd.uw = ' + convert + 'WORD, '
+ elif 'ToLong' in flags:
+ code += 'Fd.ud = ' + convert + 'LONG, '
+ else:
+ sys.exit("Error Determining Destination Type for Conversion")
+
+ #Figure out how to round value
+ if 'Ceil' in flags:
+ code += 'ceil(val)); '
+ elif 'Floor' in flags:
+ code += 'floor(val)); '
+ elif 'Round' in flags:
+ code += 'roundFP(val, 0)); '
+ elif 'Trunc' in flags:
+ code += 'truncFP(val));'
+ else:
+ code += 'val); '
+
+ iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format FloatAccOp(code, *flags) {{
+ iop = InstObjParams(name, Name, 'FPOp', CodeBlock(code), flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
decode_block = BasicDecode.subst(iop)
@@ -76,34 +319,51 @@ def format Float64Op(code, *flags) {{
exec_output = BasicExecute.subst(iop)
}};
-def format Float64ConvertOp(code, *flags) {{
- code = 'bool cond;\n' + code
- code += 'FCSR = makeCCVector(FCSR, CC,cond);\n'
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
-}};
+def format FloatPSCompareOp(cond_code1, cond_code2, *flags) {{
+ import sys
-def format FloatPSCompareOp(code, *flags) {{
- code = 'bool cond1;\nbool cond2;\n' + code
- code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n'
- code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n'
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
-}};
+ code = 'bool cond1, cond2;\n'
+ code += 'bool code_block1, code_block2;\n'
+ code += 'code_block1 = code_block2 = true;\n'
-def format FloatPSCompareWithXcptOp(code, *flags) {{
- code = 'bool cond1;\nbool cond2;\n' + code
- code += 'FCSR = makeCCVector(FCSR, CC+1, cond1);\n'
- code += 'FCSR = makeCCVector(FCSR, CC, cond2);\n'
- iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
+ if 'QnanException' in flags:
+ code += 'if (isQnan(&Fs1.sf, 32) || isQnan(&Ft1.sf, 32)) {\n'
+ code += '\tFCSR = genInvalidVector(FCSR);\n'
+ code += 'code_block1 = false;'
+ code += '}\n'
+ code += 'if (isQnan(&Fs2.sf, 32) || isQnan(&Ft2.sf, 32)) {\n'
+ code += '\tFCSR = genInvalidVector(FCSR);\n'
+ code += 'code_block2 = false;'
+ code += '}\n'
+
+ code += 'if (code_block1) {'
+ code += '\tif (isNan(&Fs1.sf, 32) || isNan(&Ft1.sf, 32)) {\n'
+ if 'UnorderedTrue' in flags:
+ code += 'cond1 = 1;\n'
+ elif 'UnorderedFalse' in flags:
+ code += 'cond1 = 0;\n'
+ else:
+ sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
+ code += '} else {\n'
+ code += cond_code1
+ code += 'FCSR = genCCVector(FCSR, CC, cond1);}\n}\n'
+
+ code += 'if (code_block2) {'
+ code += '\tif (isNan(&Fs2.sf, 32) || isNan(&Ft2.sf, 32)) {\n'
+ if 'UnorderedTrue' in flags:
+ code += 'cond2 = 1;\n'
+ elif 'UnorderedFalse' in flags:
+ code += 'cond2 = 0;\n'
+ else:
+ sys.exit('Decoder Failed: Float Compare Instruction Needs A Unordered Flag\n')
+ code += '} else {\n'
+ code += cond_code2
+ code += 'FCSR = genCCVector(FCSR, CC, cond2);}\n}'
+
+ iop = InstObjParams(name, Name, 'FPCompareOp', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
}};
+
diff --git a/src/arch/mips/isa/formats/int.isa b/src/arch/mips/isa/formats/int.isa
index 7d38b9ff5..56a4ec204 100644
--- a/src/arch/mips/isa/formats/int.isa
+++ b/src/arch/mips/isa/formats/int.isa
@@ -1,11 +1,37 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Integer operate instructions
//
-
-//Outputs to decoder.hh
output header {{
#include <iostream>
using namespace std;
@@ -25,6 +51,34 @@ output header {{
std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
};
+
+ class HiLoOp: public IntOp
+ {
+ protected:
+
+ /// Constructor
+ HiLoOp(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ IntOp(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+ class HiLoMiscOp: public HiLoOp
+ {
+ protected:
+
+ /// Constructor
+ HiLoMiscOp(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ HiLoOp(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+
+
class IntImmOp : public MipsStaticInst
{
protected:
@@ -52,6 +106,33 @@ output header {{
}};
+// HiLo<Misc> instruction class execute method template.
+// Mainly to get instruction trace data to print out
+// correctly
+def template HiLoExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(code)s;
+
+ if(fault == NoFault)
+ {
+ %(op_wb)s;
+ //If there are 2 Destination Registers then
+ //concatenate the values for the traceData
+ if(traceData && _numDestRegs == 2) {
+ uint64_t hilo_final_val = (uint64_t)HI << 32 | LO;
+ traceData->setData(hilo_final_val);
+ }
+ }
+ return fault;
+ }
+}};
+
//Outputs to decoder.cc
output decoder {{
std::string IntOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
@@ -64,7 +145,7 @@ output decoder {{
// it's generally implicit
if (_numDestRegs > 0) {
printReg(ss, _destRegIdx[0]);
- ss << ",";
+ ss << ", ";
}
// just print the first two source regs... if there's
@@ -75,13 +156,47 @@ output decoder {{
}
if (_numSrcRegs > 1) {
- ss << ",";
+ ss << ", ";
+ printReg(ss, _srcRegIdx[1]);
+ }
+
+ return ss.str();
+ }
+
+ std::string HiLoOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ //Destination Registers are implicit for HI/LO ops
+ if (_numSrcRegs > 0) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ if (_numSrcRegs > 1) {
+ ss << ", ";
printReg(ss, _srcRegIdx[1]);
}
return ss.str();
}
+ std::string HiLoMiscOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ std::stringstream ss;
+
+ ccprintf(ss, "%-10s ", mnemonic);
+
+ if (_numDestRegs > 0 && _destRegIdx[0] < 32) {
+ printReg(ss, _destRegIdx[0]);
+ } else if (_numSrcRegs > 0 && _srcRegIdx[0] < 32) {
+ printReg(ss, _srcRegIdx[0]);
+ }
+
+ return ss.str();
+ }
+
std::string IntImmOp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
std::stringstream ss;
@@ -92,15 +207,15 @@ output decoder {{
printReg(ss, _destRegIdx[0]);
}
- ss << ",";
+ ss << ", ";
if (_numSrcRegs > 0) {
printReg(ss, _srcRegIdx[0]);
- ss << ",";
+ ss << ", ";
}
if( mnemonic == "lui")
- ccprintf(ss, "%08p ", sextImm);
+ ccprintf(ss, "0x%x ", sextImm);
else
ss << (int) sextImm;
@@ -109,23 +224,47 @@ output decoder {{
}};
-//Used by decoder.isa
def format IntOp(code, *opt_flags) {{
- orig_code = code
- cblk = CodeBlock(code)
-
- # Figure out if we are creating a IntImmOp or a IntOp
- # by looking at the instruction name
- iop = InstObjParams(name, Name, 'IntOp', cblk, opt_flags)
- strlen = len(name)
- if name[strlen-1] == 'i' or name[strlen-2:] == 'iu':
- iop = InstObjParams(name, Name, 'IntImmOp', cblk, opt_flags)
-
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = OperateNopCheckDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
+ iop = InstObjParams(name, Name, 'IntOp', CodeBlock(code), opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = RegNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format IntImmOp(code, *opt_flags) {{
+ iop = InstObjParams(name, Name, 'IntImmOp', CodeBlock(code), opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = ImmNopCheckDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
+
+def format HiLoOp(code, *opt_flags) {{
+ if '.sd' in code:
+ code = 'int64_t ' + code
+ elif '.ud' in code:
+ code = 'uint64_t ' + code
+
+ code += 'HI = val<63:32>;\n'
+ code += 'LO = val<31:0>;\n'
+
+ iop = InstObjParams(name, Name, 'HiLoOp', CodeBlock(code), opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = HiLoExecute.subst(iop)
}};
+def format HiLoMiscOp(code, *opt_flags) {{
+ iop = InstObjParams(name, Name, 'HiLoMiscOp', CodeBlock(code), opt_flags)
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = HiLoExecute.subst(iop)
+}};
+
+
+
diff --git a/src/arch/mips/isa/formats/mem.isa b/src/arch/mips/isa/formats/mem.isa
index e2afc7252..f03f7becd 100644
--- a/src/arch/mips/isa/formats/mem.isa
+++ b/src/arch/mips/isa/formats/mem.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// Copyright (c) 2006 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -25,6 +25,14 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Memory-format instructions
+//
output header {{
/**
@@ -50,14 +58,8 @@ output header {{
StaticInstPtr _memAccPtr = nullStaticInstPtr)
: MipsStaticInst(mnem, _machInst, __opClass),
memAccessFlags(0), eaCompPtr(_eaCompPtr), memAccPtr(_memAccPtr),
- disp(OFFSET)
+ disp(sext<16>(OFFSET))
{
- //If Bit 15 is 1 then Sign Extend
- int32_t temp = disp & 0x00008000;
-
- if (temp > 0) {
- disp |= 0xFFFF0000;
- }
}
std::string
@@ -69,6 +71,24 @@ output header {{
const StaticInstPtr &memAccInst() const { return memAccPtr; }
};
+ /**
+ * Base class for a few miscellaneous memory-format insts
+ * that don't interpret the disp field
+ */
+ class MemoryNoDisp : public Memory
+ {
+ protected:
+ /// Constructor
+ MemoryNoDisp(const char *mnem, ExtMachInst _machInst, OpClass __opClass,
+ StaticInstPtr _eaCompPtr = nullStaticInstPtr,
+ StaticInstPtr _memAccPtr = nullStaticInstPtr)
+ : Memory(mnem, _machInst, __opClass, _eaCompPtr, _memAccPtr)
+ {
+ }
+
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
}};
@@ -76,21 +96,20 @@ output decoder {{
std::string
Memory::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
- return csprintf("%-10s %c%d,%d(r%d)", mnemonic,
+ return csprintf("%-10s %c%d, %d(r%d)", mnemonic,
flags[IsFloating] ? 'f' : 'r', RT, disp, RS);
}
+ std::string
+ MemoryNoDisp::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return csprintf("%-10s %c%d, r%d(r%d)", mnemonic,
+ flags[IsFloating] ? 'f' : 'r',
+ flags[IsFloating] ? FD : RD,
+ RS, RT);
+ }
}};
-def format LoadAddress(code) {{
- iop = InstObjParams(name, Name, 'MemoryDisp32', CodeBlock(code))
- header_output = BasicDeclare.subst(iop)
- decoder_output = BasicConstructor.subst(iop)
- decode_block = BasicDecode.subst(iop)
- exec_output = BasicExecute.subst(iop)
-}};
-
-
def template LoadStoreDeclare {{
/**
* Static instruction class for "%(mnemonic)s".
@@ -418,27 +437,76 @@ def template StoreCompleteAcc {{
}
}};
-// load instructions use Rt as dest, so check for
-// Rt == 31 to detect nops
-def template LoadNopCheckDecode {{
- {
- MipsStaticInst *i = new %(class_name)s(machInst);
- if (RT == 0) {
- i = makeNop(i);
- }
- return i;
- }
+
+def template MiscMemAccExecute {{
+ Fault %(class_name)s::MemAcc::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ EA = xc->getEA();
+
+ if (fault == NoFault) {
+ %(code)s;
+ }
+
+ return NoFault;
+ }
+}};
+
+def template MiscExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Addr EA;
+ Fault fault = NoFault;
+
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ if (fault == NoFault) {
+ %(memacc_code)s;
+ }
+
+ return NoFault;
+ }
+}};
+
+def template MiscInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("Misc instruction does not support split access method!");
+ return NoFault;
+ }
+}};
+
+
+def template MiscCompleteAcc {{
+ Fault %(class_name)s::completeAcc(uint8_t *data,
+ %(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ panic("Misc instruction does not support split access method!");
+
+ return NoFault;
+ }
}};
def format LoadMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
- decode_template = LoadNopCheckDecode,
+ decode_template = ImmNopCheckDecode,
exec_template_base = 'Load')
}};
-
def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
@@ -446,26 +514,69 @@ def format StoreMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
exec_template_base = 'Store')
}};
-//FP loads are offloaded to these formats for now ...
-def format LoadFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+def format LoadIndexedMemory(memacc_code, ea_code = {{ EA = Rs + Rt; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
- decode_template = BasicDecode,
+ decode_template = ImmNopCheckDecode,
exec_template_base = 'Load')
}};
+def format StoreIndexedMemory(memacc_code, ea_code = {{ EA = Rs + Rt; }},
+ mem_flags = [], inst_flags = []) {{
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ exec_template_base = 'Store')
+}};
+
+def format LoadUnalignedMemory(memacc_code, ea_code = {{ EA = (Rs + disp) & ~3; }},
+ mem_flags = [], inst_flags = []) {{
+ decl_code = 'uint32_t mem_word = Mem.uw;\n'
+ decl_code += 'uint32_t unalign_addr = Rs + disp;\n'
+ decl_code += 'uint32_t byte_offset = unalign_addr & 3;\n'
+ decl_code += '#if BYTE_ORDER == BIG_ENDIAN\n'
+ decl_code += '\tbyte_offset ^= 3;\n'
+ decl_code += '#endif\n'
+
+ memacc_code = decl_code + memacc_code
+
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ decode_template = ImmNopCheckDecode,
+ exec_template_base = 'Load')
+}};
-def format StoreFloatMemory(memacc_code, ea_code = {{ EA = Rs + disp; }},
+def format StoreUnalignedMemory(memacc_code, ea_code = {{ EA = (Rs + disp) & ~3; }},
mem_flags = [], inst_flags = []) {{
+ decl_code = 'uint32_t mem_word = 0;\n'
+ decl_code += 'uint32_t unaligned_addr = Rs + disp;\n'
+ decl_code += 'uint32_t byte_offset = unaligned_addr & 3;\n'
+ decl_code += '#if BYTE_ORDER == BIG_ENDIAN\n'
+ decl_code += '\tbyte_offset ^= 3;\n'
+ decl_code += '#endif\n'
+ decl_code += 'fault = xc->read(EA, (uint32_t&)mem_word, memAccessFlags);\n'
+ memacc_code = decl_code + memacc_code + '\nMem = mem_word;\n'
+
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
exec_template_base = 'Store')
}};
+def format Prefetch(ea_code = {{ EA = Rs + disp; }},
+ mem_flags = [], pf_flags = [], inst_flags = []) {{
+ pf_mem_flags = mem_flags + pf_flags + ['NO_FAULT']
+ pf_inst_flags = inst_flags + ['IsMemRef', 'IsLoad',
+ 'IsDataPrefetch', 'MemReadOp']
+
+ (header_output, decoder_output, decode_block, exec_output) = \
+ LoadStoreBase(name, Name, ea_code,
+ 'xc->prefetch(EA, memAccessFlags);',
+ pf_mem_flags, pf_inst_flags, exec_template_base = 'Misc')
+
+}};
-def format UnalignedStore(memacc_code, postacc_code,
- ea_code = {{ EA = Rb + disp; }},
+def format StoreCond(memacc_code, postacc_code,
+ ea_code = {{ EA = Rs + disp; }},
mem_flags = [], inst_flags = []) {{
(header_output, decoder_output, decode_block, exec_output) = \
LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
diff --git a/src/arch/mips/isa/formats/mt.isa b/src/arch/mips/isa/formats/mt.isa
new file mode 100644
index 000000000..96435f8c9
--- /dev/null
+++ b/src/arch/mips/isa/formats/mt.isa
@@ -0,0 +1,82 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
+////////////////////////////////////////////////////////////////////
+//
+// MT instructions
+//
+
+output header {{
+ /**
+ * Base class for MIPS MT ASE operations.
+ */
+ class MT : public MipsStaticInst
+ {
+ protected:
+
+ /// Constructor
+ MT(const char *mnem, MachInst _machInst, OpClass __opClass) :
+ MipsStaticInst(mnem, _machInst, __opClass)
+ {
+ }
+
+ std::string generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+
+output decoder {{
+ //Edit This Template When MT is Implemented
+ std::string MT::generateDisassembly(Addr pc, const SymbolTable *symtab) const
+ {
+ return "Disassembly of MT instruction\n";
+ }
+}};
+
+def template MTExecute {{
+ //Edit This Template When MT is Implemented
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
+ {
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+
+ //Call into the trap handler with the appropriate fault
+ return No_Fault;
+ }
+}};
+
+// Primary format for integer operate instructions:
+def format MipsMT() {{
+ code = 'panic(\"Mips MT Is Currently Unimplemented.\");\n'
+ iop = InstObjParams(name, Name, 'MT', CodeBlock(code))
+ header_output = BasicDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ exec_output = BasicExecute.subst(iop)
+}};
diff --git a/src/arch/mips/isa/formats/noop.isa b/src/arch/mips/isa/formats/noop.isa
index 2aa4816e3..7f3d313ad 100644
--- a/src/arch/mips/isa/formats/noop.isa
+++ b/src/arch/mips/isa/formats/noop.isa
@@ -1,5 +1,33 @@
// -*- mode:c++ -*-
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Nop
@@ -36,11 +64,7 @@ output decoder {{
std::string Nop::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
-#ifdef SS_COMPATIBLE_DISASSEMBLY
- return originalDisassembly;
-#else
- return csprintf("%-10s (%s)", "nop", originalDisassembly);
-#endif
+ return csprintf("%-10s %s", "nop", originalDisassembly);
}
/// Helper function for decoding nops. Substitute Nop object
@@ -49,7 +73,8 @@ output decoder {{
MipsStaticInst *
makeNop(MipsStaticInst *inst)
{
- MipsStaticInst *nop = new Nop(inst->disassemble(0), inst->machInst);
+ std::string nop_str = "(" + inst->disassemble(0) + ")";
+ MipsStaticInst *nop = new Nop(nop_str, inst->machInst);
delete inst;
return nop;
}
@@ -63,16 +88,36 @@ output exec {{
}
}};
-// integer & FP operate instructions use RT as dest, so check for
-// RT == 0 to detect nops
-def template OperateNopCheckDecode {{
+// Int & FP operate instructions use RD as dest, so check for
+// RD == 0 to detect nops
+def template RegNopCheckDecode {{
{
MipsStaticInst *i = new %(class_name)s(machInst);
+ //if (RD == 0) {
+ //i = makeNop(i);
+ //}
+ return i;
+ }
+}};
+def template OperateNopCheckDecode {{
+ {
+ MipsStaticInst *i = new %(class_name)s(machInst);
//if (RD == 0) {
- // i = makeNop(i);
+ // i = makeNop(i);
//}
+ return i;
+ }
+}};
+// IntImm & Memory instructions use Rt as dest, so check for
+// Rt == 0 to detect nops
+def template ImmNopCheckDecode {{
+ {
+ MipsStaticInst *i = new %(class_name)s(machInst);
+ //if (RT == 0) {
+ // i = makeNop(i);
+ // }
return i;
}
}};
@@ -89,6 +134,6 @@ def format BasicOperateWithNopCheck(code, *opt_args) {{
}};
def format Nop() {{
- decode_block = 'return new Nop(\"sll r0,r0,0\",machInst);\n'
+ decode_block = 'return new Nop(\"\",machInst);\n'
}};
diff --git a/src/arch/mips/isa/formats/tlbop.isa b/src/arch/mips/isa/formats/tlbop.isa
index f5e4076f2..b974ccbed 100644
--- a/src/arch/mips/isa/formats/tlbop.isa
+++ b/src/arch/mips/isa/formats/tlbop.isa
@@ -1,3 +1,33 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// TlbOp instructions
@@ -30,13 +60,10 @@ output decoder {{
def template TlbOpExecute {{
Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
{
- //Call into the trap handler with the appropriate fault
- return No_Fault;
- }
-
//Write the resulting state to the execution context
%(op_wb)s;
+ //Call into the trap handler with the appropriate fault
return No_Fault;
}
}};
diff --git a/src/arch/mips/isa/formats/trap.isa b/src/arch/mips/isa/formats/trap.isa
index 6884d4fa8..b9066f374 100644
--- a/src/arch/mips/isa/formats/trap.isa
+++ b/src/arch/mips/isa/formats/trap.isa
@@ -1,3 +1,33 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Trap instructions
@@ -23,27 +53,26 @@ output header {{
output decoder {{
std::string Trap::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
- return "Disassembly of integer instruction\n";
+ return "Disassembly of trap instruction\n";
}
}};
def template TrapExecute {{
+ //Edit This Template When Traps Are Implemented
Fault %(class_name)s::execute(%(CPU_exec_context)s *xc, Trace::InstRecord *traceData) const
{
- //Call into the trap handler with the appropriate fault
- return No_Fault;
- }
-
//Write the resulting state to the execution context
%(op_wb)s;
+ //Call into the trap handler with the appropriate fault
return No_Fault;
}
}};
-// Primary format for integer operate instructions:
def format Trap(code, *flags) {{
- code = 'bool cond;\n' + code;
+ code = 'warn(\"'
+ code += 'Trap Exception Handler Is Currently Not Implemented.'
+ code += '\");'
iop = InstObjParams(name, Name, 'MipsStaticInst', CodeBlock(code), flags)
header_output = BasicDeclare.subst(iop)
decoder_output = BasicConstructor.subst(iop)
diff --git a/src/arch/mips/isa/formats/unimp.isa b/src/arch/mips/isa/formats/unimp.isa
index 475a88752..03068fa74 100644
--- a/src/arch/mips/isa/formats/unimp.isa
+++ b/src/arch/mips/isa/formats/unimp.isa
@@ -1,6 +1,7 @@
// -*- mode:c++ -*-
-// Copyright (c) 2003-2005 The Regents of The University of Michigan
+
+// Copyright (c) 2006 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -25,6 +26,13 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// Unimplemented instructions
+//
output header {{
/**
@@ -96,11 +104,7 @@ output decoder {{
WarnUnimplemented::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
{
-#ifdef SS_COMPATIBLE_DISASSEMBLY
- return csprintf("%-10s", mnemonic);
-#else
return csprintf("%-10s (unimplemented)", mnemonic);
-#endif
}
}};
@@ -120,7 +124,7 @@ output exec {{
Trace::InstRecord *traceData) const
{
if (!warned) {
- warn("instruction '%s' unimplemented\n", mnemonic);
+ warn("\tinstruction '%s' unimplemented\n", mnemonic);
warned = true;
}
@@ -139,28 +143,3 @@ def format WarnUnimpl() {{
decode_block = BasicDecodeWithMnemonic.subst(iop)
}};
-output header {{
- /**
- * Static instruction class for unknown (illegal) instructions.
- * These cause simulator termination if they are executed in a
- * non-speculative mode. This is a leaf class.
- */
- class Unknown : public MipsStaticInst
- {
- public:
- /// Constructor
- Unknown(MachInst _machInst)
- : MipsStaticInst("unknown", _machInst, No_OpClass)
- {
- // don't call execute() (which panics) if we're on a
- // speculative path
- flags[IsNonSpeculative] = true;
- }
-
- %(BasicExecDeclare)s
-
- std::string
- generateDisassembly(Addr pc, const SymbolTable *symtab) const;
- };
-}};
-
diff --git a/src/arch/mips/isa/formats/unknown.isa b/src/arch/mips/isa/formats/unknown.isa
index ba83c007e..70b3901e9 100644
--- a/src/arch/mips/isa/formats/unknown.isa
+++ b/src/arch/mips/isa/formats/unknown.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// Copyright (c) 2006 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -25,30 +25,40 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
-output header {{
- std::string inst2string(MachInst machInst);
-}};
-output decoder {{
-
-std::string inst2string(MachInst machInst)
-{
- string str = "";
- uint32_t mask = 0x80000000;
+////////////////////////////////////////////////////////////////////
+//
+// Unknown instructions
+//
- for(int i=0; i < 32; i++) {
- if ((machInst & mask) == 0) {
- str += "0";
- } else {
- str += "1";
+output header {{
+ /**
+ * Static instruction class for unknown (illegal) instructions.
+ * These cause simulator termination if they are executed in a
+ * non-speculative mode. This is a leaf class.
+ */
+ class Unknown : public MipsStaticInst
+ {
+ public:
+ /// Constructor
+ Unknown(MachInst _machInst)
+ : MipsStaticInst("unknown", _machInst, No_OpClass)
+ {
+ // don't call execute() (which panics) if we're on a
+ // speculative path
+ flags[IsNonSpeculative] = true;
}
- mask = mask >> 1;
- }
+ %(BasicExecDeclare)s
- return str;
-}
+ std::string
+ generateDisassembly(Addr pc, const SymbolTable *symtab) const;
+ };
+}};
+output decoder {{
std::string
Unknown::generateDisassembly(Addr pc, const SymbolTable *symtab) const
{
diff --git a/src/arch/mips/isa/formats/util.isa b/src/arch/mips/isa/formats/util.isa
index 615160931..0cc375af3 100644
--- a/src/arch/mips/isa/formats/util.isa
+++ b/src/arch/mips/isa/formats/util.isa
@@ -1,5 +1,34 @@
// -*- mode:c++ -*-
+// 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: Steve Reinhardt
+// Korey Sewell
+
let {{
def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
postacc_code = '', base_class = 'Memory',
@@ -90,7 +119,31 @@ def LoadStoreBase(name, Name, ea_code, memacc_code, mem_flags, inst_flags,
+ completeAccTemplate.subst(completeacc_iop))
}};
+output header {{
+ std::string inst2string(MachInst machInst);
+}};
+
+output decoder {{
+
+std::string inst2string(MachInst machInst)
+{
+ string str = "";
+ uint32_t mask = 0x80000000;
+
+ for(int i=0; i < 32; i++) {
+ if ((machInst & mask) == 0) {
+ str += "0";
+ } else {
+ str += "1";
+ }
+ mask = mask >> 1;
+ }
+
+ return str;
+}
+
+}};
output exec {{
using namespace MipsISA;
@@ -124,6 +177,7 @@ output exec {{
#endif
+
}};
diff --git a/src/arch/mips/isa/includes.isa b/src/arch/mips/isa/includes.isa
index 9c370fbe3..6b5f3c588 100644
--- a/src/arch/mips/isa/includes.isa
+++ b/src/arch/mips/isa/includes.isa
@@ -1,3 +1,33 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
////////////////////////////////////////////////////////////////////
//
// Output include file directives.
@@ -16,9 +46,10 @@ output decoder {{
#include "arch/mips/isa_traits.hh"
#include "base/cprintf.hh"
#include "base/loader/symtab.hh"
-#include "cpu/exec_context.hh" // for Jump::branchTarget()
+#include "cpu/thread_context.hh"
#include "arch/mips/faults.hh"
#include "arch/mips/isa_traits.hh"
+#include "arch/mips/utility.hh"
#include <math.h>
#if defined(linux)
@@ -31,6 +62,8 @@ using namespace MipsISA;
output exec {{
#include "arch/mips/faults.hh"
#include "arch/mips/isa_traits.hh"
+#include "arch/mips/utility.hh"
+
#include <math.h>
#if defined(linux)
#include <fenv.h>
diff --git a/src/arch/mips/isa/main.isa b/src/arch/mips/isa/main.isa
index 01d81323e..2d7c63cd5 100644
--- a/src/arch/mips/isa/main.isa
+++ b/src/arch/mips/isa/main.isa
@@ -1,6 +1,6 @@
// -*- mode:c++ -*-
-// Copyright (c) 2003-2005 The Regents of The University of Michigan
+// Copyright (c) 2006 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@@ -25,7 +25,16 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// MIPS ISA description file.
+//
+////////////////////////////////////////////////////////////////////
+//Include the C++ include directives
##include "includes.isa"
////////////////////////////////////////////////////////////////////
diff --git a/src/arch/mips/isa/operands.isa b/src/arch/mips/isa/operands.isa
index 0f9c74b48..3843dc053 100644
--- a/src/arch/mips/isa/operands.isa
+++ b/src/arch/mips/isa/operands.isa
@@ -1,3 +1,33 @@
+// -*- mode:c++ -*-
+
+// Copyright (c) 2006 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Korey Sewell
+
def operand_types {{
'sb' : ('signed int', 8),
'ub' : ('unsigned int', 8),
@@ -23,8 +53,8 @@ def operands {{
'R2': ('IntReg', 'uw','2', 'IsInteger', 5),
#Special Integer Reg operands
- 'HI': ('IntReg', 'uw','32', 'IsInteger', 6),
- 'LO': ('IntReg', 'uw','33', 'IsInteger', 7),
+ 'HI': ('IntReg', 'uw','MipsISA::HI', 'IsInteger', 6),
+ 'LO': ('IntReg', 'uw','MipsISA::LO', 'IsInteger', 7),
#Immediate Value operand
'IntImm': ('IntReg', 'uw', 'INTIMM', 'IsInteger', 3),
@@ -36,11 +66,11 @@ def operands {{
'Fr': ('FloatReg', 'sf', 'FR', 'IsFloating', 3),
#Special Floating Point Control Reg Operands
- 'FIR': ('FloatReg', 'uw', '32', 'IsFloating', 1),
- 'FCCR': ('FloatReg', 'uw', '33', 'IsFloating', 2),
- 'FEXR': ('FloatReg', 'uw', '34', 'IsFloating', 3),
- 'FENR': ('FloatReg', 'uw', '35', 'IsFloating', 3),
- 'FCSR': ('FloatReg', 'uw', '36', 'IsFloating', 3),
+ 'FIR': ('FloatReg', 'uw', 'MipsISA::FIR', 'IsFloating', 1),
+ 'FCCR': ('FloatReg', 'uw', 'MipsISA::FCCR', 'IsFloating', 2),
+ 'FEXR': ('FloatReg', 'uw', 'MipsISA::FEXR', 'IsFloating', 3),
+ 'FENR': ('FloatReg', 'uw', 'MipsISA::FENR', 'IsFloating', 3),
+ 'FCSR': ('FloatReg', 'uw', 'MipsISA::FCSR', 'IsFloating', 3),
#Operands For Paired Singles FP Operations
'Fd1': ('FloatReg', 'sf', 'FD', 'IsFloating', 4),
diff --git a/src/arch/mips/isa_traits.cc b/src/arch/mips/isa_traits.cc
index 216a6e2ec..85acc4e8c 100644
--- a/src/arch/mips/isa_traits.cc
+++ b/src/arch/mips/isa_traits.cc
@@ -24,10 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "arch/mips/isa_traits.hh"
-#include "config/full_system.hh"
+//#include "config/full_system.hh"
#include "cpu/static_inst.hh"
#include "sim/serialize.hh"
#include "base/bitfield.hh"
@@ -37,111 +40,17 @@ using namespace std;
void
-MipsISA::copyRegs(ExecContext *src, ExecContext *dest)
+MipsISA::copyRegs(ThreadContext *src, ThreadContext *dest)
{
- /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag);
- uniq = xc->readMiscReg(MipsISA::Uniq_DepTag);
- lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag);
- lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag);
-
-#if FULL_SYSTEM
- copyIprs(xc);
- #endif*/
+ panic("Copy Regs Not Implemented Yet\n");
}
void
-MipsISA::MiscRegFile::copyMiscRegs(ExecContext *xc)
-{
- /*fpcr = xc->readMiscReg(MipsISA::Fpcr_DepTag);
- uniq = xc->readMiscReg(MipsISA::Uniq_DepTag);
- lock_flag = xc->readMiscReg(MipsISA::Lock_Flag_DepTag);
- lock_addr = xc->readMiscReg(MipsISA::Lock_Addr_DepTag);
-
- #endif*/
-}
-
-uint64_t
-MipsISA::fpConvert(double fp_val, ConvertType cvt_type)
-{
-
- switch (cvt_type)
- {
- case SINGLE_TO_DOUBLE:
- double sdouble_val = fp_val;
- void *sdouble_ptr = &sdouble_val;
- uint64_t sdp_bits = *(uint64_t *) sdouble_ptr;
- return sdp_bits;
-
- case SINGLE_TO_WORD:
- int32_t sword_val = (int32_t) fp_val;
- void *sword_ptr = &sword_val;
- uint64_t sword_bits= *(uint32_t *) sword_ptr;
- return sword_bits;
-
- case WORD_TO_SINGLE:
- float wfloat_val = fp_val;
- void *wfloat_ptr = &wfloat_val;
- uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr;
- return wfloat_bits;
-
- case WORD_TO_DOUBLE:
- double wdouble_val = fp_val;
- void *wdouble_ptr = &wdouble_val;
- uint64_t wdp_bits = *(uint64_t *) wdouble_ptr;
- return wdp_bits;
-
- default:
- panic("Invalid Floating Point Conversion Type (%d). See \"types.hh\" for List of Conversions\n",cvt_type);
- return 0;
- }
-}
-
-double
-MipsISA::roundFP(double val, int digits)
-{
- double digit_offset = pow(10.0,digits);
- val = val * digit_offset;
- val = val + 0.5;
- val = floor(val);
- val = val / digit_offset;
- return val;
-}
-
-double
-MipsISA::truncFP(double val)
-{
- int trunc_val = (int) val;
- return (double) trunc_val;
-}
-
-bool
-MipsISA::getFPConditionCode(uint32_t fcsr_reg, int cc)
+MipsISA::MiscRegFile::copyMiscRegs(ThreadContext *tc)
{
- //uint32_t cc_bits = xc->readFloatReg(35);
- return false;//regFile.floatRegfile.getConditionCode(cc);
-}
-
-uint32_t
-MipsISA::makeCCVector(uint32_t fcsr, int num, bool val)
-{
- int shift = (num == 0) ? 22 : num + 23;
-
- fcsr = fcsr | (val << shift);
-
- return fcsr;
+ panic("Copy Misc. Regs Not Implemented Yet\n");
}
-#if FULL_SYSTEM
-
-static inline Addr
-TruncPage(Addr addr)
-{ return addr & ~(MipsISA::PageBytes - 1); }
-
-static inline Addr
-RoundPage(Addr addr)
-{ return (addr + MipsISA::PageBytes - 1) & ~(MipsISA::PageBytes - 1); }
-#endif
-
void
IntRegFile::serialize(std::ostream &os)
{
@@ -166,12 +75,6 @@ RegFile::serialize(std::ostream &os)
SERIALIZE_SCALAR(pc);
SERIALIZE_SCALAR(npc);
SERIALIZE_SCALAR(nnpc);
-#if FULL_SYSTEM
- SERIALIZE_ARRAY(palregs, NumIntRegs);
- SERIALIZE_ARRAY(ipr, NumInternalProcRegs);
- SERIALIZE_SCALAR(intrflag);
- SERIALIZE_SCALAR(pal_shadow);
-#endif
}
@@ -187,43 +90,5 @@ RegFile::unserialize(Checkpoint *cp, const std::string &section)
UNSERIALIZE_SCALAR(pc);
UNSERIALIZE_SCALAR(npc);
UNSERIALIZE_SCALAR(nnpc);
-#if FULL_SYSTEM
- UNSERIALIZE_ARRAY(palregs, NumIntRegs);
- UNSERIALIZE_ARRAY(ipr, NumInternalProcRegs);
- UNSERIALIZE_SCALAR(intrflag);
- UNSERIALIZE_SCALAR(pal_shadow);
-#endif
-}
-
-#if FULL_SYSTEM
-void
-PTE::serialize(std::ostream &os)
-{
- SERIALIZE_SCALAR(tag);
- SERIALIZE_SCALAR(ppn);
- SERIALIZE_SCALAR(xre);
- SERIALIZE_SCALAR(xwe);
- SERIALIZE_SCALAR(asn);
- SERIALIZE_SCALAR(asma);
- SERIALIZE_SCALAR(fonr);
- SERIALIZE_SCALAR(fonw);
- SERIALIZE_SCALAR(valid);
}
-
-
-void
-PTE::unserialize(Checkpoint *cp, const std::string &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);
-}
-
-#endif //FULL_SYSTEM
diff --git a/src/arch/mips/isa_traits.hh b/src/arch/mips/isa_traits.hh
index 148c405df..ff994bef9 100644
--- a/src/arch/mips/isa_traits.hh
+++ b/src/arch/mips/isa_traits.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ARCH_MIPS_ISA_TRAITS_HH__
@@ -45,7 +48,7 @@
class FastCPU;
class FullCPU;
class Checkpoint;
-class ExecContext;
+class ThreadContext;
namespace LittleEndianGuest {};
@@ -54,12 +57,6 @@ namespace LittleEndianGuest {};
class StaticInst;
class StaticInstPtr;
-namespace MIPS34K {
-int DTB_ASN_ASN(uint64_t reg);
-int ITB_ASN_ASN(uint64_t reg);
-};
-
-#if !FULL_SYSTEM
class SyscallReturn {
public:
template <class T>
@@ -92,7 +89,6 @@ class SyscallReturn {
uint64_t retval;
bool success;
};
-#endif
namespace MipsISA
{
@@ -128,20 +124,14 @@ namespace MipsISA
/**
* Function to insure ISA semantics about 0 registers.
- * @param xc The execution context.
+ * @param tc The thread context.
*/
- template <class XC>
- void zeroRegisters(XC *xc);
+ template <class TC>
+ void zeroRegisters(TC *tc);
const Addr MaxAddr = (Addr)-1;
- void copyRegs(ExecContext *src, ExecContext *dest);
-
- uint64_t fpConvert(double fp_val, ConvertType cvt_type);
- double roundFP(double val, int digits);
- double truncFP(double val);
- bool getFPConditionCode(uint32_t fcsr_reg, int cc);
- uint32_t makeCCVector(uint32_t fcsr, int num, bool val);
+ void copyRegs(ThreadContext *src, ThreadContext *dest);
// Machine operations
@@ -188,12 +178,6 @@ namespace MipsISA
};
-#if FULL_SYSTEM
-
-#include "arch/mips/mips34k.hh"
-
-#endif
-
using namespace MipsISA;
#endif // __ARCH_MIPS_ISA_TRAITS_HH__
diff --git a/src/arch/mips/linux/process.cc b/src/arch/mips/linux/process.cc
index ffc5da2e1..17e735527 100644
--- a/src/arch/mips/linux/process.cc
+++ b/src/arch/mips/linux/process.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#include "arch/mips/linux/linux.hh"
@@ -31,7 +33,7 @@
#include "arch/mips/isa_traits.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/linux/linux.hh"
#include "sim/process.hh"
@@ -43,9 +45,9 @@ using namespace MipsISA;
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -53,7 +55,7 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
strcpy(name->machine, "mips");
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
@@ -62,18 +64,18 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
/// different in practice from those used by Tru64 processes.
static SyscallReturn
sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
- // unsigned nbytes = xc->getSyscallArg(2);
+ unsigned op = tc->getSyscallArg(0);
+ // unsigned nbytes = tc->getSyscallArg(2);
switch (op) {
case 45: { // GSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
// I don't think this exactly matches the HW FPCR
*fpcr = 0;
- fpcr.copyOut(xc->getMemPort());
+ fpcr.copyOut(tc->getMemPort());
return 0;
}
@@ -89,17 +91,17 @@ sys_getsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
/// Target sys_setsysinfo() handler.
static SyscallReturn
sys_setsysinfoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned op = xc->getSyscallArg(0);
- // unsigned nbytes = xc->getSyscallArg(2);
+ unsigned op = tc->getSyscallArg(0);
+ // unsigned nbytes = tc->getSyscallArg(2);
switch (op) {
case 14: { // SSI_IEEE_FP_CONTROL
- TypedBufferArg<uint64_t> fpcr(xc->getSyscallArg(1));
+ TypedBufferArg<uint64_t> fpcr(tc->getSyscallArg(1));
// I don't think this exactly matches the HW FPCR
- fpcr.copyIn(xc->getMemPort());
+ fpcr.copyIn(tc->getMemPort());
DPRINTFR(SyscallVerbose, "sys_setsysinfo(SSI_IEEE_FP_CONTROL): "
" setting FPCR to 0x%x\n", gtoh(*(uint64_t*)fpcr));
return 0;
@@ -133,7 +135,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 14 */ SyscallDesc("mknod", unimplementedFunc),
/* 15 */ SyscallDesc("chmod", chmodFunc<MipsLinux>),
/* 16 */ SyscallDesc("lchown", chownFunc),
- /* 17 */ SyscallDesc("break", obreakFunc), /*obreak*/
+ /* 17 */ SyscallDesc("break", obreakFunc),
/* 18 */ SyscallDesc("unused#18", unimplementedFunc),
/* 19 */ SyscallDesc("lseek", lseekFunc),
/* 20 */ SyscallDesc("getpid", getpidFunc),
@@ -161,7 +163,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 42 */ SyscallDesc("pipe", unimplementedFunc),
/* 43 */ SyscallDesc("times", unimplementedFunc),
/* 44 */ SyscallDesc("prof", unimplementedFunc),
- /* 45 */ SyscallDesc("brk", obreakFunc),/*openFunc<MipsLinux>*/
+ /* 45 */ SyscallDesc("brk", obreakFunc),
/* 46 */ SyscallDesc("setgid", unimplementedFunc),
/* 47 */ SyscallDesc("getgid", getgidFunc),
/* 48 */ SyscallDesc("signal", ignoreFunc),
@@ -171,7 +173,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 52 */ SyscallDesc("umount2", unimplementedFunc),
/* 53 */ SyscallDesc("lock", unimplementedFunc),
/* 54 */ SyscallDesc("ioctl", ioctlFunc<MipsLinux>),
- /* 55 */ SyscallDesc("fcntl", unimplementedFunc),
+ /* 55 */ SyscallDesc("fcntl", fcntlFunc),
/* 56 */ SyscallDesc("mpx", unimplementedFunc),
/* 57 */ SyscallDesc("setpgid", unimplementedFunc),
/* 58 */ SyscallDesc("ulimit", unimplementedFunc),
@@ -208,8 +210,8 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 89 */ SyscallDesc("readdir", unimplementedFunc),
/* 90 */ SyscallDesc("mmap", mmapFunc<MipsLinux>),
/* 91 */ SyscallDesc("munmap",munmapFunc),
- /* 92 */ SyscallDesc("truncate", fcntlFunc),
- /* 93 */ SyscallDesc("ftruncate", unimplementedFunc),
+ /* 92 */ SyscallDesc("truncate", truncateFunc),
+ /* 93 */ SyscallDesc("ftruncate", ftruncateFunc),
/* 94 */ SyscallDesc("fchmod", unimplementedFunc),
/* 95 */ SyscallDesc("fchown", unimplementedFunc),
/* 96 */ SyscallDesc("getpriority", unimplementedFunc),
@@ -260,7 +262,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 141 */ SyscallDesc("getdents", unimplementedFunc),
/* 142 */ SyscallDesc("newselect", unimplementedFunc),
/* 143 */ SyscallDesc("flock", unimplementedFunc),
- /* 144 */ SyscallDesc("msync", unimplementedFunc),/*getrlimitFunc<MipsLinux>*/
+ /* 144 */ SyscallDesc("msync", unimplementedFunc),
/* 145 */ SyscallDesc("readv", unimplementedFunc),
/* 146 */ SyscallDesc("writev", writevFunc<MipsLinux>),
/* 147 */ SyscallDesc("cacheflush", unimplementedFunc),
@@ -336,7 +338,7 @@ SyscallDesc MipsLinuxProcess::syscallDescs[] = {
/* 217 */ SyscallDesc("mincore", unimplementedFunc),
/* 218 */ SyscallDesc("madvise", unimplementedFunc),
/* 219 */ SyscallDesc("getdents64", unimplementedFunc),
- /* 220 */ SyscallDesc("fcntl64", fcntlFunc),
+ /* 220 */ SyscallDesc("fcntl64", fcntl64Func),
/* 221 */ SyscallDesc("reserved#221", unimplementedFunc),
/* 222 */ SyscallDesc("gettid", unimplementedFunc),
/* 223 */ SyscallDesc("readahead", unimplementedFunc),
@@ -412,9 +414,7 @@ MipsLinuxProcess::MipsLinuxProcess(const std::string &name,
: MipsLiveProcess(name, objFile, system, stdin_fd, stdout_fd, stderr_fd,
argv, envp),
Num_Syscall_Descs(sizeof(syscallDescs) / sizeof(SyscallDesc))
-{
- //init_regs->intRegFile[0] = 0;
-}
+{ }
SyscallDesc*
MipsLinuxProcess::getDesc(int callnum)
diff --git a/src/arch/mips/process.cc b/src/arch/mips/process.cc
index 7831551be..031c2030e 100644
--- a/src/arch/mips/process.cc
+++ b/src/arch/mips/process.cc
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2003-2004 The Regents of The University of Michigan
* All rights reserved.
@@ -24,74 +25,41 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
+ * Korey Sewell
*/
#include "arch/mips/isa_traits.hh"
#include "arch/mips/process.hh"
-#include "arch/mips/linux/process.hh"
#include "base/loader/object_file.hh"
#include "base/misc.hh"
-#include "cpu/exec_context.hh"
-#include "sim/builder.hh"
+#include "cpu/thread_context.hh"
#include "sim/system.hh"
using namespace std;
using namespace MipsISA;
-
-MipsLiveProcess *
-MipsLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
- int stdout_fd, int stderr_fd, std::string executable,
- std::vector<std::string> &argv, std::vector<std::string> &envp)
-{
- MipsLiveProcess *process = NULL;
-
- ObjectFile *objFile = createObjectFile(executable);
- if (objFile == NULL) {
- fatal("Can't load object file %s", executable);
- }
-
-
- if (objFile->getArch() != ObjectFile::Mips)
- fatal("Object file does not match architecture.");
- switch (objFile->getOpSys()) {
- case ObjectFile::Linux:
- process = new MipsLinuxProcess(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
- break;
-
- default:
- fatal("Unknown/unsupported operating system.");
- }
-
- if (process == NULL)
- fatal("Unknown error creating process object.");
- return process;
-}
-
MipsLiveProcess::MipsLiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
std::vector<std::string> &argv, std::vector<std::string> &envp)
: LiveProcess(nm, objFile, _system, stdin_fd, stdout_fd, stderr_fd,
argv, envp)
{
+ // Set up stack. On MIPS, stack starts at the top of kuseg
+ // user address space. MIPS stack grows down from here
+ stack_base = 0x7FFFFFFF;
+
+ // Set pointer for next thread stack. Reserve 8M for main stack.
+ next_thread_stack_base = stack_base - (8 * 1024 * 1024);
- // XXX all the below need to be updated for SPARC - Ali
+ // Set up break point (Top of Heap)
brk_point = objFile->dataBase() + objFile->dataSize() + objFile->bssSize();
brk_point = roundUp(brk_point, VMPageSize);
- // Set up stack. On Alpha, stack goes below text section. This
- // code should get moved to some architecture-specific spot.
- stack_base = objFile->textBase() - (409600+4096);
-
- // Set up region for mmaps. Tru64 seems to start just above 0 and
- // grow up from there.
+ // Set up region for mmaps. For now, start at bottom of kuseg space.
mmap_start = mmap_end = 0x10000;
-
- // Set pointer for next thread stack. Reserve 8M for main stack.
- next_thread_stack_base = stack_base - (8 * 1024 * 1024);
-
}
void
@@ -99,63 +67,3 @@ MipsLiveProcess::startup()
{
argsInit(MachineBytes, VMPageSize);
}
-
-
-
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess)
-
- VectorParam<string> cmd;
- Param<string> executable;
- Param<string> input;
- Param<string> output;
- VectorParam<string> env;
- SimObjectParam<System *> system;
-
-END_DECLARE_SIM_OBJECT_PARAMS(MipsLiveProcess)
-
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess)
-
- INIT_PARAM(cmd, "command line (executable plus arguments)"),
- INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
- INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
- INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
- INIT_PARAM(env, "environment settings"),
- INIT_PARAM(system, "system")
-
-END_INIT_SIM_OBJECT_PARAMS(MipsLiveProcess)
-
-
-CREATE_SIM_OBJECT(MipsLiveProcess)
-{
- string in = input;
- string out = output;
-
- // initialize file descriptors to default: same as simulator
- int stdin_fd, stdout_fd, stderr_fd;
-
- if (in == "stdin" || in == "cin")
- stdin_fd = STDIN_FILENO;
- else
- stdin_fd = Process::openInputFile(input);
-
- if (out == "stdout" || out == "cout")
- stdout_fd = STDOUT_FILENO;
- else if (out == "stderr" || out == "cerr")
- stdout_fd = STDERR_FILENO;
- else
- stdout_fd = Process::openOutputFile(out);
-
- stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
-
- return MipsLiveProcess::create(getInstanceName(), system,
- stdin_fd, stdout_fd, stderr_fd,
- (string)executable == "" ? cmd[0] : executable,
- cmd, env);
-}
-
-
-REGISTER_SIM_OBJECT("MipsLiveProcess", MipsLiveProcess)
-
-
diff --git a/src/arch/mips/process.hh b/src/arch/mips/process.hh
index 2a13dc955..b0ef20399 100644
--- a/src/arch/mips/process.hh
+++ b/src/arch/mips/process.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
+ * Korey Sewell
*/
#ifndef __MIPS_PROCESS_HH__
@@ -46,18 +50,6 @@ class MipsLiveProcess : public LiveProcess
std::vector<std::string> &envp);
void startup();
-
- public:
- // this function is used to create the LiveProcess object, since
- // we can't tell which subclass of LiveProcess to use until we
- // open and look at the object file.
- static MipsLiveProcess *create(const std::string &nm,
- System *_system,
- int stdin_fd, int stdout_fd, int stderr_fd,
- std::string executable,
- std::vector<std::string> &argv,
- std::vector<std::string> &envp);
-
};
diff --git a/src/arch/mips/regfile/float_regfile.hh b/src/arch/mips/regfile/float_regfile.hh
index 15c6f97f4..61efbb416 100644
--- a/src/arch/mips/regfile/float_regfile.hh
+++ b/src/arch/mips/regfile/float_regfile.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,6 +32,7 @@
#include "arch/mips/types.hh"
#include "arch/mips/constants.hh"
#include "base/misc.hh"
+#include "base/bitfield.hh"
#include "config/full_system.hh"
#include "sim/byteswap.hh"
#include "sim/faults.hh"
@@ -60,13 +61,17 @@ namespace MipsISA
switch(width)
{
case SingleWidth:
- void *float_ptr = &regs[floatReg];
- return *(float *) float_ptr;
+ {
+ void *float_ptr = &regs[floatReg];
+ return *(float *) float_ptr;
+ }
case DoubleWidth:
- uint64_t double_val = (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg];
- void *double_ptr = &double_val;
- return *(double *) double_ptr;
+ {
+ uint64_t double_val = (FloatReg64)regs[floatReg + 1] << 32 | regs[floatReg];
+ void *double_ptr = &double_val;
+ return *(double *) double_ptr;
+ }
default:
panic("Attempted to read a %d bit floating point register!", width);
@@ -95,23 +100,27 @@ namespace MipsISA
}
}
- Fault setReg(int floatReg, const FloatReg &val, int width)
+ Fault setReg(int floatReg, const FloatRegVal &val, int width)
{
-
+ using namespace std;
switch(width)
{
case SingleWidth:
- float temp = val;
- void *float_ptr = &temp;
- regs[floatReg] = *(FloatReg32 *) float_ptr;
- break;
+ {
+ float temp = val;
+ void *float_ptr = &temp;
+ regs[floatReg] = *(FloatReg32 *) float_ptr;
+ break;
+ }
case DoubleWidth:
- const void *double_ptr = &val;
- FloatReg64 temp_double = *(FloatReg64 *) double_ptr;
- regs[floatReg + 1] = temp_double >> 32;
- regs[floatReg] = temp_double;
- break;
+ {
+ const void *double_ptr = &val;
+ FloatReg64 temp_double = *(FloatReg64 *) double_ptr;
+ regs[floatReg + 1] = bits(temp_double, 63, 32);
+ regs[floatReg] = bits(temp_double, 31, 0);
+ break;
+ }
default:
panic("Attempted to read a %d bit floating point register!", width);
@@ -131,8 +140,8 @@ namespace MipsISA
break;
case DoubleWidth:
- regs[floatReg + 1] = val >> 32;
- regs[floatReg] = val;
+ regs[floatReg + 1] = bits(val, 63, 32);
+ regs[floatReg] = bits(val, 31, 0);
break;
default:
@@ -146,14 +155,6 @@ namespace MipsISA
void unserialize(Checkpoint *cp, const std::string &section);
};
- enum MiscFloatRegNums {
- FIR = NumFloatArchRegs,
- FCCR,
- FEXR,
- FENR,
- FCSR
- };
-
} // namespace MipsISA
#endif
diff --git a/src/arch/mips/regfile/int_regfile.hh b/src/arch/mips/regfile/int_regfile.hh
index 3cd87734d..5add1b7be 100644
--- a/src/arch/mips/regfile/int_regfile.hh
+++ b/src/arch/mips/regfile/int_regfile.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#ifndef __ARCH_MIPS_INT_REGFILE_HH__
@@ -35,7 +37,7 @@
#include "sim/faults.hh"
class Checkpoint;
-class ExecContext;
+class ThreadContext;
class Regfile;
namespace MipsISA
@@ -63,11 +65,6 @@ namespace MipsISA
};
- enum MiscIntRegNums {
- HI = NumIntArchRegs,
- LO
- };
-
} // namespace MipsISA
#endif
diff --git a/src/arch/mips/regfile/misc_regfile.hh b/src/arch/mips/regfile/misc_regfile.hh
index 9f054e5f7..87961f97e 100644
--- a/src/arch/mips/regfile/misc_regfile.hh
+++ b/src/arch/mips/regfile/misc_regfile.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#ifndef __ARCH_MIPS_MISC_REGFILE_HH__
@@ -34,7 +36,7 @@
#include "sim/faults.hh"
class Checkpoint;
-class ExecContext;
+class ThreadContext;
class Regfile;
namespace MipsISA
@@ -43,26 +45,20 @@ namespace MipsISA
protected:
uint64_t fpcr; // floating point condition codes
- uint64_t uniq; // process-unique register
bool lock_flag; // lock flag for LL/SC
Addr lock_addr; // lock address for LL/SC
MiscReg miscRegFile[NumMiscRegs];
public:
- //These functions should be removed once the simplescalar cpu model
- //has been replaced.
- int getInstAsid();
- int getDataAsid();
-
- void copyMiscRegs(ExecContext *xc);
+ void copyMiscRegs(ThreadContext *tc);
MiscReg readReg(int misc_reg)
{
return miscRegFile[misc_reg];
}
- MiscReg readRegWithEffect(int misc_reg, Fault &fault, ExecContext *xc)
+ MiscReg readRegWithEffect(int misc_reg, Fault &fault, ThreadContext *tc)
{
return miscRegFile[misc_reg];
}
@@ -73,22 +69,11 @@ namespace MipsISA
}
Fault setRegWithEffect(int misc_reg, const MiscReg &val,
- ExecContext *xc)
+ ThreadContext *tc)
{
miscRegFile[misc_reg] = val; return NoFault;
}
-#if FULL_SYSTEM
- void clearIprs() { }
-
- protected:
- InternalProcReg ipr[NumInternalProcRegs]; // Internal processor regs
-
- private:
- MiscReg readIpr(int idx, Fault &fault, ExecContext *xc) { }
-
- Fault setIpr(int idx, uint64_t val, ExecContext *xc) { }
-#endif
friend class RegFile;
};
} // namespace MipsISA
diff --git a/src/arch/mips/regfile/regfile.hh b/src/arch/mips/regfile/regfile.hh
index e77571b33..a68120299 100644
--- a/src/arch/mips/regfile/regfile.hh
+++ b/src/arch/mips/regfile/regfile.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#ifndef __ARCH_MIPS_REGFILE_HH__
@@ -37,7 +39,7 @@
#include "sim/faults.hh"
class Checkpoint;
-class ExecContext;
+class ThreadContext;
namespace MipsISA
{
@@ -62,10 +64,10 @@ namespace MipsISA
}
MiscReg readMiscRegWithEffect(int miscReg,
- Fault &fault, ExecContext *xc)
+ Fault &fault, ThreadContext *tc)
{
fault = NoFault;
- return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ return miscRegFile.readRegWithEffect(miscReg, fault, tc);
}
Fault setMiscReg(int miscReg, const MiscReg &val)
@@ -74,17 +76,17 @@ namespace MipsISA
}
Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
- ExecContext * xc)
+ ThreadContext * tc)
{
- return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ return miscRegFile.setRegWithEffect(miscReg, val, tc);
}
- FloatReg readFloatReg(int floatReg)
+ FloatRegVal readFloatReg(int floatReg)
{
return floatRegFile.readReg(floatReg,SingleWidth);
}
- FloatReg readFloatReg(int floatReg, int width)
+ FloatRegVal readFloatReg(int floatReg, int width)
{
return floatRegFile.readReg(floatReg,width);
}
@@ -99,12 +101,12 @@ namespace MipsISA
return floatRegFile.readRegBits(floatReg,width);
}
- Fault setFloatReg(int floatReg, const FloatReg &val)
+ Fault setFloatReg(int floatReg, const FloatRegVal &val)
{
return floatRegFile.setReg(floatReg, val, SingleWidth);
}
- Fault setFloatReg(int floatReg, const FloatReg &val, int width)
+ Fault setFloatReg(int floatReg, const FloatRegVal &val, int width)
{
return floatRegFile.setReg(floatReg, val, width);
}
@@ -166,16 +168,6 @@ namespace MipsISA
nnpc = val;
}
-
-#if FULL_SYSTEM
- IntReg palregs[NumIntRegs]; // PAL shadow registers
- InternalProcReg ipr[NumInternalProcRegs]; // internal processor regs
- int intrflag; // interrupt flag
- bool pal_shadow; // using pal_shadow registers
- inline int instAsid() { return MIPS34K::ITB_ASN_ASN(ipr[IPR_ITB_ASN]); }
- inline int dataAsid() { return MIPS34K::DTB_ASN_ASN(ipr[IPR_DTB_ASN]); }
-#endif // FULL_SYSTEM
-
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
@@ -187,13 +179,10 @@ namespace MipsISA
}
};
- void copyRegs(ExecContext *src, ExecContext *dest);
+ void copyRegs(ThreadContext *src, ThreadContext *dest);
- void copyMiscRegs(ExecContext *src, ExecContext *dest);
+ void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
-#if FULL_SYSTEM
- void copyIprs(ExecContext *src, ExecContext *dest);
-#endif
} // namespace MipsISA
#endif
diff --git a/src/arch/mips/stacktrace.hh b/src/arch/mips/stacktrace.hh
index 1d8d97a79..f9e092dbd 100644
--- a/src/arch/mips/stacktrace.hh
+++ b/src/arch/mips/stacktrace.hh
@@ -24,21 +24,23 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
*/
-#ifndef __ARCH_ALPHA_STACKTRACE_HH__
-#define __ARCH_ALPHA_STACKTRACE_HH__
+#ifndef __ARCH_MIPS_STACKTRACE_HH__
+#define __ARCH_MIPS_STACKTRACE_HH__
#include "base/trace.hh"
#include "cpu/static_inst.hh"
-class ExecContext;
+class ThreadContext;
class StackTrace;
class ProcessInfo
{
private:
- ExecContext *xc;
+ ThreadContext *tc;
int thread_info_size;
int task_struct_size;
@@ -47,7 +49,7 @@ class ProcessInfo
int name_off;
public:
- ProcessInfo(ExecContext *_xc);
+ ProcessInfo(ThreadContext *_tc);
Addr task(Addr ksp) const;
int pid(Addr ksp) const;
@@ -59,7 +61,7 @@ class StackTrace
protected:
typedef TheISA::MachInst MachInst;
private:
- ExecContext *xc;
+ ThreadContext *tc;
std::vector<Addr> stack;
private:
@@ -68,21 +70,21 @@ class StackTrace
bool decodeSave(MachInst inst, int &reg, int &disp);
bool decodeStack(MachInst inst, int &disp);
- void trace(ExecContext *xc, bool is_call);
+ void trace(ThreadContext *tc, bool is_call);
public:
StackTrace();
- StackTrace(ExecContext *xc, StaticInstPtr inst);
+ StackTrace(ThreadContext *tc, StaticInstPtr inst);
~StackTrace();
void clear()
{
- xc = 0;
+ tc = 0;
stack.clear();
}
- bool valid() const { return xc != NULL; }
- bool trace(ExecContext *xc, StaticInstPtr inst);
+ bool valid() const { return tc != NULL; }
+ bool trace(ThreadContext *tc, StaticInstPtr inst);
public:
const std::vector<Addr> &getstack() const { return stack; }
@@ -104,7 +106,7 @@ class StackTrace
};
inline bool
-StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+StackTrace::trace(ThreadContext *tc, StaticInstPtr inst)
{
if (!inst->isCall() && !inst->isReturn())
return false;
@@ -112,8 +114,8 @@ StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
if (valid())
clear();
- trace(xc, !inst->isReturn());
+ trace(tc, !inst->isReturn());
return true;
}
-#endif // __ARCH_ALPHA_STACKTRACE_HH__
+#endif // __ARCH_MIPS_STACKTRACE_HH__
diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh
index 4d5fb3456..6330044d9 100644
--- a/src/arch/mips/types.hh
+++ b/src/arch/mips/types.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
*/
#ifndef __ARCH_MIPS_TYPES_HH__
@@ -40,14 +42,15 @@ namespace MipsISA
typedef uint32_t IntReg;
// floating point register file entry type
- typedef double FloatReg;
typedef uint32_t FloatReg32;
typedef uint64_t FloatReg64;
typedef uint64_t FloatRegBits;
+ typedef double FloatRegVal;
+ typedef double FloatReg;
+
// cop-0/cop-1 system control register
typedef uint64_t MiscReg;
- typedef uint64_t InternalProcReg;
typedef union {
IntReg intreg;
diff --git a/src/arch/mips/utility.cc b/src/arch/mips/utility.cc
new file mode 100644
index 000000000..e7455fdbf
--- /dev/null
+++ b/src/arch/mips/utility.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ */
+
+#include "arch/mips/isa_traits.hh"
+#include "arch/mips/utility.hh"
+#include "config/full_system.hh"
+#include "cpu/static_inst.hh"
+#include "sim/serialize.hh"
+#include "base/bitfield.hh"
+
+using namespace MipsISA;
+using namespace std;
+
+uint64_t
+MipsISA::fpConvert(ConvertType cvt_type, double fp_val)
+{
+
+ switch (cvt_type)
+ {
+ case SINGLE_TO_DOUBLE:
+ {
+ double sdouble_val = fp_val;
+ void *sdouble_ptr = &sdouble_val;
+ uint64_t sdp_bits = *(uint64_t *) sdouble_ptr;
+ return sdp_bits;
+ }
+
+ case SINGLE_TO_WORD:
+ {
+ int32_t sword_val = (int32_t) fp_val;
+ void *sword_ptr = &sword_val;
+ uint64_t sword_bits= *(uint32_t *) sword_ptr;
+ return sword_bits;
+ }
+
+ case WORD_TO_SINGLE:
+ {
+ float wfloat_val = fp_val;
+ void *wfloat_ptr = &wfloat_val;
+ uint64_t wfloat_bits = *(uint32_t *) wfloat_ptr;
+ return wfloat_bits;
+ }
+
+ case WORD_TO_DOUBLE:
+ {
+ double wdouble_val = fp_val;
+ void *wdouble_ptr = &wdouble_val;
+ uint64_t wdp_bits = *(uint64_t *) wdouble_ptr;
+ return wdp_bits;
+ }
+
+ default:
+ panic("Invalid Floating Point Conversion Type (%d). See \"types.hh\" for List of Conversions\n",cvt_type);
+ return 0;
+ }
+}
+
+double
+MipsISA::roundFP(double val, int digits)
+{
+ double digit_offset = pow(10.0,digits);
+ val = val * digit_offset;
+ val = val + 0.5;
+ val = floor(val);
+ val = val / digit_offset;
+ return val;
+}
+
+double
+MipsISA::truncFP(double val)
+{
+ int trunc_val = (int) val;
+ return (double) trunc_val;
+}
+
+bool
+MipsISA::getCondCode(uint32_t fcsr, int cc_idx)
+{
+ int shift = (cc_idx == 0) ? 23 : cc_idx + 24;
+ bool cc_val = (fcsr >> shift) & 0x00000001;
+ return cc_val;
+}
+
+uint32_t
+MipsISA::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 |
+ cc_val << cc_idx |
+ bits(fcsr, cc_idx - 1, 0);
+
+ return fcsr;
+}
+
+uint32_t
+MipsISA::genInvalidVector(uint32_t fcsr_bits)
+{
+ //Set FCSR invalid in "flag" field
+ int invalid_offset = Invalid + Flag_Field;
+ fcsr_bits = fcsr_bits | (1 << invalid_offset);
+
+ //Set FCSR invalid in "cause" flag
+ int cause_offset = Invalid + Cause_Field;
+ fcsr_bits = fcsr_bits | (1 << cause_offset);
+
+ return fcsr_bits;
+}
+
+bool
+MipsISA::isNan(void *val_ptr, int size)
+{
+ switch (size)
+ {
+ case 32:
+ {
+ uint32_t val_bits = *(uint32_t *) val_ptr;
+ return (bits(val_bits, 30, 23) == 0xFF);
+ }
+
+ case 64:
+ {
+ uint64_t val_bits = *(uint64_t *) val_ptr;
+ return (bits(val_bits, 62, 52) == 0x7FF);
+ }
+
+ default:
+ panic("Type unsupported. Size mismatch\n");
+ }
+}
+
+
+bool
+MipsISA::isQnan(void *val_ptr, int size)
+{
+ switch (size)
+ {
+ case 32:
+ {
+ uint32_t val_bits = *(uint32_t *) val_ptr;
+ return (bits(val_bits, 30, 22) == 0x1FE);
+ }
+
+ case 64:
+ {
+ uint64_t val_bits = *(uint64_t *) val_ptr;
+ return (bits(val_bits, 62, 51) == 0xFFE);
+ }
+
+ default:
+ panic("Type unsupported. Size mismatch\n");
+ }
+}
+
+bool
+MipsISA::isSnan(void *val_ptr, int size)
+{
+ switch (size)
+ {
+ case 32:
+ {
+ uint32_t val_bits = *(uint32_t *) val_ptr;
+ return (bits(val_bits, 30, 22) == 0x1FF);
+ }
+
+ case 64:
+ {
+ uint64_t val_bits = *(uint64_t *) val_ptr;
+ return (bits(val_bits, 62, 51) == 0xFFF);
+ }
+
+ default:
+ panic("Type unsupported. Size mismatch\n");
+ }
+}
diff --git a/src/arch/mips/utility.hh b/src/arch/mips/utility.hh
index 5c7dc3ea4..c5c69ddcd 100644
--- a/src/arch/mips/utility.hh
+++ b/src/arch/mips/utility.hh
@@ -39,6 +39,19 @@
namespace MipsISA {
+ //Floating Point Utility Functions
+ uint64_t fpConvert(ConvertType cvt_type, double fp_val);
+ double roundFP(double val, int digits);
+ double truncFP(double val);
+
+ bool getCondCode(uint32_t fcsr, int cc);
+ uint32_t genCCVector(uint32_t fcsr, int num, uint32_t cc_val);
+ uint32_t genInvalidVector(uint32_t fcsr);
+
+ bool isNan(void *val_ptr, int size);
+ bool isQnan(void *val_ptr, int size);
+ bool isSnan(void *val_ptr, int size);
};
+
#endif
diff --git a/src/arch/sparc/SConscript b/src/arch/sparc/SConscript
index 7362c9275..e7a8278db 100644
--- a/src/arch/sparc/SConscript
+++ b/src/arch/sparc/SConscript
@@ -25,6 +25,9 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Gabe Black
+# Steve Reinhardt
import os
import sys
@@ -47,12 +50,8 @@ base_sources = Split('''
# Full-system sources
full_system_sources = Split('''
- tlb.cc
- arguments.cc
- ev5.cc
- osfpal.cc
- stacktrace.cc
vtophys.cc
+ ua2005.cc
''')
# Syscall emulation (non-full-system) sources
diff --git a/src/arch/sparc/faults.cc b/src/arch/sparc/faults.cc
index 67a89ab0e..7b7765935 100644
--- a/src/arch/sparc/faults.cc
+++ b/src/arch/sparc/faults.cc
@@ -24,12 +24,19 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#include "arch/sparc/faults.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "base/trace.hh"
+#if !FULL_SYSTEM
+#include "sim/process.hh"
+#include "mem/page_table.hh"
+#endif
namespace SparcISA
{
@@ -215,40 +222,66 @@ TrapType TrapInstruction::_baseTrapType = 0x100;
FaultPriority TrapInstruction::_priority = 16;
FaultStat TrapInstruction::_count;
+#if !FULL_SYSTEM
+FaultName PageTableFault::_name = "page_table_fault";
+TrapType PageTableFault::_trapType = 0x0000;
+FaultPriority PageTableFault::_priority = 0;
+FaultStat PageTableFault::_count;
+#endif
+
#if FULL_SYSTEM
-void SparcFault::invoke(ExecContext * xc)
+void SparcFault::invoke(ThreadContext * tc)
{
- FaultBase::invoke(xc);
+ FaultBase::invoke(tc);
countStat()++;
//Use the SPARC trap state machine
/*// exception restart address
- if (setRestartAddress() || !xc->inPalMode())
- xc->setMiscReg(AlphaISA::IPR_EXC_ADDR, xc->regs.pc);
+ if (setRestartAddress() || !tc->inPalMode())
+ tc->setMiscReg(AlphaISA::IPR_EXC_ADDR, tc->regs.pc);
if (skipFaultingInstruction()) {
// traps... skip faulting instruction.
- xc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
- xc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
+ tc->setMiscReg(AlphaISA::IPR_EXC_ADDR,
+ tc->readMiscReg(AlphaISA::IPR_EXC_ADDR) + 4);
}
- if (!xc->inPalMode())
- AlphaISA::swap_palshadow(&(xc->regs), true);
+ if (!tc->inPalMode())
+ AlphaISA::swap_palshadow(&(tc->regs), true);
- xc->regs.pc = xc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect();
- xc->regs.npc = xc->regs.pc + sizeof(MachInst);*/
+ tc->regs.pc = tc->readMiscReg(AlphaISA::IPR_PAL_BASE) + vect();
+ tc->regs.npc = tc->regs.pc + sizeof(MachInst);*/
}
#endif
#if !FULL_SYSTEM
-void TrapInstruction::invoke(ExecContext * xc)
+void TrapInstruction::invoke(ThreadContext * tc)
{
- xc->syscall(syscall_num);
+ // Should be handled in ISA.
}
+void PageTableFault::invoke(ThreadContext *tc)
+{
+ Process *p = tc->getProcessPtr();
+
+ // address is higher than the stack region or in the current stack region
+ if (vaddr > p->stack_base || vaddr > p->stack_min)
+ FaultBase::invoke(tc);
+
+ // We've accessed the next page
+ if (vaddr > p->stack_min - PageBytes) {
+ p->stack_min -= PageBytes;
+ if (p->stack_base - p->stack_min > 8*1024*1024)
+ fatal("Over max stack size for one thread\n");
+ p->pTable->allocate(p->stack_min, PageBytes);
+ warn("Increasing stack size by one page.");
+ } else {
+ FaultBase::invoke(tc);
+ }
+}
#endif
} // namespace SparcISA
diff --git a/src/arch/sparc/faults.hh b/src/arch/sparc/faults.hh
index e8fb8dfc5..b279f4911 100644
--- a/src/arch/sparc/faults.hh
+++ b/src/arch/sparc/faults.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#ifndef __ALPHA_FAULTS_HH__
@@ -43,7 +46,7 @@ class SparcFault : public FaultBase
{
public:
#if FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
virtual TrapType trapType() = 0;
virtual FaultPriority priority() = 0;
@@ -80,6 +83,31 @@ class MemAddressNotAligned : public SparcFault
bool isAlignmentFault() {return true;}
};
+#if !FULL_SYSTEM
+class PageTableFault : public SparcFault
+{
+ private:
+ Addr vaddr;
+ static FaultName _name;
+ static TrapType _trapType;
+ static FaultPriority _priority;
+ static FaultStat _count;
+ public:
+ PageTableFault(Addr va)
+ : vaddr(va) {}
+ FaultName name() {return _name;}
+ TrapType trapType() {return _trapType;}
+ FaultPriority priority() {return _priority;}
+ FaultStat & countStat() {return _count;}
+ void invoke(ThreadContext * tc);
+};
+
+static inline Fault genPageTableFault(Addr va)
+{
+ return new PageTableFault(va);
+}
+#endif
+
static inline Fault genMachineCheckFault()
{
return new InternalProcessorError;
@@ -582,10 +610,11 @@ class TrapInstruction : public EnumeratedFault
FaultPriority priority() {return _priority;}
FaultStat & countStat() {return _count;}
#if !FULL_SYSTEM
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
#endif
};
+
} // SparcISA namespace
#endif // __FAULTS_HH__
diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa
index c6e05bf6f..fa8832920 100644
--- a/src/arch/sparc/isa/decoder.isa
+++ b/src/arch/sparc/isa/decoder.isa
@@ -44,13 +44,13 @@ decode OP default Unknown::unknown()
format Branch19
{
0x0: bpcci({{
- if(passesCondition(CcrIcc, COND2))
+ if(passesCondition(Ccr<3:0>, COND2))
NNPC = xc->readPC() + disp;
else
handle_annul
}});
0x2: bpccx({{
- if(passesCondition(CcrXcc, COND2))
+ if(passesCondition(Ccr<7:4>, COND2))
NNPC = xc->readPC() + disp;
else
handle_annul
@@ -58,7 +58,7 @@ decode OP default Unknown::unknown()
}
}
0x2: Branch22::bicc({{
- if(passesCondition(CcrIcc, COND2))
+ if(passesCondition(Ccr<3:0>, COND2))
NNPC = xc->readPC() + disp;
else
handle_annul
@@ -124,17 +124,17 @@ decode OP default Unknown::unknown()
0x05: andn({{Rd = Rs1.udw & ~Rs2_or_imm13;}});
0x06: orn({{Rd = Rs1.udw | ~Rs2_or_imm13;}});
0x07: xnor({{Rd = ~(Rs1.udw ^ Rs2_or_imm13);}});
- 0x08: addc({{Rd = Rs1.sdw + Rs2_or_imm13 + CcrIccC;}});
+ 0x08: addc({{Rd = Rs1.sdw + Rs2_or_imm13 + Ccr<0:0>;}});
0x09: mulx({{Rd = Rs1 * Rs2_or_imm13;}});
0x0A: umul({{
Rd = Rs1.udw<31:0> * Rs2_or_imm13<31:0>;
- YValue = Rd<63:32>;
+ Y = Rd<63:32>;
}});
0x0B: smul({{
Rd.sdw = Rs1.sdw<31:0> * Rs2_or_imm13<31:0>;
- YValue = Rd.sdw;
+ Y = Rd.sdw;
}});
- 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 + CcrIccC;}});
+ 0x0C: subc({{Rd.sdw = Rs1.sdw + (~Rs2_or_imm13) + 1 + Ccr<0:0>}});
0x0D: udivx({{
if(Rs2_or_imm13 == 0) fault = new DivisionByZero;
else Rd.udw = Rs1.udw / Rs2_or_imm13;
@@ -143,7 +143,7 @@ decode OP default Unknown::unknown()
if(Rs2_or_imm13 == 0) fault = new DivisionByZero;
else
{
- Rd.udw = ((YValue << 32) | Rs1.udw<31:0>) / Rs2_or_imm13;
+ Rd.udw = ((Y << 32) | Rs1.udw<31:0>) / Rs2_or_imm13;
if(Rd.udw >> 32 != 0)
Rd.udw = 0xFFFFFFFF;
}
@@ -153,7 +153,7 @@ decode OP default Unknown::unknown()
fault = new DivisionByZero;
else
{
- Rd.udw = ((int64_t)((YValue << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw;
+ Rd.udw = ((int64_t)((Y << 32) | Rs1.sdw<31:0>)) / Rs2_or_imm13.sdw;
if(Rd.udw<63:31> != 0)
Rd.udw = 0x7FFFFFFF;
else if(Rd.udw<63:> && Rd.udw<62:31> != 0xFFFFFFFF)
@@ -187,7 +187,7 @@ decode OP default Unknown::unknown()
0x17: IntOpCcRes::xnorcc({{Rd = ~(Rs1 ^ Rs2_or_imm13);}});
0x18: addccc({{
int64_t resTemp, val2 = Rs2_or_imm13;
- int64_t carryin = CcrIccC;
+ int64_t carryin = Ccr<0:0>;
Rd = resTemp = Rs1 + val2 + carryin;}},
{{(Rs1<31:0> + val2<31:0> + carryin)<32:>}},
{{Rs1<31:> == val2<31:> && val2<31:> != resTemp<31:>}},
@@ -198,16 +198,16 @@ decode OP default Unknown::unknown()
0x1A: umulcc({{
uint64_t resTemp;
Rd = resTemp = Rs1.udw<31:0> * Rs2_or_imm13.udw<31:0>;
- YValue = resTemp<63:32>;}},
+ Y = resTemp<63:32>;}},
{{0}},{{0}},{{0}},{{0}});
0x1B: smulcc({{
int64_t resTemp;
Rd = resTemp = Rs1.sdw<31:0> * Rs2_or_imm13.sdw<31:0>;
- YValue = resTemp<63:32>;}},
+ Y = resTemp<63:32>;}},
{{0}},{{0}},{{0}},{{0}});
0x1C: subccc({{
int64_t resTemp, val2 = Rs2_or_imm13;
- int64_t carryin = CcrIccC;
+ int64_t carryin = Ccr<0:0>;
Rd = resTemp = Rs1 + ~(val2 + carryin) + 1;}},
{{(~((Rs1<31:0> + (~(val2 + carryin))<31:0> + 1))<32:>)}},
{{Rs1<31:> != val2<31:> && Rs1<31:> != resTemp<31:>}},
@@ -224,7 +224,7 @@ decode OP default Unknown::unknown()
if(val2 == 0) fault = new DivisionByZero;
else
{
- resTemp = (uint64_t)((YValue << 32) | Rs1.udw<31:0>) / val2;
+ resTemp = (uint64_t)((Y << 32) | Rs1.udw<31:0>) / val2;
overflow = (resTemp<63:32> != 0);
if(overflow) Rd = resTemp = 0xFFFFFFFF;
else Rd = resTemp;
@@ -240,7 +240,7 @@ decode OP default Unknown::unknown()
if(val2 == 0) fault = new DivisionByZero;
else
{
- Rd = resTemp = (int64_t)((YValue << 32) | Rs1.sdw<31:0>) / val2;
+ Rd = resTemp = (int64_t)((Y << 32) | Rs1.sdw<31:0>) / val2;
overflow = (resTemp<63:31> != 0);
underflow = (resTemp<63:> && resTemp<62:31> != 0xFFFFFFFF);
if(overflow) Rd = resTemp = 0x7FFFFFFF;
@@ -295,12 +295,12 @@ decode OP default Unknown::unknown()
int32_t multiplier = Rs1<31:0>;
int32_t savedLSB = Rs1<0:>;
multiplier = multiplier<31:1> |
- ((CcrIccN
- ^ CcrIccV) << 32);
- if(!YValue<0:>)
+ ((Ccr<3:3>
+ ^ Ccr<1:1>) << 32);
+ if(!Y<0:>)
multiplicand = 0;
Rd = resTemp = multiplicand + multiplier;
- YValue = YValue<31:1> | (savedLSB << 31);}},
+ Y = Y<31:1> | (savedLSB << 31);}},
{{((multiplicand & 0xFFFFFFFF + multiplier & 0xFFFFFFFF) >> 31)}},
{{multiplicand<31:> == multiplier<31:> && multiplier<31:> != resTemp<31:>}},
{{((multiplicand >> 1) + (multiplier >> 1) + (multiplicand & multiplier & 0x1))<63:>}},
@@ -321,56 +321,27 @@ decode OP default Unknown::unknown()
0x0: sra({{Rd = Rs1.sw >> (I ? SHCNT32 : Rs2<4:0>);}});
0x1: srax({{Rd = Rs1.sdw >> (I ? SHCNT64 : Rs2<5:0>);}});
}
- 0x28: decode RS1 {
- 0x0: rdy({{Rd = YValue;}});
- 0x2: rdccr({{Rd = Ccr;}});
- 0x3: rdasi({{Rd = Asi;}});
- 0x4: PrivTick::rdtick({{Rd = Tick;}});
- 0x5: rdpc({{Rd = xc->readPC();}});
- 0x6: rdfprs({{Rd = Fprs;}});
- 0xF: decode I {
- 0x0: Nop::membar({{/*Membar isn't needed yet*/}});
- 0x1: Nop::stbar({{/*Stbar isn't needed yet*/}});
- }
- }
- 0x2A: decode RS1 {
- format Priv
- {
- 0x0: rdprtpc({{
- Rd = xc->readMiscReg(MISCREG_TPC_BASE + Tl);
- }});
- 0x1: rdprtnpc({{
- Rd = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
- }});
- 0x2: rdprtstate({{
- Rd = xc->readMiscReg(MISCREG_TSTATE_BASE + Tl);
- }});
- 0x3: rdprtt({{
- Rd = xc->readMiscReg(MISCREG_TT_BASE + Tl);
- }});
- 0x4: rdprtick({{Rd = Tick;}});
- 0x5: rdprtba({{Rd = Tba;}});
- 0x6: rdprpstate({{Rd = Pstate;}});
- 0x7: rdprtl({{Rd = Tl;}});
- 0x8: rdprpil({{Rd = Pil;}});
- 0x9: rdprcwp({{Rd = Cwp;}});
- 0xA: rdprcansave({{Rd = Cansave;}});
- 0xB: rdprcanrestore({{Rd = Canrestore;}});
- 0xC: rdprcleanwin({{Rd = Cleanwin;}});
- 0xD: rdprotherwin({{Rd = Otherwin;}});
- 0xE: rdprwstate({{Rd = Wstate;}});
- }
- //The floating point queue isn't implemented right now.
- 0xF: Trap::rdprfq({{fault = new IllegalInstruction;}});
- 0x1F: Priv::rdprver({{Rd = Ver;}});
- }
+ // XXX might want a format rdipr thing here
+ 0x28: rdasr({{
+ Rd = xc->readMiscRegWithEffect(RS1 + AsrStart, fault);
+ }});
+ 0x29: rdhpr({{
+ // XXX Need to protect with format that traps non-priv/priv
+ // access
+ Rd = xc->readMiscRegWithEffect(RS1 + HprStart, fault);
+ }});
+ 0x2A: rdpr({{
+ // XXX Need to protect with format that traps non-priv
+ // access
+ Rd = xc->readMiscRegWithEffect(RS1 + PrStart, fault);
+ }});
0x2B: BasicOperate::flushw({{
if(NWindows - 2 - Cansave == 0)
{
if(Otherwin)
- fault = new SpillNOther(WstateOther);
+ fault = new SpillNOther(Wstate<5:3>);
else
- fault = new SpillNNormal(WstateNormal);
+ fault = new SpillNNormal(Wstate<2:0>);
}
}});
0x2C: decode MOVCC3
@@ -379,13 +350,13 @@ decode OP default Unknown::unknown()
0x1: decode CC
{
0x0: movcci({{
- if(passesCondition(CcrIcc, COND4))
+ if(passesCondition(Ccr<3:0>, COND4))
Rd = Rs2_or_imm11;
else
Rd = Rd;
}});
0x2: movccx({{
- if(passesCondition(CcrXcc, COND4))
+ if(passesCondition(Ccr<7:4>, COND4))
Rd = Rs2_or_imm11;
else
Rd = Rd;
@@ -419,49 +390,23 @@ decode OP default Unknown::unknown()
0x6: movrg({{Rd = (Rs1.sdw > 0) ? Rs2_or_imm10 : Rd;}});
0x7: movrge({{Rd = (Rs1.sdw >= 0) ? Rs2_or_imm10 : Rd;}});
}
- 0x30: decode RD {
- 0x0: wry({{Y = Rs1 ^ Rs2_or_imm13;}});
- 0x2: wrccr({{Ccr = Rs1 ^ Rs2_or_imm13;}});
- 0x3: wrasi({{Asi = Rs1 ^ Rs2_or_imm13;}});
- 0x6: wrfprs({{Asi = Rs1 ^ Rs2_or_imm13;}});
- 0xF: Trap::sir({{fault = new SoftwareInitiatedReset;}});
- }
+ 0x30: wrasr({{
+ xc->setMiscRegWithEffect(RD + AsrStart, Rs1 ^ Rs2_or_imm13);
+ }});
0x31: decode FCN {
0x0: BasicOperate::saved({{/*Boogy Boogy*/}});
0x1: BasicOperate::restored({{/*Boogy Boogy*/}});
}
- 0x32: decode RD {
- format Priv
- {
- 0x0: wrprtpc({{
- xc->setMiscReg(MISCREG_TPC_BASE + Tl,
- Rs1 ^ Rs2_or_imm13);
- }});
- 0x1: wrprtnpc({{
- xc->setMiscReg(MISCREG_TNPC_BASE + Tl,
- Rs1 ^ Rs2_or_imm13);
- }});
- 0x2: wrprtstate({{
- xc->setMiscReg(MISCREG_TSTATE_BASE + Tl,
- Rs1 ^ Rs2_or_imm13);
- }});
- 0x3: wrprtt({{
- xc->setMiscReg(MISCREG_TT_BASE + Tl,
- Rs1 ^ Rs2_or_imm13);
- }});
- 0x4: wrprtick({{Tick = Rs1 ^ Rs2_or_imm13;}});
- 0x5: wrprtba({{Tba = Rs1 ^ Rs2_or_imm13;}});
- 0x6: wrprpstate({{Pstate = Rs1 ^ Rs2_or_imm13;}});
- 0x7: wrprtl({{Tl = Rs1 ^ Rs2_or_imm13;}});
- 0x8: wrprpil({{Pil = Rs1 ^ Rs2_or_imm13;}});
- 0x9: wrprcwp({{Cwp = Rs1 ^ Rs2_or_imm13;}});
- 0xA: wrprcansave({{Cansave = Rs1 ^ Rs2_or_imm13;}});
- 0xB: wrprcanrestore({{Canrestore = Rs1 ^ Rs2_or_imm13;}});
- 0xC: wrprcleanwin({{Cleanwin = Rs1 ^ Rs2_or_imm13;}});
- 0xD: wrprotherwin({{Otherwin = Rs1 ^ Rs2_or_imm13;}});
- 0xE: wrprwstate({{Wstate = Rs1 ^ Rs2_or_imm13;}});
- }
- }
+ 0x32: wrpr({{
+ // XXX Need to protect with format that traps non-priv
+ // access
+ xc->setMiscRegWithEffect(RD + PrStart, Rs1 ^ Rs2_or_imm13);
+ }});
+ 0x33: wrhpr({{
+ // XXX Need to protect with format that traps non-priv/priv
+ // access
+ xc->setMiscRegWithEffect(RD + HprStart, Rs1 ^ Rs2_or_imm13);
+ }});
0x34: Trap::fpop1({{fault = new FpDisabled;}});
0x35: Trap::fpop2({{fault = new FpDisabled;}});
0x38: Branch::jmpl({{
@@ -492,9 +437,9 @@ decode OP default Unknown::unknown()
if(Canrestore == 0)
{
if(Otherwin)
- fault = new FillNOther(WstateOther);
+ fault = new FillNOther(Wstate<5:3>);
else
- fault = new FillNNormal(WstateNormal);
+ fault = new FillNNormal(Wstate<2:0>);
}
else
{
@@ -511,7 +456,7 @@ decode OP default Unknown::unknown()
0x3A: decode CC
{
0x0: Trap::tcci({{
- if(passesCondition(CcrIcc, COND2))
+ if(passesCondition(Ccr<3:0>, COND2))
{
int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2);
DPRINTF(Sparc, "The trap number is %d\n", lTrapNum);
@@ -524,7 +469,7 @@ decode OP default Unknown::unknown()
}
}});
0x2: Trap::tccx({{
- if(passesCondition(CcrXcc, COND2))
+ if(passesCondition(Ccr<7:4>, COND2))
{
int lTrapNum = I ? (Rs1 + SW_TRAP) : (Rs1 + Rs2);
DPRINTF(Sparc, "The trap number is %d\n", lTrapNum);
@@ -545,9 +490,9 @@ decode OP default Unknown::unknown()
if(Cansave == 0)
{
if(Otherwin)
- fault = new SpillNOther(WstateOther);
+ fault = new SpillNOther(Wstate<5:3>);
else
- fault = new SpillNNormal(WstateNormal);
+ fault = new SpillNNormal(Wstate<2:0>);
Cwp = (Cwp + 2) % NWindows;
}
else if(Cleanwin - Canrestore == 0)
@@ -575,9 +520,9 @@ decode OP default Unknown::unknown()
if(Canrestore == 0)
{
if(Otherwin)
- fault = new FillNOther(WstateOther);
+ fault = new FillNOther(Wstate<5:3>);
else
- fault = new FillNNormal(WstateNormal);
+ fault = new FillNNormal(Wstate<2:0>);
}
else
{
@@ -594,23 +539,26 @@ decode OP default Unknown::unknown()
0x0: Priv::done({{
if(Tl == 0)
return new IllegalInstruction;
- Cwp = xc->readMiscReg(MISCREG_TSTATE_CWP_BASE + Tl);
- Asi = xc->readMiscReg(MISCREG_TSTATE_ASI_BASE + Tl);
- Ccr = xc->readMiscReg(MISCREG_TSTATE_CCR_BASE + Tl);
- Pstate = xc->readMiscReg(MISCREG_TSTATE_PSTATE_BASE + Tl);
- NPC = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
- NNPC = NPC + 4;
+
+ Cwp = Tstate<4:0>;
+ Pstate = Tstate<20:8>;
+ Asi = Tstate<31:24>;
+ Ccr = Tstate<39:32>;
+ Gl = Tstate<42:40>;
+ NPC = Tnpc;
+ NNPC = Tnpc + 4;
Tl = Tl - 1;
}});
0x1: BasicOperate::retry({{
if(Tl == 0)
return new IllegalInstruction;
- Cwp = xc->readMiscReg(MISCREG_TSTATE_CWP_BASE + Tl);
- Asi = xc->readMiscReg(MISCREG_TSTATE_ASI_BASE + Tl);
- Ccr = xc->readMiscReg(MISCREG_TSTATE_CCR_BASE + Tl);
- Pstate = xc->readMiscReg(MISCREG_TSTATE_PSTATE_BASE + Tl);
- NPC = xc->readMiscReg(MISCREG_TPC_BASE + Tl);
- NNPC = xc->readMiscReg(MISCREG_TNPC_BASE + Tl);
+ Cwp = Tstate<4:0>;
+ Pstate = Tstate<20:8>;
+ Asi = Tstate<31:24>;
+ Ccr = Tstate<39:32>;
+ Gl = Tstate<42:40>;
+ NPC = Tpc;
+ NNPC = Tnpc + 4;
Tl = Tl - 1;
}});
}
diff --git a/src/arch/sparc/isa/formats/integerop.isa b/src/arch/sparc/isa/formats/integerop.isa
index 1fd87b1d3..1894ce541 100644
--- a/src/arch/sparc/isa/formats/integerop.isa
+++ b/src/arch/sparc/isa/formats/integerop.isa
@@ -316,22 +316,38 @@ let {{
return (header_output, decoder_output, exec_output, decode_block)
calcCcCode = '''
- CcrIccN = (Rd >> 31) & 1;
- CcrIccZ = ((Rd & 0xFFFFFFFF) == 0);
- CcrXccN = (Rd >> 63) & 1;
- CcrXccZ = (Rd == 0);
- CcrIccV = %(ivValue)s;
- CcrIccC = %(icValue)s;
- CcrXccV = %(xvValue)s;
- CcrXccC = %(xcValue)s;
- DPRINTF(Sparc, "in = %%d\\n", CcrIccN);
- DPRINTF(Sparc, "iz = %%d\\n", CcrIccZ);
- DPRINTF(Sparc, "xn = %%d\\n", CcrXccN);
- DPRINTF(Sparc, "xz = %%d\\n", CcrXccZ);
- DPRINTF(Sparc, "iv = %%d\\n", CcrIccV);
- DPRINTF(Sparc, "ic = %%d\\n", CcrIccC);
- DPRINTF(Sparc, "xv = %%d\\n", CcrXccV);
- DPRINTF(Sparc, "xc = %%d\\n", CcrXccC);
+ uint8_t tmp_ccriccc;
+ uint8_t tmp_ccriccv;
+ uint8_t tmp_ccriccz;
+ uint8_t tmp_ccriccn;
+ uint8_t tmp_ccrxccc;
+ uint8_t tmp_ccrxccv;
+ uint8_t tmp_ccrxccz;
+ uint8_t tmp_ccrxccn;
+
+ tmp_ccriccn = (Rd >> 31) & 1;
+ tmp_ccriccz = ((Rd & 0xFFFFFFFF) == 0);
+ tmp_ccrxccn = (Rd >> 63) & 1;
+ tmp_ccrxccz = (Rd == 0);
+ tmp_ccriccv = %(ivValue)s & 1;
+ tmp_ccriccc = %(icValue)s & 1;
+ tmp_ccrxccv = %(xvValue)s & 1;
+ tmp_ccrxccc = %(xcValue)s & 1;
+
+ Ccr = tmp_ccriccc | tmp_ccriccv << 1 |
+ tmp_ccriccz << 2 | tmp_ccriccn << 3|
+ tmp_ccrxccc << 4 | tmp_ccrxccv << 5|
+ tmp_ccrxccz << 6| tmp_ccrxccn << 7;
+
+
+ DPRINTF(Sparc, "in = %%d\\n", (uint16_t)tmp_ccriccn);
+ DPRINTF(Sparc, "iz = %%d\\n", (uint16_t)tmp_ccriccz);
+ DPRINTF(Sparc, "xn = %%d\\n", (uint16_t)tmp_ccrxccn);
+ DPRINTF(Sparc, "xz = %%d\\n", (uint16_t)tmp_ccrxccz);
+ DPRINTF(Sparc, "iv = %%d\\n", (uint16_t)tmp_ccriccv);
+ DPRINTF(Sparc, "ic = %%d\\n", (uint16_t)tmp_ccriccc);
+ DPRINTF(Sparc, "xv = %%d\\n", (uint16_t)tmp_ccrxccv);
+ DPRINTF(Sparc, "xc = %%d\\n", (uint16_t)tmp_ccrxccc);
'''
}};
diff --git a/src/arch/sparc/isa/formats/priv.isa b/src/arch/sparc/isa/formats/priv.isa
index a8de22c0e..7df59d736 100644
--- a/src/arch/sparc/isa/formats/priv.isa
+++ b/src/arch/sparc/isa/formats/priv.isa
@@ -51,23 +51,6 @@ output header {{
};
/**
- * Base class for user mode "tick" access.
- */
- class PrivTick : public SparcStaticInst
- {
- protected:
- // Constructor
- PrivTick(const char *mnem, ExtMachInst _machInst,
- OpClass __opClass) :
- SparcStaticInst(mnem, _machInst, __opClass)
- {
- }
-
- std::string generateDisassembly(Addr pc,
- const SymbolTable *symtab) const;
- };
-
- /**
* Base class for privelege mode operations with immediates.
*/
class PrivImm : public Priv
@@ -83,21 +66,6 @@ output header {{
int32_t imm;
};
- /**
- * Base class for user mode "tick" access with immediates.
- */
- class PrivTickImm : public PrivTick
- {
- protected:
- // Constructor
- PrivTickImm(const char *mnem, ExtMachInst _machInst,
- OpClass __opClass) :
- PrivTick(mnem, _machInst, __opClass), imm(SIMM13)
- {
- }
-
- int32_t imm;
- };
}};
output decoder {{
@@ -106,12 +74,6 @@ output decoder {{
{
return "Privileged Instruction";
}
-
- std::string PrivTick::generateDisassembly(Addr pc,
- const SymbolTable *symtab) const
- {
- return "Regular access to Tick";
- }
}};
def template PrivExecute {{
@@ -154,16 +116,10 @@ let {{
// Primary format for integer operate instructions:
def format Priv(code, *opt_flags) {{
- checkCode = "(!PstatePriv)"
+ checkCode = "((xc->readMiscReg(PrStart + MISCREG_PSTATE))<2:2>)"
(header_output, decoder_output,
exec_output, decode_block) = doPrivFormat(code,
checkCode, name, Name, opt_flags)
}};
-// Primary format for integer operate instructions:
-def format PrivTick(code, *opt_flags) {{
- checkCode = "(!PstatePriv && TickNpt)"
- (header_output, decoder_output,
- exec_output, decode_block) = doPrivFormat(code,
- checkCode, name, Name, opt_flags)
-}};
+
diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa
index 762de243a..40afb3722 100644
--- a/src/arch/sparc/isa/includes.isa
+++ b/src/arch/sparc/isa/includes.isa
@@ -48,7 +48,7 @@ output header {{
output decoder {{
#include "base/cprintf.hh"
#include "base/loader/symtab.hh"
-#include "cpu/exec_context.hh" // for Jump::branchTarget()
+#include "cpu/thread_context.hh" // for Jump::branchTarget()
#include <math.h>
#if defined(linux)
diff --git a/src/arch/sparc/isa/main.isa b/src/arch/sparc/isa/main.isa
index 35167d6b7..14acf54fa 100644
--- a/src/arch/sparc/isa/main.isa
+++ b/src/arch/sparc/isa/main.isa
@@ -25,7 +25,16 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (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
+
+////////////////////////////////////////////////////////////////////
+//
+// SPARC ISA description file.
+//
+////////////////////////////////////////////////////////////////////
+//Include the C++ include directives
##include "includes.isa"
////////////////////////////////////////////////////////////////////
diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa
index a89034e30..9e5c783e8 100644
--- a/src/arch/sparc/isa/operands.isa
+++ b/src/arch/sparc/isa/operands.isa
@@ -63,83 +63,26 @@ def operands {{
'R1': ('IntReg', 'udw', '1', None, 7),
'R15': ('IntReg', 'udw', '15', 'IsInteger', 8),
'R16': ('IntReg', 'udw', '16', None, 9),
+
# Control registers
- 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 1),
- 'PstateAg': ('ControlReg', 'udw', 'MISCREG_PSTATE_AG', None, 2),
- 'PstateIe': ('ControlReg', 'udw', 'MISCREG_PSTATE_IE', None, 3),
- 'PstatePriv': ('ControlReg', 'udw', 'MISCREG_PSTATE_PRIV', None, 4),
- 'PstateAm': ('ControlReg', 'udw', 'MISCREG_PSTATE_AM', None, 5),
- 'PstatePef': ('ControlReg', 'udw', 'MISCREG_PSTATE_PEF', None, 6),
- 'PstateRed': ('ControlReg', 'udw', 'MISCREG_PSTATE_RED', None, 7),
- 'PstateMm': ('ControlReg', 'udw', 'MISCREG_PSTATE_MM', None, 8),
- 'PstateTle': ('ControlReg', 'udw', 'MISCREG_PSTATE_TLE', None, 9),
- 'PstateCle': ('ControlReg', 'udw', 'MISCREG_PSTATE_CLE', None, 10),
- 'Tba': ('ControlReg', 'udw', 'MISCREG_TBA', None, 11),
'Y': ('ControlReg', 'udw', 'MISCREG_Y', None, 12),
- 'YValue': ('ControlReg', 'udw', 'MISCREG_Y_VALUE', None, 13),
- 'Pil': ('ControlReg', 'udw', 'MISCREG_PIL', None, 14),
- 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 15),
- #'Tt': ('ControlReg', 'udw', 'MISCREG_TT_BASE + tl', None, 16),
'Ccr': ('ControlReg', 'udw', 'MISCREG_CCR', None, 17),
- 'CcrIcc': ('ControlReg', 'udw', 'MISCREG_CCR_ICC', None, 18),
- 'CcrIccC': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_C', None, 19),
- 'CcrIccV': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_V', None, 20),
- 'CcrIccZ': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_Z', None, 21),
- 'CcrIccN': ('ControlReg', 'udw', 'MISCREG_CCR_ICC_N', None, 22),
- 'CcrXcc': ('ControlReg', 'udw', 'MISCREG_CCR_XCC', None, 23),
- 'CcrXccC': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_C', None, 22),
- 'CcrXccV': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_V', None, 23),
- 'CcrXccZ': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_Z', None, 24),
- 'CcrXccN': ('ControlReg', 'udw', 'MISCREG_CCR_XCC_N', None, 25),
'Asi': ('ControlReg', 'udw', 'MISCREG_ASI', None, 26),
+
+ 'Tpc': ('ControlReg', 'udw', 'MISCREG_TPC', None, 28),
+ 'Tnpc': ('ControlReg', 'udw', 'MISCREG_TNPC', None, 28),
+ 'Tstate': ('ControlReg', 'udw', 'MISCREG_TSTATE', None, 28),
+ 'Pstate': ('ControlReg', 'udw', 'MISCREG_PSTATE', None, 1),
'Tl': ('ControlReg', 'udw', 'MISCREG_TL', None, 27),
- #'Tpc': ('ControlReg', 'udw', 'MISCREG_TPC', None, 28),
- 'Tick': ('ControlReg', 'udw', 'MISCREG_TICK', None, 29),
- 'TickCounter': ('ControlReg', 'udw', 'MISCREG_TICK_COUNTER', None, 32),
- 'TickNpt': ('ControlReg', 'udw', 'MISCREG_TICK_NPT', None, 33),
+
+ 'Cwp': ('ControlReg', 'udw', 'MISCREG_CWP', None, 15),
'Cansave': ('ControlReg', 'udw', 'MISCREG_CANSAVE', None, 34),
'Canrestore': ('ControlReg', 'udw', 'MISCREG_CANRESTORE', None, 35),
- 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 36),
'Cleanwin': ('ControlReg', 'udw', 'MISCREG_CLEANWIN', None, 37),
+ 'Otherwin': ('ControlReg', 'udw', 'MISCREG_OTHERWIN', None, 36),
'Wstate': ('ControlReg', 'udw', 'MISCREG_WSTATE', None, 38),
- 'WstateNormal': ('ControlReg', 'udw', 'MISCREG_WSTATE_NORMAL', None,39),
- 'WstateOther': ('ControlReg', 'udw', 'MISCREG_WSTATE_OTHER', None, 40),
- 'Ver': ('ControlReg', 'udw', 'MISCREG_VER', None, 41),
- 'VerMaxwin': ('ControlReg', 'udw', 'MISCREG_VER_MAXWIN', None, 42),
- 'VerMaxtl': ('ControlReg', 'udw', 'MISCREG_VER_MAXTL', None, 43),
- 'VerMask': ('ControlReg', 'udw', 'MISCREG_VER_MASK', None, 44),
- 'VerImpl': ('ControlReg', 'udw', 'MISCREG_VER_MASK', None, 45),
- 'VerManuf': ('ControlReg', 'udw', 'MISCREG_VER_MANUF', None, 46),
- 'Fsr': ('ControlReg', 'udw', 'MISCREG_FSR', None, 47),
- 'FsrCexc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC', None, 48),
- 'FsrCexcNxc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_NXC', None, 49),
- 'FsrCexcDzc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_DZC', None, 50),
- 'FsrCexcUfc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_UFC', None, 51),
- 'FsrCexcOfc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_OFC', None, 52),
- 'FsrCexcNvc': ('ControlReg', 'udw', 'MISCREG_FSR_CEXC_NVC', None, 53),
- 'FsrAexc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC', None, 54),
- 'FsrAexcNxc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_NXC', None, 55),
- 'FsrAexcDzc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_DZC', None, 56),
- 'FsrAexcUfc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_UFC', None, 57),
- 'FsrAexcOfc': ('ControlReg', 'udw', 'MISCREG_FSR_AEXC_OFC', None, 58),
- 'FsrAexcNvc': ('ControlReg', 'udw', 'MISCREC_FSR_AEXC_NVC', None, 59),
- 'FsrFcc0': ('ControlReg', 'udw', 'MISCREG_FSR_FCC0', None, 60),
- 'FsrQne': ('ControlReg', 'udw', 'MISCREG_FSR_QNE', None, 61),
- 'FsrFtt': ('ControlReg', 'udw', 'MISCREG_FSR_FTT', None, 62),
- 'FsrVer': ('ControlReg', 'udw', 'MISCREG_FSR_VER', None, 63),
- 'FsrNs': ('ControlReg', 'udw', 'MISCREG_FSR_NS', None, 64),
- 'FsrTem': ('ControlReg', 'udw', 'MISCREG_FSR_TEM', None, 65),
- 'FsrTemNxm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_NXM', None, 66),
- 'FsrTemDzm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_DZM', None, 67),
- 'FsrTemUfm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_UFM', None, 68),
- 'FsrTemOfm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_OFM', None, 69),
- 'FsrTemNvm': ('ControlReg', 'udw', 'MISCREG_FSR_TEM_NVM', None, 70),
- 'FsrRd': ('ControlReg', 'udw', 'MISCREG_FSR_RD', None, 71),
- 'FsrFcc1': ('ControlReg', 'udw', 'MISCREG_FSR_FCC1', None, 72),
- 'FsrFcc2': ('ControlReg', 'udw', 'MISCREG_FSR_FCC2', None, 73),
- 'FsrFcc3': ('ControlReg', 'udw', 'MISCREG_FSR_FCC3', None, 74),
- 'Fprs': ('ControlReg', 'udw', 'MISCREG_FPRS', None, 75),
- 'FprsDl': ('ControlReg', 'udw', 'MISCREG_FPRS_DL', None, 76),
- 'FprsDu': ('ControlReg', 'udw', 'MISCREG_FPRS_DU', None, 77),
- 'FprsFef': ('ControlReg', 'udw', 'MISCREG_FPRS_FEF', None, 78)
+ 'Gl': ('ControlReg', 'udw', 'MISCREG_GL', None, 12),
+
+ 'Fsr': ('ControlReg', 'udw', 'MISCREG_FSR', None, 47)
+
}};
diff --git a/src/arch/sparc/isa_traits.hh b/src/arch/sparc/isa_traits.hh
index 453d14664..346f7b730 100644
--- a/src/arch/sparc/isa_traits.hh
+++ b/src/arch/sparc/isa_traits.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Gabe Black
*/
#ifndef __ARCH_SPARC_ISA_TRAITS_HH__
@@ -33,7 +36,7 @@
#include "config/full_system.hh"
#include "sim/host.hh"
-class ExecContext;
+class ThreadContext;
class FastCPU;
//class FullCPU;
class Checkpoint;
@@ -80,6 +83,9 @@ class SyscallReturn
#endif
+#if FULL_SYSTEM
+#include "arch/sparc/isa_fullsys_traits.hh"
+#endif
namespace SparcISA
{
@@ -172,12 +178,12 @@ namespace SparcISA
// indicate success/failure in reg the carry bit of the ccr
// and put the return value itself in the standard return value reg ().
if (return_value.successful()) {
- // no error
- regs->setMiscReg(MISCREG_CCR_XCC_C, 0);
+ // no error, clear XCC.C
+ regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) & 0xEF);
regs->setIntReg(ReturnValueReg, return_value.value());
} else {
- // got an error, return details
- regs->setMiscReg(MISCREG_CCR_XCC_C, 1);
+ // got an error, set XCC.C
+ regs->setMiscReg(MISCREG_CCR, regs->readMiscReg(MISCREG_CCR) | 0x10);
regs->setIntReg(ReturnValueReg, return_value.value());
}
}
diff --git a/src/arch/sparc/linux/linux.cc b/src/arch/sparc/linux/linux.cc
index c7ed29358..ae6ffbc2a 100644
--- a/src/arch/sparc/linux/linux.cc
+++ b/src/arch/sparc/linux/linux.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/sparc/linux/linux.hh"
diff --git a/src/arch/sparc/linux/linux.hh b/src/arch/sparc/linux/linux.hh
index 9cde5bb9c..926c2cb77 100644
--- a/src/arch/sparc/linux/linux.hh
+++ b/src/arch/sparc/linux/linux.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_LINUX_LINUX_HH__
diff --git a/src/arch/sparc/linux/process.cc b/src/arch/sparc/linux/process.cc
index 71be6a83a..e27255e67 100644
--- a/src/arch/sparc/linux/process.cc
+++ b/src/arch/sparc/linux/process.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/sparc/isa_traits.hh"
@@ -31,7 +35,7 @@
#include "arch/sparc/regfile.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/linux/linux.hh"
#include "sim/process.hh"
@@ -44,9 +48,9 @@ using namespace SparcISA;
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<Linux::utsname> name(xc->getSyscallArg(0));
+ TypedBufferArg<Linux::utsname> name(tc->getSyscallArg(0));
strcpy(name->sysname, "Linux");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -54,40 +58,40 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
strcpy(name->version, "#1 Mon Aug 18 11:32:15 EDT 2003");
strcpy(name->machine, "sparc");
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
SyscallReturn SparcISA::getresuidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc)
+ Process *p, ThreadContext *tc)
{
const IntReg id = htog(100);
- Addr ruid = xc->getSyscallArg(0);
- Addr euid = xc->getSyscallArg(1);
- Addr suid = xc->getSyscallArg(2);
+ Addr ruid = tc->getSyscallArg(0);
+ Addr euid = tc->getSyscallArg(1);
+ Addr suid = tc->getSyscallArg(2);
//Handle the EFAULT case
//Set the ruid
if(ruid)
{
BufferArg ruidBuff(ruid, sizeof(IntReg));
memcpy(ruidBuff.bufferPtr(), &id, sizeof(IntReg));
- ruidBuff.copyOut(xc->getMemPort());
+ ruidBuff.copyOut(tc->getMemPort());
}
//Set the euid
if(euid)
{
BufferArg euidBuff(euid, sizeof(IntReg));
memcpy(euidBuff.bufferPtr(), &id, sizeof(IntReg));
- euidBuff.copyOut(xc->getMemPort());
+ euidBuff.copyOut(tc->getMemPort());
}
//Set the suid
if(suid)
{
BufferArg suidBuff(suid, sizeof(IntReg));
memcpy(suidBuff.bufferPtr(), &id, sizeof(IntReg));
- suidBuff.copyOut(xc->getMemPort());
+ suidBuff.copyOut(tc->getMemPort());
}
return 0;
}
diff --git a/src/arch/sparc/linux/process.hh b/src/arch/sparc/linux/process.hh
index 23ce66d02..f4819ba84 100644
--- a/src/arch/sparc/linux/process.hh
+++ b/src/arch/sparc/linux/process.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __SPARC_LINUX_PROCESS_HH__
@@ -59,7 +61,7 @@ class SparcLinuxProcess : public SparcLiveProcess
};
SyscallReturn getresuidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
} // namespace SparcISA
#endif // __ALPHA_LINUX_PROCESS_HH__
diff --git a/src/arch/sparc/process.cc b/src/arch/sparc/process.cc
index 250c1bec4..75f01e038 100644
--- a/src/arch/sparc/process.cc
+++ b/src/arch/sparc/process.cc
@@ -24,60 +24,23 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/sparc/isa_traits.hh"
#include "arch/sparc/process.hh"
-#include "arch/sparc/linux/process.hh"
-#include "arch/sparc/solaris/process.hh"
#include "base/loader/object_file.hh"
#include "base/misc.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/page_table.hh"
#include "mem/translating_port.hh"
-#include "sim/builder.hh"
#include "sim/system.hh"
using namespace std;
using namespace SparcISA;
-SparcLiveProcess *
-SparcLiveProcess::create(const std::string &nm, System *system, int stdin_fd,
- int stdout_fd, int stderr_fd, std::string executable,
- std::vector<std::string> &argv, std::vector<std::string> &envp)
-{
- SparcLiveProcess *process = NULL;
-
- ObjectFile *objFile = createObjectFile(executable);
- if (objFile == NULL) {
- fatal("Can't load object file %s", executable);
- }
-
-
- if (objFile->getArch() != ObjectFile::SPARC)
- fatal("Object file with arch %x does not match architecture %x.",
- objFile->getArch(), ObjectFile::SPARC);
- switch (objFile->getOpSys()) {
- case ObjectFile::Linux:
- process = new SparcLinuxProcess(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
- break;
-
-
- case ObjectFile::Solaris:
- process = new SparcSolarisProcess(nm, objFile, system,
- stdin_fd, stdout_fd, stderr_fd,
- argv, envp);
- break;
- default:
- fatal("Unknown/unsupported operating system.");
- }
-
- if (process == NULL)
- fatal("Unknown error creating process object.");
- return process;
-}
SparcLiveProcess::SparcLiveProcess(const std::string &nm, ObjectFile *objFile,
System *_system, int stdin_fd, int stdout_fd, int stderr_fd,
@@ -110,36 +73,27 @@ SparcLiveProcess::startup()
//From the SPARC ABI
//The process runs in user mode
- execContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE_PRIV, 0);
- //Interrupts are enabled
- execContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE_IE, 1);
- //Round to nearest
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_RD, 0);
- //Floating point traps are not enabled
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_TEM, 0);
- //Turn non standard mode off
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_NS, 0);
- //The floating point queue is empty
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_QNE, 0);
- //There are no accrued eexecContext[0]eptions
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_AEXC, 0);
- //There are no current eexecContext[0]eptions
- execContexts[0]->setMiscRegWithEffect(MISCREG_FSR_CEXC, 0);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_PSTATE, 0x02);
+
+ //Setup default FP state
+ threadContexts[0]->setMiscReg(MISCREG_FSR, 0);
+ threadContexts[0]->setMiscReg(MISCREG_TICK, 0);
+ //
/*
* Register window management registers
*/
//No windows contain info from other programs
- execContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_OTHERWIN, 0);
//There are no windows to pop
- execContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_CANRESTORE, 0);
//All windows are available to save into
- execContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_CANSAVE, NWindows - 2);
//All windows are "clean"
- execContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_CLEANWIN, NWindows);
//Start with register window 0
- execContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0);
+ threadContexts[0]->setMiscRegWithEffect(MISCREG_CWP, 0);
}
m5_auxv_t buildAuxVect(int64_t type, int64_t val)
@@ -317,72 +271,14 @@ SparcLiveProcess::argsInit(int intSize, int pageSize)
initVirtMem->writeBlob(argc_base, (uint8_t*)&guestArgc, intSize);
- execContexts[0]->setIntReg(ArgumentReg0, argc);
- execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
- execContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
+ threadContexts[0]->setIntReg(ArgumentReg0, argc);
+ threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+ threadContexts[0]->setIntReg(StackPointerReg, stack_min - StackBias);
Addr prog_entry = objFile->entryPoint();
- execContexts[0]->setPC(prog_entry);
- execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
- execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ threadContexts[0]->setPC(prog_entry);
+ threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+ threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
// num_processes++;
}
-
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess)
-
- VectorParam<string> cmd;
- Param<string> executable;
- Param<string> input;
- Param<string> output;
- VectorParam<string> env;
- SimObjectParam<System *> system;
-
-END_DECLARE_SIM_OBJECT_PARAMS(SparcLiveProcess)
-
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess)
-
- INIT_PARAM(cmd, "command line (executable plus arguments)"),
- INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
- INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
- INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
- INIT_PARAM(env, "environment settings"),
- INIT_PARAM(system, "system")
-
-END_INIT_SIM_OBJECT_PARAMS(SparcLiveProcess)
-
-
-CREATE_SIM_OBJECT(SparcLiveProcess)
-{
- string in = input;
- string out = output;
-
- // initialize file descriptors to default: same as simulator
- int stdin_fd, stdout_fd, stderr_fd;
-
- if (in == "stdin" || in == "cin")
- stdin_fd = STDIN_FILENO;
- else
- stdin_fd = Process::openInputFile(input);
-
- if (out == "stdout" || out == "cout")
- stdout_fd = STDOUT_FILENO;
- else if (out == "stderr" || out == "cerr")
- stdout_fd = STDERR_FILENO;
- else
- stdout_fd = Process::openOutputFile(out);
-
- stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
-
- return SparcLiveProcess::create(getInstanceName(), system,
- stdin_fd, stdout_fd, stderr_fd,
- (string)executable == "" ? cmd[0] : executable,
- cmd, env);
-}
-
-
-REGISTER_SIM_OBJECT("SparcLiveProcess", SparcLiveProcess)
-
-
diff --git a/src/arch/sparc/process.hh b/src/arch/sparc/process.hh
index c177f20a5..7ba8d7109 100644
--- a/src/arch/sparc/process.hh
+++ b/src/arch/sparc/process.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __SPARC_PROCESS_HH__
@@ -62,15 +65,6 @@ class SparcLiveProcess : public LiveProcess
void startup();
public:
- // this function is used to create the LiveProcess object, since
- // we can't tell which subclass of LiveProcess to use until we
- // open and look at the object file.
- static SparcLiveProcess *create(const std::string &nm,
- System *_system,
- int stdin_fd, int stdout_fd, int stderr_fd,
- std::string executable,
- std::vector<std::string> &argv,
- std::vector<std::string> &envp);
void argsInit(int intSize, int pageSize);
diff --git a/src/arch/sparc/regfile.hh b/src/arch/sparc/regfile.hh
index 96f36eb91..cbeb3c7b9 100644
--- a/src/arch/sparc/regfile.hh
+++ b/src/arch/sparc/regfile.hh
@@ -24,14 +24,19 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __ARCH_SPARC_REGFILE_HH__
#define __ARCH_SPARC_REGFILE_HH__
+#include "arch/sparc/exceptions.hh"
#include "arch/sparc/faults.hh"
#include "base/trace.hh"
#include "sim/byteswap.hh"
+#include "cpu/cpuevent.hh"
#include "sim/host.hh"
class Checkpoint;
@@ -42,7 +47,7 @@ namespace SparcISA
typedef uint8_t RegIndex;
// MAXTL - maximum trap level
- const int MaxPTL = 6;
+ const int MaxPTL = 2;
const int MaxTL = 6;
const int MaxGL = 3;
const int MaxPGL = 2;
@@ -50,6 +55,14 @@ namespace SparcISA
// NWINDOWS - number of register windows, can be 3 to 32
const int NWindows = 32;
+
+ const int AsrStart = 0;
+ const int PrStart = 32;
+ const int HprStart = 64;
+ const int MiscStart = 96;
+
+ const uint64_t Bit64 = (1ULL << 63);
+
class IntRegFile
{
protected:
@@ -231,17 +244,22 @@ namespace SparcISA
//In each of these cases, we have to copy the value into a temporary
//variable. This is because we may otherwise try to access an
//unaligned portion of memory.
+
+ uint32_t result32;
+ uint64_t result64;
switch(width)
{
case SingleWidth:
- uint32_t result32 = gtoh((uint32_t)val);
+ result32 = gtoh((uint32_t)val);
memcpy(regSpace + 4 * floatReg, &result32, width);
+ break;
case DoubleWidth:
- uint64_t result64 = gtoh((uint64_t)val);
+ result64 = gtoh((uint64_t)val);
memcpy(regSpace + 4 * floatReg, &result64, width);
+ break;
case QuadWidth:
- uint64_t result128 = gtoh((uint64_t)val);
- memcpy(regSpace + 4 * floatReg, &result128, width);
+ panic("Quad width FP not implemented.");
+ break;
default:
panic("Attempted to read a %d bit floating point register!", width);
}
@@ -253,17 +271,21 @@ namespace SparcISA
//In each of these cases, we have to copy the value into a temporary
//variable. This is because we may otherwise try to access an
//unaligned portion of memory.
+ uint32_t result32;
+ uint64_t result64;
switch(width)
{
case SingleWidth:
- uint32_t result32 = gtoh((uint32_t)val);
+ result32 = gtoh((uint32_t)val);
memcpy(regSpace + 4 * floatReg, &result32, width);
+ break;
case DoubleWidth:
- uint64_t result64 = gtoh((uint64_t)val);
+ result64 = gtoh((uint64_t)val);
memcpy(regSpace + 4 * floatReg, &result64, width);
+ break;
case QuadWidth:
- uint64_t result128 = gtoh((uint64_t)val);
- memcpy(regSpace + 4 * floatReg, &result128, width);
+ panic("Quad width FP not implemented.");
+ break;
default:
panic("Attempted to read a %d bit floating point register!", width);
}
@@ -277,156 +299,83 @@ namespace SparcISA
enum MiscRegIndex
{
- MISCREG_PSTATE,
- MISCREG_PSTATE_AG,
- MISCREG_PSTATE_IE,
- MISCREG_PSTATE_PRIV,
- MISCREG_PSTATE_AM,
- MISCREG_PSTATE_PEF,
- MISCREG_PSTATE_RED,
- MISCREG_PSTATE_MM,
- MISCREG_PSTATE_TLE,
- MISCREG_PSTATE_CLE,
- MISCREG_TBA,
- MISCREG_Y,
- MISCREG_Y_VALUE,
- MISCREG_PIL,
- MISCREG_CWP,
- MISCREG_TT_BASE,
- MISCREG_TT_END = MISCREG_TT_BASE + MaxTL,
- MISCREG_CCR,
- MISCREG_CCR_ICC,
- MISCREG_CCR_ICC_C,
- MISCREG_CCR_ICC_V,
- MISCREG_CCR_ICC_Z,
- MISCREG_CCR_ICC_N,
- MISCREG_CCR_XCC,
- MISCREG_CCR_XCC_C,
- MISCREG_CCR_XCC_V,
- MISCREG_CCR_XCC_Z,
- MISCREG_CCR_XCC_N,
- MISCREG_ASI,
- MISCREG_TL,
- MISCREG_TPC_BASE,
- MISCREG_TPC_END = MISCREG_TPC_BASE + MaxTL,
- MISCREG_TNPC_BASE,
- MISCREG_TNPC_END = MISCREG_TNPC_BASE + MaxTL,
- MISCREG_TSTATE_BASE,
- MISCREG_TSTATE_END = MISCREG_TSTATE_BASE + MaxTL,
- MISCREG_TSTATE_CWP_BASE,
- MISCREG_TSTATE_CWP_END = MISCREG_TSTATE_CWP_BASE + MaxTL,
- MISCREG_TSTATE_PSTATE_BASE,
- MISCREG_TSTATE_PSTATE_END = MISCREG_TSTATE_PSTATE_BASE + MaxTL,
- MISCREG_TSTATE_ASI_BASE,
- MISCREG_TSTATE_ASI_END = MISCREG_TSTATE_ASI_BASE + MaxTL,
- MISCREG_TSTATE_CCR_BASE,
- MISCREG_TSTATE_CCR_END = MISCREG_TSTATE_CCR_BASE + MaxTL,
- MISCREG_TICK,
- MISCREG_TICK_COUNTER,
- MISCREG_TICK_NPT,
- MISCREG_CANSAVE,
- MISCREG_CANRESTORE,
- MISCREG_OTHERWIN,
- MISCREG_CLEANWIN,
- MISCREG_WSTATE,
- MISCREG_WSTATE_NORMAL,
- MISCREG_WSTATE_OTHER,
- MISCREG_VER,
- MISCREG_VER_MAXWIN,
- MISCREG_VER_MAXTL,
- MISCREG_VER_MASK,
- MISCREG_VER_IMPL,
- MISCREG_VER_MANUF,
- MISCREG_FSR,
- MISCREG_FSR_CEXC,
- MISCREG_FSR_CEXC_NXC,
- MISCREG_FSR_CEXC_DZC,
- MISCREG_FSR_CEXC_UFC,
- MISCREG_FSR_CEXC_OFC,
- MISCREG_FSR_CEXC_NVC,
- MISCREG_FSR_AEXC,
- MISCREG_FSR_AEXC_NXC,
- MISCREG_FSR_AEXC_DZC,
- MISCREG_FSR_AEXC_UFC,
- MISCREG_FSR_AEXC_OFC,
- MISCREG_FSR_AEXC_NVC,
- MISCREG_FSR_FCC0,
- MISCREG_FSR_QNE,
- MISCREG_FSR_FTT,
- MISCREG_FSR_VER,
- MISCREG_FSR_NS,
- MISCREG_FSR_TEM,
- MISCREG_FSR_TEM_NXM,
- MISCREG_FSR_TEM_DZM,
- MISCREG_FSR_TEM_UFM,
- MISCREG_FSR_TEM_OFM,
- MISCREG_FSR_TEM_NVM,
- MISCREG_FSR_RD,
- MISCREG_FSR_FCC1,
- MISCREG_FSR_FCC2,
- MISCREG_FSR_FCC3,
- MISCREG_FPRS,
- MISCREG_FPRS_DL,
- MISCREG_FPRS_DU,
- MISCREG_FPRS_FEF,
- numMiscRegs
+ /** Ancillary State Registers */
+ MISCREG_Y = AsrStart + 0,
+ MISCREG_CCR = AsrStart + 2,
+ MISCREG_ASI = AsrStart + 3,
+ MISCREG_TICK = AsrStart + 4,
+ MISCREG_PC = AsrStart + 5,
+ MISCREG_FPRS = AsrStart + 6,
+ MISCREG_PCR = AsrStart + 16,
+ MISCREG_PIC = AsrStart + 17,
+ MISCREG_GSR = AsrStart + 19,
+ MISCREG_SOFTINT_SET = AsrStart + 20,
+ MISCREG_SOFTINT_CLR = AsrStart + 21,
+ MISCREG_SOFTINT = AsrStart + 22,
+ MISCREG_TICK_CMPR = AsrStart + 23,
+ MISCREG_STICK = AsrStart + 24,
+ MISCREG_STICK_CMPR = AsrStart + 25,
+
+ /** Privilged Registers */
+ MISCREG_TPC = PrStart + 0,
+ MISCREG_TNPC = PrStart + 1,
+ MISCREG_TSTATE = PrStart + 2,
+ MISCREG_TT = PrStart + 3,
+ MISCREG_PRIVTICK = PrStart + 4,
+ MISCREG_TBA = PrStart + 5,
+ MISCREG_PSTATE = PrStart + 6,
+ MISCREG_TL = PrStart + 7,
+ MISCREG_PIL = PrStart + 8,
+ MISCREG_CWP = PrStart + 9,
+ MISCREG_CANSAVE = PrStart + 10,
+ MISCREG_CANRESTORE = PrStart + 11,
+ MISCREG_CLEANWIN = PrStart + 12,
+ MISCREG_OTHERWIN = PrStart + 13,
+ MISCREG_WSTATE = PrStart + 14,
+ MISCREG_GL = PrStart + 16,
+
+ /** Hyper privileged registers */
+ MISCREG_HPSTATE = HprStart + 0,
+ MISCREG_HTSTATE = HprStart + 1,
+ MISCREG_HINTP = HprStart + 3,
+ MISCREG_HTBA = HprStart + 5,
+ MISCREG_HVER = HprStart + 6,
+ MISCREG_STRAND_STS_REG = HprStart + 16,
+ MISCREG_HSTICK_CMPR = HprStart + 31,
+
+ /** Floating Point Status Register */
+ MISCREG_FSR = MiscStart + 0
+
};
// The control registers, broken out into fields
class MiscRegFile
{
private:
- union
- {
- uint16_t pstate; // Process State Register
- struct
- {
- uint16_t ag:1; // Alternate Globals
- uint16_t ie:1; // Interrupt enable
- uint16_t priv:1; // Privelege mode
- uint16_t am:1; // Address mask
- uint16_t pef:1; // PSTATE enable floating-point
- uint16_t red:1; // RED (reset, error, debug) state
- uint16_t mm:2; // Memory Model
- uint16_t tle:1; // Trap little-endian
- uint16_t cle:1; // Current little-endian
- } pstateFields;
- };
- uint64_t tba; // Trap Base Address
- union
- {
+
+ /* ASR Registers */
+ union {
uint64_t y; // Y (used in obsolete multiplication)
- struct
- {
+ struct {
uint64_t value:32; // The actual value stored in y
uint64_t :32; // reserved bits
} yFields;
};
- uint8_t pil; // Process Interrupt Register
- uint8_t cwp; // Current Window Pointer
- uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured
- // on the previous level)
- union
- {
+ union {
uint8_t ccr; // Condition Code Register
- struct
- {
- union
- {
+ struct {
+ union {
uint8_t icc:4; // 32-bit condition codes
- struct
- {
+ struct {
uint8_t c:1; // Carry
uint8_t v:1; // Overflow
uint8_t z:1; // Zero
uint8_t n:1; // Negative
} iccFields;
};
- union
- {
+ union {
uint8_t xcc:4; // 64-bit condition codes
- struct
- {
+ struct {
uint8_t c:1; // Carry
uint8_t v:1; // Overflow
uint8_t z:1; // Zero
@@ -436,73 +385,143 @@ namespace SparcISA
} ccrFields;
};
uint8_t asi; // Address Space Identifier
- uint8_t tl; // Trap Level
+ union {
+ uint64_t tick; // Hardware clock-tick counter
+ struct {
+ int64_t counter:63; // Clock-tick count
+ uint64_t npt:1; // Non-priveleged trap
+ } tickFields;
+ };
+ union {
+ uint8_t fprs; // Floating-Point Register State
+ struct {
+ uint8_t dl:1; // Dirty lower
+ uint8_t du:1; // Dirty upper
+ uint8_t fef:1; // FPRS enable floating-Point
+ } fprsFields;
+ };
+ union {
+ uint64_t softint;
+ struct {
+ uint64_t tm:1;
+ uint64_t int_level:14;
+ uint64_t sm:1;
+ } softintFields;
+ };
+ union {
+ uint64_t tick_cmpr; // Hardware tick compare registers
+ struct {
+ uint64_t tick_cmpr:63; // Clock-tick count
+ uint64_t int_dis:1; // Non-priveleged trap
+ } tick_cmprFields;
+ };
+ union {
+ uint64_t stick; // Hardware clock-tick counter
+ struct {
+ int64_t :63; // Not used, storage in SparcSystem
+ uint64_t npt:1; // Non-priveleged trap
+ } stickFields;
+ };
+ union {
+ uint64_t stick_cmpr; // Hardware tick compare registers
+ struct {
+ uint64_t tick_cmpr:63; // Clock-tick count
+ uint64_t int_dis:1; // Non-priveleged trap
+ } stick_cmprFields;
+ };
+
+
+ /* Privileged Registers */
uint64_t tpc[MaxTL]; // Trap Program Counter (value from
// previous trap level)
uint64_t tnpc[MaxTL]; // Trap Next Program Counter (value from
// previous trap level)
- union
- {
+ union {
uint64_t tstate[MaxTL]; // Trap State
- struct
- {
+ struct {
//Values are from previous trap level
uint64_t cwp:5; // Current Window Pointer
- uint64_t :2; // Reserved bits
- uint64_t pstate:10; // Process State
- uint64_t :6; // Reserved bits
+ uint64_t :3; // Reserved bits
+ uint64_t pstate:13; // Process State
+ uint64_t :3; // Reserved bits
uint64_t asi:8; // Address Space Identifier
uint64_t ccr:8; // Condition Code Register
+ uint64_t gl:8; // Global level
} tstateFields[MaxTL];
};
- union
- {
- uint64_t tick; // Hardware clock-tick counter
- struct
- {
- uint64_t counter:63; // Clock-tick count
- uint64_t npt:1; // Non-priveleged trap
- } tickFields;
+ uint16_t tt[MaxTL]; // Trap Type (Type of trap which occured
+ // on the previous level)
+ uint64_t tba; // Trap Base Address
+
+ union {
+ uint16_t pstate; // Process State Register
+ struct {
+ uint16_t :1; // reserved
+ uint16_t ie:1; // Interrupt enable
+ uint16_t priv:1; // Privelege mode
+ uint16_t am:1; // Address mask
+ uint16_t pef:1; // PSTATE enable floating-point
+ uint16_t :1; // reserved2
+ uint16_t mm:2; // Memory Model
+ uint16_t tle:1; // Trap little-endian
+ uint16_t cle:1; // Current little-endian
+ } pstateFields;
};
+ uint8_t tl; // Trap Level
+ uint8_t pil; // Process Interrupt Register
+ uint8_t cwp; // Current Window Pointer
uint8_t cansave; // Savable windows
uint8_t canrestore; // Restorable windows
- uint8_t otherwin; // Other windows
uint8_t cleanwin; // Clean windows
- union
- {
+ uint8_t otherwin; // Other windows
+ union {
uint8_t wstate; // Window State
- struct
- {
+ struct {
uint8_t normal:3; // Bits TT<4:2> are set to on a normal
// register window trap
uint8_t other:3; // Bits TT<4:2> are set to on an "otherwin"
// register window trap
} wstateFields;
};
- union
- {
- uint64_t ver; // Version
- struct
- {
- uint64_t maxwin:5; // Max CWP value
- uint64_t :2; // Reserved bits
- uint64_t maxtl:8; // Maximum trap level
- uint64_t :8; // Reserved bits
- uint64_t mask:8; // Processor mask set revision number
- uint64_t impl:16; // Implementation identification number
- uint64_t manuf:16; // Manufacturer code
- } verFields;
+ uint8_t gl; // Global level register
+
+
+ /** Hyperprivileged Registers */
+ union {
+ uint64_t hpstate; // Hyperprivileged State Register
+ struct {
+ uint8_t tlz: 1;
+ uint8_t :1;
+ uint8_t hpriv:1;
+ uint8_t :2;
+ uint8_t red:1;
+ uint8_t :4;
+ uint8_t ibe:1;
+ uint8_t id:1;
+ } hpstateFields;
};
- union
- {
+
+ uint64_t htstate[MaxTL]; // Hyperprivileged Trap State Register
+ uint64_t hintp;
+ uint64_t htba; // Hyperprivileged Trap Base Address register
+ union {
+ uint64_t hstick_cmpr; // Hardware tick compare registers
+ struct {
+ uint64_t tick_cmpr:63; // Clock-tick count
+ uint64_t int_dis:1; // Non-priveleged trap
+ } hstick_cmprFields;
+ };
+
+ uint64_t strandStatusReg; // Per strand status register
+
+
+ /** Floating point misc registers. */
+ union {
uint64_t fsr; // Floating-Point State Register
- struct
- {
- union
- {
+ struct {
+ union {
uint64_t cexc:5; // Current excpetion
- struct
- {
+ struct {
uint64_t nxc:1; // Inexact
uint64_t dzc:1; // Divide by zero
uint64_t ufc:1; // Underflow
@@ -510,11 +529,9 @@ namespace SparcISA
uint64_t nvc:1; // Invalid operand
} cexcFields;
};
- union
- {
+ union {
uint64_t aexc:5; // Accrued exception
- struct
- {
+ struct {
uint64_t nxc:1; // Inexact
uint64_t dzc:1; // Divide by zero
uint64_t ufc:1; // Underflow
@@ -530,11 +547,9 @@ namespace SparcISA
uint64_t ver:3; // Version (of the FPU)
uint64_t :2; // Reserved bits
uint64_t ns:1; // Nonstandard floating point
- union
- {
+ union {
uint64_t tem:5; // Trap Enable Mask
- struct
- {
+ struct {
uint64_t nxm:1; // Inexact
uint64_t dzm:1; // Divide by zero
uint64_t ufm:1; // Underflow
@@ -550,17 +565,34 @@ namespace SparcISA
uint64_t :26; // Reserved bits
} fsrFields;
};
- union
- {
- uint8_t fprs; // Floating-Point Register State
- struct
- {
- uint8_t dl:1; // Dirty lower
- uint8_t du:1; // Dirty upper
- uint8_t fef:1; // FPRS enable floating-Point
- } fprsFields;
- };
+ // These need to check the int_dis field and if 0 then
+ // set appropriate bit in softint and checkinterrutps on the cpu
+#if FULL_SYSTEM
+ /** Process a tick compare event and generate an interrupt on the cpu if
+ * appropriate. */
+ void processTickCompare(ThreadContext *tc);
+ void processSTickCompare(ThreadContext *tc);
+ void processHSTickCompare(ThreadContext *tc);
+
+ typedef CpuEventWrapper<MiscRegFile,
+ &MiscRegFile::processTickCompare> TickCompareEvent;
+ TickCompareEvent *tickCompare;
+
+ typedef CpuEventWrapper<MiscRegFile,
+ &MiscRegFile::processSTickCompare> STickCompareEvent;
+ STickCompareEvent *sTickCompare;
+
+ typedef CpuEventWrapper<MiscRegFile,
+ &MiscRegFile::processHSTickCompare> HSTickCompareEvent;
+ HSTickCompareEvent *hSTickCompare;
+
+ /** Fullsystem only register version of ReadRegWithEffect() */
+ MiscReg readFSRegWithEffect(int miscReg, Fault &fault, ThreadContext *tc);
+ /** Fullsystem only register version of SetRegWithEffect() */
+ Fault setFSRegWithEffect(int miscReg, const MiscReg &val,
+ ThreadContext * tc);
+#endif
public:
void reset()
@@ -572,18 +604,32 @@ namespace SparcISA
//on reset Trap which sets the processor into the following state.
//Bits that aren't set aren't defined on startup.
tl = MaxTL;
- tt[tl] = PowerOnReset.trapType();
- pstateFields.mm = 0; //Total Store Order
- pstateFields.red = 1; //Enter RED_State
- pstateFields.am = 0; //Address Masking is turned off
- pstateFields.priv = 1; //Processor enters privileged mode
- pstateFields.ie = 0; //Interrupts are disabled
- pstateFields.ag = 1; //Globals are replaced with alternate globals
- pstateFields.tle = 0; //Big Endian mode for traps
- pstateFields.cle = 0; //Big Endian mode for non-traps
- tickFields.counter = 0; //The TICK register is unreadable by
- tickFields.npt = 1; //The TICK register is unreadable by
- //non-priveleged software
+ gl = MaxGL;
+
+ tickFields.counter = 0; //The TICK register is unreadable bya
+ tickFields.npt = 1; //The TICK register is unreadable by by !priv
+
+ softint = 0; // Clear all the soft interrupt bits
+ tick_cmprFields.int_dis = 1; // disable timer compare interrupts
+ tick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
+ stickFields.npt = 1; //The TICK register is unreadable by by !priv
+ stick_cmprFields.int_dis = 1; // disable timer compare interrupts
+ stick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
+
+
+ tt[tl] = power_on_reset;
+ pstate = 0; // fields 0 but pef
+ pstateFields.pef = 1;
+
+ hpstate = 0;
+ hpstateFields.red = 1;
+ hpstateFields.hpriv = 1;
+ hpstateFields.tlz = 0; // this is a guess
+
+ hintp = 0; // no interrupts pending
+ hstick_cmprFields.int_dis = 1; // disable timer compare interrupts
+ hstick_cmprFields.tick_cmpr = 0; // Reset to 0 for pretty printing
+
#else
/* //This sets up the initial state of the processor for usermode processes
pstateFields.priv = 0; //Process runs in user mode
@@ -608,20 +654,42 @@ namespace SparcISA
reset();
}
+ /** read a value out of an either an SE or FS IPR. No checking is done
+ * about SE vs. FS as this is mostly used to copy the regfile. Thus more
+ * register are copied that are necessary for FS. However this prevents
+ * a bunch of ifdefs and is rarely called so is not performance
+ * criticial. */
MiscReg readReg(int miscReg);
- MiscReg readRegWithEffect(int miscReg, Fault &fault, ExecContext *xc);
-
+ /** Read a value from an IPR. Only the SE iprs are here and the rest
+ * are are readFSRegWithEffect (which is called by readRegWithEffect()).
+ * Checking is done for permission based on state bits in the miscreg
+ * file. */
+ MiscReg readRegWithEffect(int miscReg, Fault &fault, ThreadContext *tc);
+
+ /** write a value into an either an SE or FS IPR. No checking is done
+ * about SE vs. FS as this is mostly used to copy the regfile. Thus more
+ * register are copied that are necessary for FS. However this prevents
+ * a bunch of ifdefs and is rarely called so is not performance
+ * criticial.*/
Fault setReg(int miscReg, const MiscReg &val);
+ /** Write a value into an IPR. Only the SE iprs are here and the rest
+ * are are setFSRegWithEffect (which is called by setRegWithEffect()).
+ * Checking is done for permission based on state bits in the miscreg
+ * file. */
Fault setRegWithEffect(int miscReg,
- const MiscReg &val, ExecContext * xc);
+ const MiscReg &val, ThreadContext * tc);
void serialize(std::ostream & os);
void unserialize(Checkpoint * cp, const std::string & section);
- void copyMiscRegs(ExecContext * xc);
+ void copyMiscRegs(ThreadContext * tc);
+
+ bool isHyperPriv() { return hpstateFields.hpriv; }
+ bool isPriv() { return hpstateFields.hpriv || pstateFields.priv; }
+ bool isNonPriv() { return !isPriv(); }
};
typedef union
@@ -693,9 +761,9 @@ namespace SparcISA
}
MiscReg readMiscRegWithEffect(int miscReg,
- Fault &fault, ExecContext *xc)
+ Fault &fault, ThreadContext *tc)
{
- return miscRegFile.readRegWithEffect(miscReg, fault, xc);
+ return miscRegFile.readRegWithEffect(miscReg, fault, tc);
}
Fault setMiscReg(int miscReg, const MiscReg &val)
@@ -704,9 +772,9 @@ namespace SparcISA
}
Fault setMiscRegWithEffect(int miscReg, const MiscReg &val,
- ExecContext * xc)
+ ThreadContext * tc)
{
- return miscRegFile.setRegWithEffect(miscReg, val, xc);
+ return miscRegFile.setRegWithEffect(miscReg, val, tc);
}
FloatReg readFloatReg(int floatReg, int width)
@@ -775,22 +843,17 @@ namespace SparcISA
CONTEXT_CWP,
CONTEXT_GLOBALS
};
-
- union ContextVal
- {
- MiscReg reg;
- int globalLevel;
- };
+ typedef int ContextVal;
void changeContext(ContextParam param, ContextVal val)
{
switch(param)
{
case CONTEXT_CWP:
- intRegFile.setCWP(val.reg);
+ intRegFile.setCWP(val);
break;
case CONTEXT_GLOBALS:
- intRegFile.setGlobals(val.globalLevel);
+ intRegFile.setGlobals(val);
break;
default:
panic("Tried to set illegal context parameter in the SPARC regfile.\n");
@@ -798,9 +861,11 @@ namespace SparcISA
}
};
- void copyRegs(ExecContext *src, ExecContext *dest);
+ void copyRegs(ThreadContext *src, ThreadContext *dest);
+
+ void copyMiscRegs(ThreadContext *src, ThreadContext *dest);
- void copyMiscRegs(ExecContext *src, ExecContext *dest);
+ int InterruptLevel(uint64_t softint);
} // namespace SparcISA
diff --git a/src/arch/sparc/solaris/process.cc b/src/arch/sparc/solaris/process.cc
index 95cdb0bd5..af0550910 100644
--- a/src/arch/sparc/solaris/process.cc
+++ b/src/arch/sparc/solaris/process.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/sparc/isa_traits.hh"
@@ -31,7 +33,7 @@
#include "arch/sparc/regfile.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/solaris/solaris.hh"
#include "sim/process.hh"
@@ -44,9 +46,9 @@ using namespace SparcISA;
/// Target uname() handler.
static SyscallReturn
unameFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<Solaris::utsname> name(xc->getSyscallArg(0));
+ TypedBufferArg<Solaris::utsname> name(tc->getSyscallArg(0));
strcpy(name->sysname, "SunOS");
strcpy(name->nodename, "m5.eecs.umich.edu");
@@ -54,7 +56,7 @@ unameFunc(SyscallDesc *desc, int callnum, Process *process,
strcpy(name->version, "Generic_118558-21");
strcpy(name->machine, "sun4u");
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
diff --git a/src/arch/sparc/solaris/process.hh b/src/arch/sparc/solaris/process.hh
index 24dffdaf0..3c0d7eba7 100644
--- a/src/arch/sparc/solaris/process.hh
+++ b/src/arch/sparc/solaris/process.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SPARC_SOLARIS_PROCESS_HH__
diff --git a/src/arch/sparc/solaris/solaris.cc b/src/arch/sparc/solaris/solaris.cc
index a56f10740..c588925b0 100644
--- a/src/arch/sparc/solaris/solaris.cc
+++ b/src/arch/sparc/solaris/solaris.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/sparc/solaris/solaris.hh"
diff --git a/src/arch/sparc/solaris/solaris.hh b/src/arch/sparc/solaris/solaris.hh
index 6833a2d6a..0564faba4 100644
--- a/src/arch/sparc/solaris/solaris.hh
+++ b/src/arch/sparc/solaris/solaris.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
*/
#ifndef __ARCH_SPARC_SOLARIS_SOLARIS_HH__
diff --git a/src/arch/sparc/stacktrace.hh b/src/arch/sparc/stacktrace.hh
index 1d8d97a79..d12aee211 100644
--- a/src/arch/sparc/stacktrace.hh
+++ b/src/arch/sparc/stacktrace.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ARCH_ALPHA_STACKTRACE_HH__
@@ -32,13 +34,13 @@
#include "base/trace.hh"
#include "cpu/static_inst.hh"
-class ExecContext;
+class ThreadContext;
class StackTrace;
class ProcessInfo
{
private:
- ExecContext *xc;
+ ThreadContext *tc;
int thread_info_size;
int task_struct_size;
@@ -47,7 +49,7 @@ class ProcessInfo
int name_off;
public:
- ProcessInfo(ExecContext *_xc);
+ ProcessInfo(ThreadContext *_tc);
Addr task(Addr ksp) const;
int pid(Addr ksp) const;
@@ -59,7 +61,7 @@ class StackTrace
protected:
typedef TheISA::MachInst MachInst;
private:
- ExecContext *xc;
+ ThreadContext *tc;
std::vector<Addr> stack;
private:
@@ -68,21 +70,21 @@ class StackTrace
bool decodeSave(MachInst inst, int &reg, int &disp);
bool decodeStack(MachInst inst, int &disp);
- void trace(ExecContext *xc, bool is_call);
+ void trace(ThreadContext *tc, bool is_call);
public:
StackTrace();
- StackTrace(ExecContext *xc, StaticInstPtr inst);
+ StackTrace(ThreadContext *tc, StaticInstPtr inst);
~StackTrace();
void clear()
{
- xc = 0;
+ tc = 0;
stack.clear();
}
- bool valid() const { return xc != NULL; }
- bool trace(ExecContext *xc, StaticInstPtr inst);
+ bool valid() const { return tc != NULL; }
+ bool trace(ThreadContext *tc, StaticInstPtr inst);
public:
const std::vector<Addr> &getstack() const { return stack; }
@@ -104,7 +106,7 @@ class StackTrace
};
inline bool
-StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
+StackTrace::trace(ThreadContext *tc, StaticInstPtr inst)
{
if (!inst->isCall() && !inst->isReturn())
return false;
@@ -112,7 +114,7 @@ StackTrace::trace(ExecContext *xc, StaticInstPtr inst)
if (valid())
clear();
- trace(xc, !inst->isReturn());
+ trace(tc, !inst->isReturn());
return true;
}
diff --git a/src/arch/sparc/system.cc b/src/arch/sparc/system.cc
index 1e2882607..e197e7918 100644
--- a/src/arch/sparc/system.cc
+++ b/src/arch/sparc/system.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/sparc/system.hh"
@@ -40,7 +42,8 @@
using namespace BigEndianGuest;
SparcSystem::SparcSystem(Params *p)
- : System(p)
+ : System(p), sysTick(0)
+
{
resetSymtab = new SymbolTable;
hypervisorSymtab = new SymbolTable;
diff --git a/src/arch/sparc/system.hh b/src/arch/sparc/system.hh
index 27aa8768a..614707f6c 100644
--- a/src/arch/sparc/system.hh
+++ b/src/arch/sparc/system.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
*/
#ifndef __ARCH_SPARC_SYSTEM_HH__
@@ -53,7 +55,7 @@ class SparcSystem : public System
SparcSystem(Params *p);
- ~SparcaSystem();
+ ~SparcSystem();
virtual bool breakpoint();
@@ -82,6 +84,9 @@ class SparcSystem : public System
/** Object pointer for the openboot code */
ObjectFile *openboot;
+ /** System Tick for syncronized tick across all cpus. */
+ Tick sysTick;
+
protected:
const Params *params() const { return (const Params *)_params; }
diff --git a/src/arch/sparc/tlb.hh b/src/arch/sparc/tlb.hh
new file mode 100644
index 000000000..35ff08b43
--- /dev/null
+++ b/src/arch/sparc/tlb.hh
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __ARCH_SPARC_TLB_HH__
+#define __ARCH_SPARC_TLB_HH__
+
+
+#endif // __ARCH_SPARC_TLB_HH__
diff --git a/src/arch/sparc/ua2005.cc b/src/arch/sparc/ua2005.cc
new file mode 100644
index 000000000..b89d48663
--- /dev/null
+++ b/src/arch/sparc/ua2005.cc
@@ -0,0 +1,224 @@
+/*
+ * 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 "arch/sparc/regfile.hh"
+
+Fault
+SparcISA::MiscRegFile::setFSRegWithEffect(int miscReg, const MiscReg &val,
+ ThreadContext *tc)
+{
+ int64_t time;
+ SparcSystem *sys;
+ switch (miscReg) {
+ /** Full system only ASRs */
+ case MISCREG_SOFTINT:
+ if (isNonPriv())
+ return new PrivilegedOpcode;
+ // Check if we are going to interrupt because of something
+ int oldLevel = InterruptLevel(softint);
+ int newLevel = InterruptLevel(val);
+ setReg(miscReg, val);
+ if (newLevel > oldLevel)
+ ; // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX
+ //tc->getCpuPtr()->checkInterrupts = true;
+ return NoFault;
+
+ case MISCREG_SOFTINT_CLR:
+ return setRegWithEffect(miscReg, ~val & softint, tc);
+ case MISCREG_SOFTINT_SET:
+ return setRegWithEffect(miscReg, val | softint, tc);
+
+ case MISCREG_TICK_CMPR:
+ if (isNonPriv())
+ return new PrivilegedOpcode;
+ if (tickCompare == NULL)
+ tickCompare = new TickCompareEvent(this, tc);
+ setReg(miscReg, val);
+ if (tick_cmprFields.int_dis && tickCompare.scheduled())
+ tickCompare.deschedule();
+ time = tick_cmprFields.tick_cmpr - tickFields.counter;
+ if (!tick_cmprFields.int_dis && time > 0)
+ tickCompare.schedule(time * tc->getCpuPtr()->cycles(1));
+ return NoFault;
+
+ case MISCREG_STICK:
+ if (isNonPriv())
+ return new PrivilegedOpcode;
+ if (isPriv())
+ return new PrivilegedAction;
+ sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
+ assert(sys != NULL);
+ sys->sysTick = curTick/Clock::Int::ns - val & ~Bit64;
+ stickFields.npt = val & Bit64 ? 1 : 0;
+ return NoFault;
+
+ case MISCREG_STICK_CMPR:
+ if (isNonPriv())
+ return new PrivilegedOpcode;
+ if (sTickCompare == NULL)
+ sTickCompare = new STickCompareEvent(this, tc);
+ sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
+ assert(sys != NULL);
+ setReg(miscReg, val);
+ if (stick_cmprFields.int_dis && sTickCompare.scheduled())
+ sTickCompare.deschedule();
+ time = stick_cmprFields.tick_cmpr - sys->sysTick;
+ if (!stick_cmprFields.int_dis && time > 0)
+ sTickCompare.schedule(time * Clock::Int::ns);
+ return NoFault;
+
+ /** Fullsystem only Priv registers. */
+ case MISCREG_PIL:
+ if (FULL_SYSTEM) {
+ setReg(miscReg, val);
+ //tc->getCpuPtr()->checkInterrupts;
+ // MUST DO SOMETHING HERE TO TELL CPU TO LOOK FOR INTERRUPTS XXX
+ return NoFault;
+ } else
+ panic("PIL not implemented for syscall emulation\n");
+
+ /** Hyper privileged registers */
+ case MISCREG_HPSTATE:
+ case MISCREG_HINTP:
+ setReg(miscReg, val);
+ return NoFault;
+ case MISCREG_HTSTATE:
+ if (tl == 0)
+ return new IllegalInstruction;
+ setReg(miscReg, val);
+ return NoFault;
+
+ case MISCREG_HTBA:
+ // clear lower 7 bits on writes.
+ setReg(miscReg, val & ULL(~0x7FFF));
+ return NoFault;
+
+ case MISCREG_STRAND_STS_REG:
+ setReg(miscReg, strandStatusReg);
+ return NoFault;
+ case MISCREG_HSTICK_CMPR:
+ if (isNonPriv())
+ return new PrivilegedOpcode;
+ if (hSTickCompare == NULL)
+ hSTickCompare = new HSTickCompareEvent(this, tc);
+ sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
+ assert(sys != NULL);
+ setReg(miscReg, val);
+ if (hstick_cmprFields.int_dis && hSTickCompare.scheduled())
+ hSTickCompare.deschedule();
+ int64_t time = hstick_cmprFields.tick_cmpr - sys->sysTick;
+ if (!hstick_cmprFields.int_dis && time > 0)
+ hSTickCompare.schedule(time * Clock::Int::ns);
+ return NoFault;
+ default:
+ return new IllegalInstruction;
+ }
+}
+
+MiscReg
+MiscRegFile::readFSRegWithEffect(int miscReg, Fault &fault, ThreadContext * tc)
+{
+ switch (miscReg) {
+
+ /** Privileged registers. */
+ case MISCREG_SOFTINT:
+ if (isNonPriv()) {
+ fault = new PrivilegedOpcode;
+ return 0;
+ }
+ return readReg(miscReg);
+ case MISCREG_TICK_CMPR:
+ if (isNonPriv()) {
+ fault = new PrivilegedOpcode;
+ return 0;
+ }
+ return readReg(miscReg);
+ case MISCREG_STICK:
+ SparcSystem *sys;
+ if (stickFields.npt && !isNonPriv()) {
+ fault = new PrivilegedAction;
+ return 0;
+ }
+ sys = dynamic_cast<SparcSystem*>(tc->getSystemPtr());
+ assert(sys != NULL);
+ return curTick/Clock::Int::ns - sys->sysTick | stickFields.npt << 63;
+ case MISCREG_STICK_CMPR:
+ if (isNonPriv()) {
+ fault = new PrivilegedOpcode;
+ return 0;
+ }
+ return readReg(miscReg);
+
+
+ /** Hyper privileged registers */
+ case MISCREG_HPSTATE:
+ case MISCREG_HINTP:
+ return readReg(miscReg);
+ case MISCREG_HTSTATE:
+ if (tl == 0) {
+ fault = new IllegalInstruction;
+ return 0;
+ }
+ return readReg(miscReg);
+
+ case MISCREG_HTBA:
+ return readReg(miscReg) & ULL(~0x7FFF);
+ case MISCREG_HVER:
+ return NWindows | MaxTL << 8 | MaxGL << 16;
+ case MISCREG_STRAND_STS_REG:
+ return strandStatusReg;
+ case MISCREG_HSTICK_CMPR:
+ return hstick_cmpr;
+
+ default:
+ fault = new IllegalInstruction;
+ return 0;
+ }
+}
+
+void
+MiscRegFile::processTickCompare(ThreadContext *tc)
+{
+ panic("tick compare not implemented\n");
+}
+
+void
+MiscRegFile::processSTickCompare(ThreadContext *tc)
+{
+ panic("tick compare not implemented\n");
+}
+
+void
+MiscRegFile::processHSTickCompare(ThreadContext *tc)
+{
+ panic("tick compare not implemented\n");
+}
+
+}; // namespace SparcISA
diff --git a/src/arch/sparc/utility.hh b/src/arch/sparc/utility.hh
index 1e67b3370..f1c071148 100644
--- a/src/arch/sparc/utility.hh
+++ b/src/arch/sparc/utility.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_UTILITY_HH__
@@ -79,10 +81,10 @@ namespace SparcISA
/**
* Function to insure ISA semantics about 0 registers.
- * @param xc The execution context.
+ * @param tc The thread context.
*/
- template <class XC>
- void zeroRegisters(XC *xc);
+ template <class TC>
+ void zeroRegisters(TC *tc);
} // namespace SparcISA
diff --git a/src/arch/sparc/vtophys.cc b/src/arch/sparc/vtophys.cc
new file mode 100644
index 000000000..f7fd92c15
--- /dev/null
+++ b/src/arch/sparc/vtophys.cc
@@ -0,0 +1,166 @@
+/*
+ * 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
+ * Steve Reinhardt
+ * Ali Saidi
+ */
+
+#include <string>
+
+#include "arch/alpha/ev5.hh"
+#include "arch/alpha/vtophys.hh"
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "cpu/thread_context.hh"
+#include "mem/vport.hh"
+
+using namespace std;
+using namespace AlphaISA;
+
+AlphaISA::PageTableEntry
+AlphaISA::kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, AlphaISA::VAddr vaddr)
+{
+ Addr level1_pte = ptbr + vaddr.level1();
+ AlphaISA::PageTableEntry level1 = mem->read<uint64_t>(level1_pte);
+ if (!level1.valid()) {
+ DPRINTF(VtoPhys, "level 1 PTE not valid, va = %#\n", vaddr);
+ return 0;
+ }
+
+ Addr level2_pte = level1.paddr() + vaddr.level2();
+ AlphaISA::PageTableEntry level2 = mem->read<uint64_t>(level2_pte);
+ if (!level2.valid()) {
+ DPRINTF(VtoPhys, "level 2 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+
+ Addr level3_pte = level2.paddr() + vaddr.level3();
+ AlphaISA::PageTableEntry level3 = mem->read<uint64_t>(level3_pte);
+ if (!level3.valid()) {
+ DPRINTF(VtoPhys, "level 3 PTE not valid, va = %#x\n", vaddr);
+ return 0;
+ }
+ return level3;
+}
+
+Addr
+AlphaISA::vtophys(Addr vaddr)
+{
+ Addr paddr = 0;
+ if (AlphaISA::IsUSeg(vaddr))
+ DPRINTF(VtoPhys, "vtophys: invalid vaddr %#x", vaddr);
+ else if (AlphaISA::IsK0Seg(vaddr))
+ paddr = AlphaISA::K0Seg2Phys(vaddr);
+ else
+ panic("vtophys: ptbr is not set on virtual lookup");
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+Addr
+AlphaISA::vtophys(ThreadContext *tc, Addr addr)
+{
+ AlphaISA::VAddr vaddr = addr;
+ Addr ptbr = tc->readMiscReg(AlphaISA::IPR_PALtemp20);
+ Addr paddr = 0;
+ //@todo Andrew couldn't remember why he commented some of this code
+ //so I put it back in. Perhaps something to do with gdb debugging?
+ if (AlphaISA::PcPAL(vaddr) && (vaddr < EV5::PalMax)) {
+ paddr = vaddr & ~ULL(1);
+ } else {
+ if (AlphaISA::IsK0Seg(vaddr)) {
+ paddr = AlphaISA::K0Seg2Phys(vaddr);
+ } else if (!ptbr) {
+ paddr = vaddr;
+ } else {
+ AlphaISA::PageTableEntry pte =
+ kernel_pte_lookup(tc->getPhysPort(), ptbr, vaddr);
+ if (pte.valid())
+ paddr = pte.paddr() | vaddr.offset();
+ }
+ }
+
+
+ DPRINTF(VtoPhys, "vtophys(%#x) -> %#x\n", vaddr, paddr);
+
+ return paddr;
+}
+
+
+void
+AlphaISA::CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen)
+{
+ uint8_t *dst = (uint8_t *)dest;
+ VirtualPort *vp = tc->getVirtPort(tc);
+
+ vp->readBlob(src, dst, cplen);
+
+ tc->delVirtPort(vp);
+
+}
+
+void
+AlphaISA::CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen)
+{
+ uint8_t *src = (uint8_t *)source;
+ VirtualPort *vp = tc->getVirtPort(tc);
+
+ vp->writeBlob(dest, src, cplen);
+
+ tc->delVirtPort(vp);
+}
+
+void
+AlphaISA::CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen)
+{
+ int len = 0;
+ VirtualPort *vp = tc->getVirtPort(tc);
+
+ do {
+ vp->readBlob(vaddr++, (uint8_t*)dst++, 1);
+ len++;
+ } while (len < maxlen && dst[len] != 0 );
+
+ tc->delVirtPort(vp);
+ dst[len] = 0;
+}
+
+void
+AlphaISA::CopyStringIn(ThreadContext *tc, char *src, Addr vaddr)
+{
+ VirtualPort *vp = tc->getVirtPort(tc);
+ for (ChunkGenerator gen(vaddr, strlen(src), AlphaISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ vp->writeBlob(gen.addr(), (uint8_t*)src, gen.size());
+ src += gen.size();
+ }
+ tc->delVirtPort(vp);
+}
diff --git a/src/arch/sparc/vtophys.hh b/src/arch/sparc/vtophys.hh
new file mode 100644
index 000000000..bf2b757d6
--- /dev/null
+++ b/src/arch/sparc/vtophys.hh
@@ -0,0 +1,55 @@
+/*
+ * 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
+ * Steve Reinhardt
+ */
+
+#ifndef __ARCH_SPARC_VTOPHYS_H__
+#define __ARCH_SPARC_VTOPHYS_H__
+
+#include "arch/sparc/isa_traits.hh"
+
+class ThreadContext;
+class FunctionalPort;
+
+namespace SparcISA {
+
+PageTableEntry
+kernel_pte_lookup(FunctionalPort *mem, Addr ptbr, SparcISA::VAddr vaddr);
+
+Addr vtophys(Addr vaddr);
+Addr vtophys(ThreadContext *tc, Addr vaddr);
+
+void CopyOut(ThreadContext *tc, void *dst, Addr src, size_t len);
+void CopyIn(ThreadContext *tc, Addr dst, void *src, size_t len);
+void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen);
+void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr);
+
+};
+#endif // __ARCH_SPARC_VTOPHYS_H__
+
diff --git a/src/base/bitfield.hh b/src/base/bitfield.hh
index c59354c7d..f4e49aa8d 100644
--- a/src/base/bitfield.hh
+++ b/src/base/bitfield.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __BASE_BITFIELD_HH__
diff --git a/src/base/callback.hh b/src/base/callback.hh
index 7b3023505..a39d7df20 100644
--- a/src/base/callback.hh
+++ b/src/base/callback.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CALLBACK_HH__
diff --git a/src/base/chunk_generator.hh b/src/base/chunk_generator.hh
index 4f708bd4b..e9d5355ca 100644
--- a/src/base/chunk_generator.hh
+++ b/src/base/chunk_generator.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __BASE__CHUNK_GENERATOR_HH__
diff --git a/src/base/circlebuf.cc b/src/base/circlebuf.cc
index 89bbfd822..a0c015671 100644
--- a/src/base/circlebuf.cc
+++ b/src/base/circlebuf.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <algorithm>
diff --git a/src/base/circlebuf.hh b/src/base/circlebuf.hh
index 8a64cb5f5..66583b7db 100644
--- a/src/base/circlebuf.hh
+++ b/src/base/circlebuf.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CIRCLEBUF_HH__
diff --git a/src/base/compression/lzss_compression.cc b/src/base/compression/lzss_compression.cc
index 3ffdf7e95..eb35fb8f1 100644
--- a/src/base/compression/lzss_compression.cc
+++ b/src/base/compression/lzss_compression.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/** @file
diff --git a/src/base/compression/lzss_compression.hh b/src/base/compression/lzss_compression.hh
index c136c6d60..35e4dcb3f 100644
--- a/src/base/compression/lzss_compression.hh
+++ b/src/base/compression/lzss_compression.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
#ifndef __LZSS_COMPRESSION_HH__
diff --git a/src/base/compression/null_compression.hh b/src/base/compression/null_compression.hh
index 5fbcf562b..5a582d828 100644
--- a/src/base/compression/null_compression.hh
+++ b/src/base/compression/null_compression.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
+ * Nathan Binkert
*/
#ifndef __BASE_COMPRESSION_NULL_COMPRESSION_HH__
diff --git a/src/base/cprintf.cc b/src/base/cprintf.cc
index cf332ebf2..dd8ce858b 100644
--- a/src/base/cprintf.cc
+++ b/src/base/cprintf.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <cassert>
diff --git a/src/base/cprintf.hh b/src/base/cprintf.hh
index c468c375f..6b2a77f90 100644
--- a/src/base/cprintf.hh
+++ b/src/base/cprintf.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __CPRINTF_HH__
diff --git a/src/base/cprintf_formats.hh b/src/base/cprintf_formats.hh
index 05a8723a4..58ee7f795 100644
--- a/src/base/cprintf_formats.hh
+++ b/src/base/cprintf_formats.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CPRINTF_FORMATS_HH__
diff --git a/src/base/crc.hh b/src/base/crc.hh
index 6ede07748..16dce79aa 100644
--- a/src/base/crc.hh
+++ b/src/base/crc.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CRC_HH__
diff --git a/src/base/date.cc b/src/base/date.cc
index ba7698c29..9ec8a0b33 100644
--- a/src/base/date.cc
+++ b/src/base/date.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
const char *compileDate = __DATE__ " " __TIME__;
diff --git a/src/base/dbl_list.hh b/src/base/dbl_list.hh
index 1d06ff576..8fca72998 100644
--- a/src/base/dbl_list.hh
+++ b/src/base/dbl_list.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __DBL_LIST_HH__
diff --git a/src/base/endian.hh b/src/base/endian.hh
index 499eb50c5..d2b9dc65c 100644
--- a/src/base/endian.hh
+++ b/src/base/endian.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ENDIAN_HH__
diff --git a/src/base/fast_alloc.cc b/src/base/fast_alloc.cc
index 6504e07c2..610dff66c 100644
--- a/src/base/fast_alloc.cc
+++ b/src/base/fast_alloc.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/*
@@ -178,13 +180,11 @@ FastAlloc::dump_oldest(int n)
// C interfaces to FastAlloc::dump_summary() and FastAlloc::dump_oldest().
// gdb seems to have trouble with calling C++ functions directly.
//
-extern "C" void
fast_alloc_summary()
{
FastAlloc::dump_summary();
}
-extern "C" void
fast_alloc_oldest(int n)
{
FastAlloc::dump_oldest(n);
diff --git a/src/base/fast_alloc.hh b/src/base/fast_alloc.hh
index 54e35f8e0..3e22e59c1 100644
--- a/src/base/fast_alloc.hh
+++ b/src/base/fast_alloc.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/*
diff --git a/src/base/fenv.hh b/src/base/fenv.hh
index 3234f5dd3..013d2f09b 100644
--- a/src/base/fenv.hh
+++ b/src/base/fenv.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __BASE_FENV_HH__
diff --git a/src/base/fifo_buffer.cc b/src/base/fifo_buffer.cc
index 85b306c25..4bafa88bd 100644
--- a/src/base/fifo_buffer.cc
+++ b/src/base/fifo_buffer.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
*/
#include "base/fifo_buffer.hh"
diff --git a/src/base/fifo_buffer.hh b/src/base/fifo_buffer.hh
index 03ce057c7..f6205330b 100644
--- a/src/base/fifo_buffer.hh
+++ b/src/base/fifo_buffer.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
*/
#ifndef __FIFO_BUFFER_HH__
diff --git a/src/base/hashmap.hh b/src/base/hashmap.hh
index 712366829..570cbc152 100644
--- a/src/base/hashmap.hh
+++ b/src/base/hashmap.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __HASHMAP_HH__
diff --git a/src/base/hostinfo.cc b/src/base/hostinfo.cc
index d42c96732..a7c93e712 100644
--- a/src/base/hostinfo.cc
+++ b/src/base/hostinfo.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <ctype.h>
diff --git a/src/base/hostinfo.hh b/src/base/hostinfo.hh
index 21a6e5475..b6663ea69 100644
--- a/src/base/hostinfo.hh
+++ b/src/base/hostinfo.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __HOSTINFO_HH__
diff --git a/src/base/hybrid_pred.cc b/src/base/hybrid_pred.cc
index 21cbdb0fd..73216489e 100644
--- a/src/base/hybrid_pred.cc
+++ b/src/base/hybrid_pred.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
*/
#include <string>
diff --git a/src/base/hybrid_pred.hh b/src/base/hybrid_pred.hh
index ea4a9d04c..cb1d6003b 100644
--- a/src/base/hybrid_pred.hh
+++ b/src/base/hybrid_pred.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Steve Reinhardt
*/
//==========================================================================
diff --git a/src/base/inet.cc b/src/base/inet.cc
index f2665bd2b..b8da12a99 100644
--- a/src/base/inet.cc
+++ b/src/base/inet.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sstream>
diff --git a/src/base/inet.hh b/src/base/inet.hh
index e5d0473f9..1bf7c585f 100644
--- a/src/base/inet.hh
+++ b/src/base/inet.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __BASE_INET_HH__
diff --git a/src/base/inifile.cc b/src/base/inifile.cc
index eb5a1335f..4d504d04f 100644
--- a/src/base/inifile.cc
+++ b/src/base/inifile.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#define USE_CPP
diff --git a/src/base/inifile.hh b/src/base/inifile.hh
index 3c6894978..631b29b87 100644
--- a/src/base/inifile.hh
+++ b/src/base/inifile.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __INIFILE_HH__
diff --git a/src/base/intmath.cc b/src/base/intmath.cc
index f1c1651ba..22414ea4b 100644
--- a/src/base/intmath.cc
+++ b/src/base/intmath.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "base/intmath.hh"
diff --git a/src/base/intmath.hh b/src/base/intmath.hh
index 51baddb91..227012e30 100644
--- a/src/base/intmath.hh
+++ b/src/base/intmath.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __INTMATH_HH__
diff --git a/src/base/loader/aout_object.cc b/src/base/loader/aout_object.cc
index 564898ca3..6691bd4ae 100644
--- a/src/base/loader/aout_object.cc
+++ b/src/base/loader/aout_object.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <string>
diff --git a/src/base/loader/aout_object.hh b/src/base/loader/aout_object.hh
index aeb710427..d180d69f3 100644
--- a/src/base/loader/aout_object.hh
+++ b/src/base/loader/aout_object.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __AOUT_OBJECT_HH__
diff --git a/src/base/loader/ecoff_object.cc b/src/base/loader/ecoff_object.cc
index 80917ee9c..134f2d98d 100644
--- a/src/base/loader/ecoff_object.cc
+++ b/src/base/loader/ecoff_object.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <string>
diff --git a/src/base/loader/ecoff_object.hh b/src/base/loader/ecoff_object.hh
index 603c70bec..05c604b2b 100644
--- a/src/base/loader/ecoff_object.hh
+++ b/src/base/loader/ecoff_object.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ECOFF_OBJECT_HH__
diff --git a/src/base/loader/elf_object.cc b/src/base/loader/elf_object.cc
index 79601e9d1..00d218b76 100644
--- a/src/base/loader/elf_object.cc
+++ b/src/base/loader/elf_object.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <string>
diff --git a/src/base/loader/elf_object.hh b/src/base/loader/elf_object.hh
index 72c265edd..46dbfe37b 100644
--- a/src/base/loader/elf_object.hh
+++ b/src/base/loader/elf_object.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __ELF_OBJECT_HH__
diff --git a/src/base/loader/object_file.cc b/src/base/loader/object_file.cc
index c6dfced1d..42c74d418 100644
--- a/src/base/loader/object_file.cc
+++ b/src/base/loader/object_file.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <list>
diff --git a/src/base/loader/object_file.hh b/src/base/loader/object_file.hh
index b43989cb5..79fa394c6 100644
--- a/src/base/loader/object_file.hh
+++ b/src/base/loader/object_file.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __OBJECT_FILE_HH__
diff --git a/src/base/loader/symtab.cc b/src/base/loader/symtab.cc
index 25f54f9bf..3e73eb7a3 100644
--- a/src/base/loader/symtab.cc
+++ b/src/base/loader/symtab.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/base/loader/symtab.hh b/src/base/loader/symtab.hh
index ebcda1345..55ff0c86f 100644
--- a/src/base/loader/symtab.hh
+++ b/src/base/loader/symtab.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __SYMTAB_HH__
@@ -32,7 +35,7 @@
#include <iosfwd>
#include <map>
-#include "arch/isa_traits.hh" // for Addr
+#include "sim/host.hh" // for Addr
class Checkpoint;
class SymbolTable
diff --git a/src/base/match.cc b/src/base/match.cc
index 4f1f49b57..994209864 100644
--- a/src/base/match.cc
+++ b/src/base/match.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/match.hh"
diff --git a/src/base/match.hh b/src/base/match.hh
index 1b0a083a7..6e1f03b80 100644
--- a/src/base/match.hh
+++ b/src/base/match.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/base/misc.cc b/src/base/misc.cc
index f3c86827b..991a33736 100644
--- a/src/base/misc.cc
+++ b/src/base/misc.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/base/misc.hh b/src/base/misc.hh
index 9255c69c6..87faf20e6 100644
--- a/src/base/misc.hh
+++ b/src/base/misc.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Dave Greene
*/
#ifndef __MISC_HH__
diff --git a/src/base/mod_num.hh b/src/base/mod_num.hh
index fabbb56a9..6962dc0fd 100644
--- a/src/base/mod_num.hh
+++ b/src/base/mod_num.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
*/
template<class T, T MV>
diff --git a/src/base/mysql.cc b/src/base/mysql.cc
index c8d6e933a..2416c766a 100644
--- a/src/base/mysql.cc
+++ b/src/base/mysql.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/base/mysql.hh b/src/base/mysql.hh
index ae28a9dfb..272a0f07c 100644
--- a/src/base/mysql.hh
+++ b/src/base/mysql.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_MYSQL_HH__
diff --git a/src/base/output.cc b/src/base/output.cc
index 2b1733f21..afcac03a5 100644
--- a/src/base/output.cc
+++ b/src/base/output.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <errno.h>
diff --git a/src/base/output.hh b/src/base/output.hh
index 3bbe73e3b..0aae4ae81 100644
--- a/src/base/output.hh
+++ b/src/base/output.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_OUTPUT_HH__
diff --git a/src/base/pollevent.cc b/src/base/pollevent.cc
index 99044fc09..2743cd95d 100644
--- a/src/base/pollevent.cc
+++ b/src/base/pollevent.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/ioctl.h>
diff --git a/src/base/pollevent.hh b/src/base/pollevent.hh
index d39931797..5b84650cb 100644
--- a/src/base/pollevent.hh
+++ b/src/base/pollevent.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __POLLEVENT_H__
diff --git a/src/base/predictor.hh b/src/base/predictor.hh
index 37aa29989..94f19ca28 100644
--- a/src/base/predictor.hh
+++ b/src/base/predictor.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
*/
//
diff --git a/src/base/random.cc b/src/base/random.cc
index 4aac14101..e135b55f5 100644
--- a/src/base/random.cc
+++ b/src/base/random.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <cstdlib>
diff --git a/src/base/random.hh b/src/base/random.hh
index def7a4bce..b5eb39f94 100644
--- a/src/base/random.hh
+++ b/src/base/random.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __BASE_RANDOM_HH__
diff --git a/src/base/range.cc b/src/base/range.cc
index a4e50fc4f..442e5fdf8 100644
--- a/src/base/range.cc
+++ b/src/base/range.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/intmath.hh"
diff --git a/src/base/range.hh b/src/base/range.hh
index 4e3e0fd6e..d9542c0ca 100644
--- a/src/base/range.hh
+++ b/src/base/range.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __BASE_RANGE_HH__
diff --git a/src/base/refcnt.hh b/src/base/refcnt.hh
index de589f7c5..6672d4a5f 100644
--- a/src/base/refcnt.hh
+++ b/src/base/refcnt.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __REFCNT_HH__
diff --git a/src/base/remote_gdb.cc b/src/base/remote_gdb.cc
index 41d0c1471..0d3b73b1e 100644
--- a/src/base/remote_gdb.cc
+++ b/src/base/remote_gdb.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/*
@@ -126,7 +128,7 @@
#include "base/socket.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/static_inst.hh"
#include "mem/physical.hh"
#include "mem/port.hh"
@@ -250,7 +252,7 @@ RemoteGDB::Event::process(int revent)
gdb->detach();
}
-RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
+RemoteGDB::RemoteGDB(System *_system, ThreadContext *c)
: event(NULL), listener(NULL), number(-1), fd(-1),
active(false), attached(false),
system(_system), pmem(_system->physmem), context(c)
@@ -640,7 +642,9 @@ RemoteGDB::read(Addr vaddr, size_t size, char *data)
DPRINTF(GDBRead, "read: addr=%#x, size=%d", vaddr, size);
- context->getVirtPort(context)->readBlob(vaddr, (uint8_t*)data, size);
+ VirtualPort *vp = context->getVirtPort(context);
+ vp->readBlob(vaddr, (uint8_t*)data, size);
+ context->delVirtPort(vp);
#if TRACING_ON
if (DTRACE(GDBRead)) {
@@ -677,8 +681,9 @@ RemoteGDB::write(Addr vaddr, size_t size, const char *data)
} else
DPRINTFNR("\n");
}
-
- context->getVirtPort(context)->writeBlob(vaddr, (uint8_t*)data, size);
+ VirtualPort *vp = context->getVirtPort(context);
+ vp->writeBlob(vaddr, (uint8_t*)data, size);
+ context->delVirtPort(vp);
#ifdef IMB
alpha_pal_imb();
@@ -702,11 +707,11 @@ RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
}
void
-RemoteGDB::HardBreakpoint::process(ExecContext *xc)
+RemoteGDB::HardBreakpoint::process(ThreadContext *tc)
{
DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc());
- if (xc == gdb->context)
+ if (tc == gdb->context)
gdb->trap(ALPHA_KENTRY_INT);
}
diff --git a/src/base/remote_gdb.hh b/src/base/remote_gdb.hh
index b7abf5116..90b53e53f 100644
--- a/src/base/remote_gdb.hh
+++ b/src/base/remote_gdb.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __REMOTE_GDB_HH__
@@ -37,7 +39,7 @@
#include "base/socket.hh"
class System;
-class ExecContext;
+class ThreadContext;
class PhysicalMemory;
class GDBListener;
@@ -78,7 +80,7 @@ class RemoteGDB
System *system;
PhysicalMemory *pmem;
- ExecContext *context;
+ ThreadContext *context;
protected:
uint8_t getbyte();
@@ -96,10 +98,10 @@ class RemoteGDB
template <class T> void write(Addr addr, T data);
public:
- RemoteGDB(System *system, ExecContext *context);
+ RemoteGDB(System *system, ThreadContext *context);
~RemoteGDB();
- void replaceExecContext(ExecContext *xc) { context = xc; }
+ void replaceThreadContext(ThreadContext *tc) { context = tc; }
void attach(int fd);
void detach();
@@ -131,7 +133,7 @@ class RemoteGDB
HardBreakpoint(RemoteGDB *_gdb, Addr addr);
std::string name() { return gdb->name() + ".hwbkpt"; }
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
friend class HardBreakpoint;
diff --git a/src/base/res_list.hh b/src/base/res_list.hh
index 960ed108e..442280e15 100644
--- a/src/base/res_list.hh
+++ b/src/base/res_list.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
*/
#ifndef __RES_LIST_HH__
diff --git a/src/base/sat_counter.cc b/src/base/sat_counter.cc
index 7920f6c81..8980275eb 100644
--- a/src/base/sat_counter.cc
+++ b/src/base/sat_counter.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
*/
#include <sstream>
diff --git a/src/base/sat_counter.hh b/src/base/sat_counter.hh
index d7be17b6f..79de11156 100644
--- a/src/base/sat_counter.hh
+++ b/src/base/sat_counter.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Steve Reinhardt
*/
#ifndef __SAT_COUNTER_HH__
diff --git a/src/base/sched_list.hh b/src/base/sched_list.hh
index f794e3514..56ee2f8ec 100644
--- a/src/base/sched_list.hh
+++ b/src/base/sched_list.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
*/
#ifndef SCHED_LIST_HH
diff --git a/src/base/socket.cc b/src/base/socket.cc
index 45a60e7e3..adcc48735 100644
--- a/src/base/socket.cc
+++ b/src/base/socket.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
diff --git a/src/base/socket.hh b/src/base/socket.hh
index 848405c09..8e55eae72 100644
--- a/src/base/socket.hh
+++ b/src/base/socket.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SOCKET_HH__
diff --git a/src/base/statistics.cc b/src/base/statistics.cc
index 20de46347..2acef83c5 100644
--- a/src/base/statistics.cc
+++ b/src/base/statistics.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iomanip>
@@ -41,7 +43,6 @@
#include "base/time.hh"
#include "base/trace.hh"
#include "base/stats/statdb.hh"
-#include "config/stats_binning.hh"
using namespace std;
@@ -172,12 +173,6 @@ FormulaBase::size() const
return root->size();
}
-bool
-FormulaBase::binned() const
-{
- return root && root->binned();
-}
-
void
FormulaBase::reset()
{
@@ -236,33 +231,6 @@ Formula::operator+=(Temp r)
return *this;
}
-MainBin::MainBin(const string &name)
- : _name(name), mem(NULL), memsize(-1)
-{
- Database::regBin(this, name);
-}
-
-MainBin::~MainBin()
-{
- if (mem)
- delete [] mem;
-}
-
-char *
-MainBin::memory(off_t off)
-{
- if (memsize == -1)
- memsize = ceilPow2((size_t) offset());
-
- if (!mem) {
- mem = new char[memsize];
- memset(mem, 0, memsize);
- }
-
- assert(offset() <= size());
- return mem + off;
-}
-
void
check()
{
@@ -285,13 +253,6 @@ check()
Database::stats().sort(StatData::less);
-#if STATS_BINNING
- if (MainBin::curBin() == NULL) {
- static MainBin mainBin("main bin");
- mainBin.activate();
- }
-#endif
-
if (i == end)
return;
@@ -311,39 +272,14 @@ CallbackQueue resetQueue;
void
reset()
{
- // reset non-binned stats
Database::stat_list_t::iterator i = Database::stats().begin();
Database::stat_list_t::iterator end = Database::stats().end();
while (i != end) {
StatData *data = *i;
- if (!data->binned())
- data->reset();
+ data->reset();
++i;
}
- // save the bin so we can go back to where we were
- MainBin *orig = MainBin::curBin();
-
- // reset binned stats
- Database::bin_list_t::iterator bi = Database::bins().begin();
- Database::bin_list_t::iterator be = Database::bins().end();
- while (bi != be) {
- MainBin *bin = *bi;
- bin->activate();
-
- i = Database::stats().begin();
- while (i != end) {
- StatData *data = *i;
- if (data->binned())
- data->reset();
- ++i;
- }
- ++bi;
- }
-
- // restore bin
- MainBin::curBin() = orig;
-
resetQueue.process();
}
diff --git a/src/base/statistics.hh b/src/base/statistics.hh
index dd507c091..59f219c07 100644
--- a/src/base/statistics.hh
+++ b/src/base/statistics.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Erik Hallnor
*/
/** @file
@@ -57,11 +60,9 @@
#include "base/intmath.hh"
#include "base/refcnt.hh"
#include "base/str.hh"
-#include "base/stats/bin.hh"
#include "base/stats/flags.hh"
#include "base/stats/visit.hh"
#include "base/stats/types.hh"
-#include "config/stats_binning.hh"
#include "sim/host.hh"
class Callback;
@@ -100,11 +101,6 @@ struct StatData
virtual ~StatData();
/**
- * @return true if the stat is binned.
- */
- virtual bool binned() const = 0;
-
- /**
* Reset the corresponding stat to the default state.
*/
virtual void reset() = 0;
@@ -157,7 +153,6 @@ class ScalarStatData : public ScalarData
public:
ScalarStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual Counter value() const { return s.value(); }
virtual Result result() const { return s.result(); }
@@ -200,7 +195,6 @@ class VectorStatData : public VectorData
public:
VectorStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual bool zero() const { return s.zero(); }
virtual void reset() { s.reset(); }
@@ -258,7 +252,6 @@ class DistStatData : public DistData
public:
DistStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return s.binned(); }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual bool zero() const { return s.zero(); }
@@ -297,12 +290,10 @@ class VectorDistStatData : public VectorDistData
{
protected:
Stat &s;
- typedef typename Stat::bin_t bin_t;
public:
VectorDistStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return bin_t::binned; }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual size_t size() const { return s.size(); }
@@ -339,12 +330,10 @@ class Vector2dStatData : public Vector2dData
{
protected:
Stat &s;
- typedef typename Stat::bin_t bin_t;
public:
Vector2dStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return bin_t::binned; }
virtual bool check() const { return s.check(); }
virtual void reset() { s.reset(); }
virtual bool zero() const { return s.zero(); }
@@ -356,7 +345,6 @@ class Vector2dStatData : public Vector2dData
}
};
-
class DataAccess
{
protected:
@@ -612,22 +600,16 @@ struct StatStor
* changes. This allows the quick calculation of a per cycle count of the item
* being watched. This is good for keeping track of residencies in structures
* among other things.
- * @todo add lateny to the stat and fix binning.
*/
struct AvgStor
{
public:
/** The paramaters for this storage type */
- struct Params
- {
- /**
- * The current count. We stash this here because the current
- * value is not a binned value.
- */
- Counter current;
- };
+ struct Params { };
private:
+ /** The current count. */
+ Counter current;
/** The total count for all cycles. */
mutable Result total;
/** The cycle that current last changed. */
@@ -637,7 +619,7 @@ struct AvgStor
/**
* Build and initializes this stat storage.
*/
- AvgStor(Params &p) : total(0), last(0) { p.current = Counter(); }
+ AvgStor(Params &p) : current(0), total(0), last(0) { }
/**
* Set the current count to the one provided, update the total and last
@@ -646,9 +628,9 @@ struct AvgStor
* @param p The parameters for this storage.
*/
void set(Counter val, Params &p) {
- total += p.current * (curTick - last);
+ total += current * (curTick - last);
last = curTick;
- p.current = val;
+ current = val;
}
/**
@@ -656,21 +638,21 @@ struct AvgStor
* @param val The amount to increment.
* @param p The parameters for this storage.
*/
- void inc(Counter val, Params &p) { set(p.current + val, p); }
+ void inc(Counter val, Params &p) { set(current + val, p); }
/**
* Deccrement the current count by the provided value, calls set.
* @param val The amount to decrement.
* @param p The parameters for this storage.
*/
- void dec(Counter val, Params &p) { set(p.current - val, p); }
+ void dec(Counter val, Params &p) { set(current - val, p); }
/**
* Return the current count.
* @param p The parameters for this storage.
* @return The current count.
*/
- Counter value(const Params &p) const { return p.current; }
+ Counter value(const Params &p) const { return current; }
/**
* Return the current average.
@@ -679,9 +661,9 @@ struct AvgStor
*/
Result result(const Params &p) const
{
- total += p.current * (curTick - last);
+ total += current * (curTick - last);
last = curTick;
- return (Result)(total + p.current) / (Result)(curTick + 1);
+ return (Result)(total + current) / (Result)(curTick + 1);
}
/**
@@ -701,39 +683,53 @@ struct AvgStor
/**
* Implementation of a scalar stat. The type of stat is determined by the
- * Storage template. The storage for this stat is held within the Bin class.
- * This allows for breaking down statistics across multiple bins easily.
+ * Storage template.
*/
-template <class Storage, class Bin>
+template <class Stor>
class ScalarBase : public DataAccess
{
public:
+ typedef Stor Storage;
+
/** Define the params of the storage class. */
- typedef typename Storage::Params params_t;
- /** Define the bin type. */
- typedef typename Bin::template Bin<Storage> bin_t;
+ typedef typename Storage::Params Params;
protected:
- /** The bin of this stat. */
- bin_t bin;
+ /** The storage of this stat. */
+ char storage[sizeof(Storage)];
+
/** The parameters for this stat. */
- params_t params;
+ Params params;
protected:
/**
- * Retrieve the storage from the bin.
- * @return The storage object for this stat.
+ * Retrieve the storage.
+ * @param index The vector index to access.
+ * @return The storage object at the given index.
*/
- Storage *data() { return bin.data(params); }
+ Storage *
+ data()
+ {
+ return reinterpret_cast<Storage *>(storage);
+ }
+
/**
- * Retrieve a const pointer to the storage from the bin.
- * @return A const pointer to the storage object for this stat.
+ * Retrieve a const pointer to the storage.
+ * for the given index.
+ * @param index The vector index to access.
+ * @return A const pointer to the storage object at the given index.
*/
- const Storage *data() const
+ const Storage *
+ data() const
+ {
+ return reinterpret_cast<const Storage *>(storage);
+ }
+
+ void
+ doInit()
{
- bin_t *_bin = const_cast<bin_t *>(&bin);
- params_t *_params = const_cast<params_t *>(&params);
- return _bin->data(*_params);
+ new (storage) Storage(params);
+ setInit();
}
public:
@@ -748,9 +744,7 @@ class ScalarBase : public DataAccess
* Create and initialize this stat, register it with the database.
*/
ScalarBase()
- {
- bin.init(params);
- }
+ { }
public:
// Common operators for stats
@@ -799,18 +793,13 @@ class ScalarBase : public DataAccess
* @return 1.
*/
size_t size() const { return 1; }
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- bool binned() const { return bin_t::binned; }
- bool check() const { return bin.initialized(); }
+ bool check() const { return true; }
/**
* Reset stat value to default
*/
- void reset() { bin.reset(); }
+ void reset() { data()->reset(); }
Counter value() { return data()->value(params); }
@@ -826,7 +815,6 @@ class ProxyData : public ScalarData
{
public:
virtual void visit(Visit &visitor) { visitor.visit(*this); }
- virtual bool binned() const { return false; }
virtual std::string str() const { return to_string(value()); }
virtual size_t size() const { return 1; }
virtual bool zero() const { return value() == 0; }
@@ -888,7 +876,6 @@ class ValueBase : public DataAccess
Result total() const { return proxy->total(); };
size_t size() const { return proxy->size(); }
- bool binned() const { return proxy->binned(); }
std::string str() const { return proxy->str(); }
bool zero() const { return proxy->zero(); }
bool check() const { return proxy != NULL; }
@@ -900,195 +887,62 @@ class ValueBase : public DataAccess
// Vector Statistics
//
//////////////////////////////////////////////////////////////////////
-template <class Storage, class Bin>
-class ScalarProxy;
-
-/**
- * Implementation of a vector of stats. The type of stat is determined by the
- * Storage class. @sa ScalarBase
- */
-template <class Storage, class Bin>
-class VectorBase : public DataAccess
-{
- public:
- /** Define the params of the storage class. */
- typedef typename Storage::Params params_t;
- /** Define the bin type. */
- typedef typename Bin::template VectorBin<Storage> bin_t;
-
- protected:
- /** The bin of this stat. */
- bin_t bin;
- /** The parameters for this stat. */
- params_t params;
-
- protected:
- /**
- * Retrieve the storage from the bin for the given index.
- * @param index The vector index to access.
- * @return The storage object at the given index.
- */
- Storage *data(int index) { return bin.data(index, params); }
- /**
- * Retrieve a const pointer to the storage from the bin
- * for the given index.
- * @param index The vector index to access.
- * @return A const pointer to the storage object at the given index.
- */
- const Storage *data(int index) const
- {
- bin_t *_bin = const_cast<bin_t *>(&bin);
- params_t *_params = const_cast<params_t *>(&params);
- return _bin->data(index, *_params);
- }
-
- public:
- void value(VCounter &vec) const
- {
- vec.resize(size());
- for (int i = 0; i < size(); ++i)
- vec[i] = data(i)->value(params);
- }
-
- /**
- * Copy the values to a local vector and return a reference to it.
- * @return A reference to a vector of the stat values.
- */
- void result(VResult &vec) const
- {
- vec.resize(size());
- for (int i = 0; i < size(); ++i)
- vec[i] = data(i)->result(params);
- }
-
- /**
- * @return True is stat is binned.
- */
- bool binned() const { return bin_t::binned; }
-
- /**
- * Return a total of all entries in this vector.
- * @return The total of all vector entries.
- */
- Result total() const {
- Result total = 0.0;
- for (int i = 0; i < size(); ++i)
- total += data(i)->result(params);
- return total;
- }
-
- /**
- * @return the number of elements in this vector.
- */
- size_t size() const { return bin.size(); }
-
- bool zero() const
- {
- for (int i = 0; i < size(); ++i)
- if (data(i)->zero())
- return true;
- return false;
- }
-
- bool check() const { return bin.initialized(); }
- void reset() { bin.reset(); }
-
- public:
- VectorBase() {}
-
- /** Friend this class with the associated scalar proxy. */
- friend class ScalarProxy<Storage, Bin>;
-
- /**
- * Return a reference (ScalarProxy) to the stat at the given index.
- * @param index The vector index to access.
- * @return A reference of the stat.
- */
- ScalarProxy<Storage, Bin> operator[](int index);
-
- void update(StatData *data) {}
-};
-
-const StatData * getStatData(const void *stat);
/**
* A proxy class to access the stat at a given index in a VectorBase stat.
* Behaves like a ScalarBase.
*/
-template <class Storage, class Bin>
+template <class Stat>
class ScalarProxy
{
- public:
- /** Define the params of the storage class. */
- typedef typename Storage::Params params_t;
- /** Define the bin type. */
- typedef typename Bin::template VectorBin<Storage> bin_t;
-
private:
- /** Pointer to the bin in the parent VectorBase. */
- bin_t *bin;
- /** Pointer to the params in the parent VectorBase. */
- params_t *params;
+ /** Pointer to the parent Vector. */
+ Stat *stat;
+
/** The index to access in the parent VectorBase. */
int index;
- /** Keep a pointer to the original stat so was can get data */
- void *stat;
-
- protected:
- /**
- * Retrieve the storage from the bin.
- * @return The storage from the bin for this stat.
- */
- Storage *data() { return bin->data(index, *params); }
- /**
- * Retrieve a const pointer to the storage from the bin.
- * @return A const pointer to the storage for this stat.
- */
- const Storage *data() const
- {
- bin_t *_bin = const_cast<bin_t *>(bin);
- params_t *_params = const_cast<params_t *>(params);
- return _bin->data(index, *_params);
- }
public:
/**
* Return the current value of this stat as its base type.
* @return The current value.
*/
- Counter value() const { return data()->value(*params); }
+ Counter value() const { return stat->data(index)->value(stat->params); }
/**
* Return the current value of this statas a result type.
* @return The current value.
*/
- Result result() const { return data()->result(*params); }
+ Result result() const { return stat->data(index)->result(stat->params); }
public:
/**
* Create and initialize this proxy, do not register it with the database.
- * @param b The bin to use.
* @param p The params to use.
* @param i The index to access.
*/
- ScalarProxy(bin_t &b, params_t &p, int i, void *s)
- : bin(&b), params(&p), index(i), stat(s) {}
+ ScalarProxy(Stat *s, int i)
+ : stat(s), index(i)
+ {
+ assert(stat);
+ }
+
/**
* Create a copy of the provided ScalarProxy.
* @param sp The proxy to copy.
*/
ScalarProxy(const ScalarProxy &sp)
- : bin(sp.bin), params(sp.params), index(sp.index), stat(sp.stat) {}
+ : stat(sp.stat), index(sp.index)
+ {}
+
/**
* Set this proxy equal to the provided one.
* @param sp The proxy to copy.
* @return A reference to this proxy.
*/
const ScalarProxy &operator=(const ScalarProxy &sp) {
- bin = sp.bin;
- params = sp.params;
- index = sp.index;
stat = sp.stat;
+ index = sp.index;
return *this;
}
@@ -1098,12 +952,12 @@ class ScalarProxy
* Increment the stat by 1. This calls the associated storage object inc
* function.
*/
- void operator++() { data()->inc(1, *params); }
+ void operator++() { stat->data(index)->inc(1, stat->params); }
/**
* Decrement the stat by 1. This calls the associated storage object dec
* function.
*/
- void operator--() { data()->dec(1, *params); }
+ void operator--() { stat->data(index)->dec(1, stat->params); }
/** Increment the stat by 1. */
void operator++(int) { ++*this; }
@@ -1116,7 +970,7 @@ class ScalarProxy
* @param v The new value.
*/
template <typename U>
- void operator=(const U &v) { data()->set(v, *params); }
+ void operator=(const U &v) { stat->data(index)->set(v, stat->params); }
/**
* Increment the stat by the given value. This calls the associated
@@ -1124,7 +978,7 @@ class ScalarProxy
* @param v The value to add.
*/
template <typename U>
- void operator+=(const U &v) { data()->inc(v, *params); }
+ void operator+=(const U &v) { stat->data(index)->inc(v, stat->params); }
/**
* Decrement the stat by the given value. This calls the associated
@@ -1132,7 +986,7 @@ class ScalarProxy
* @param v The value to substract.
*/
template <typename U>
- void operator-=(const U &v) { data()->dec(v, *params); }
+ void operator-=(const U &v) { stat->data(index)->dec(v, stat->params); }
/**
* Return the number of elements, always 1 for a scalar.
@@ -1141,192 +995,356 @@ class ScalarProxy
size_t size() const { return 1; }
/**
- * Return true if stat is binned.
- *@return false since Proxies aren't printed/binned
- */
- bool binned() const { return false; }
-
- /**
* This stat has no state. Nothing to reset
*/
void reset() { }
public:
- const StatData *statData() const { return getStatData(stat); }
- std::string str() const
+ std::string
+ str() const
{
- return csprintf("%s[%d]", this->statData()->name, index);
+ return csprintf("%s[%d]", stat->str(), index);
}
};
-template <class Storage, class Bin>
-inline ScalarProxy<Storage, Bin>
-VectorBase<Storage, Bin>::operator[](int index)
+/**
+ * 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
{
- assert (index >= 0 && index < size());
- return ScalarProxy<Storage, Bin>(bin, params, index, this);
-}
+ public:
+ typedef Stor Storage;
-template <class Storage, class Bin>
-class VectorProxy;
+ /** Define the params of the storage class. */
+ typedef typename Storage::Params Params;
-template <class Storage, class Bin>
-class Vector2dBase : public DataAccess
-{
- public:
- typedef typename Storage::Params params_t;
- typedef typename Bin::template VectorBin<Storage> bin_t;
+ /** Proxy type */
+ typedef ScalarProxy<VectorBase<Storage> > Proxy;
+
+ friend class ScalarProxy<VectorBase<Storage> >;
protected:
- size_t x;
- size_t y;
- bin_t bin;
- params_t params;
+ /** The storage of this stat. */
+ Storage *storage;
+ size_t _size;
+
+ /** The parameters for this stat. */
+ Params params;
protected:
- Storage *data(int index) { return bin.data(index, params); }
- const Storage *data(int index) const
+ /**
+ * Retrieve the storage.
+ * @param index The vector index to access.
+ * @return The storage object at the given index.
+ */
+ Storage *data(int 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]; }
+
+ void
+ doInit(int s)
{
- bin_t *_bin = const_cast<bin_t *>(&bin);
- params_t *_params = const_cast<params_t *>(&params);
- return _bin->data(index, *_params);
+ assert(s > 0 && "size must be positive!");
+ assert(!storage && "already initialized");
+ _size = s;
+
+ 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();
}
public:
- Vector2dBase() {}
+ void value(VCounter &vec) const
+ {
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->value(params);
+ }
- void update(Vector2dData *data)
+ /**
+ * 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
{
- int size = this->size();
- data->cvec.resize(size);
- for (int i = 0; i < size; ++i)
- data->cvec[i] = this->data(i)->value(params);
+ vec.resize(size());
+ for (int i = 0; i < size(); ++i)
+ vec[i] = data(i)->result(params);
}
- std::string ysubname(int i) const { return (*this->y_subnames)[i]; }
+ /**
+ * Return a total of all entries in this vector.
+ * @return The total of all vector entries.
+ */
+ Result total() const {
+ Result total = 0.0;
+ for (int i = 0; i < size(); ++i)
+ total += data(i)->result(params);
+ return total;
+ }
+
+ /**
+ * @return the number of elements in this vector.
+ */
+ size_t size() const { return _size; }
+
+ bool
+ zero() const
+ {
+ for (int i = 0; i < size(); ++i)
+ if (data(i)->zero())
+ return false;
+ return true;
+ }
+
+ bool
+ check() const
+ {
+ return storage != NULL;
+ }
+
+ void
+ reset()
+ {
+ for (int i = 0; i < size(); ++i)
+ data(i)->reset();
+ }
- friend class VectorProxy<Storage, Bin>;
- VectorProxy<Storage, Bin> operator[](int index);
+ public:
+ VectorBase()
+ : storage(NULL)
+ {}
- size_t size() const { return bin.size(); }
- bool zero() const { return data(0)->value(params) == 0.0; }
+ ~VectorBase()
+ {
+ if (!storage)
+ return;
+
+ for (int i = 0; i < _size; ++i)
+ data(i)->~Storage();
+ delete [] reinterpret_cast<char *>(storage);
+ }
/**
- * Reset stat value to default
+ * Return a reference (ScalarProxy) to the stat at the given index.
+ * @param index The vector index to access.
+ * @return A reference of the stat.
*/
- void reset() { bin.reset(); }
+ Proxy
+ operator[](int index)
+ {
+ assert (index >= 0 && index < size());
+ return Proxy(this, index);
+ }
- bool check() { return bin.initialized(); }
+ void update(StatData *data) {}
};
-template <class Storage, class Bin>
+template <class Stat>
class VectorProxy
{
- public:
- typedef typename Storage::Params params_t;
- typedef typename Bin::template VectorBin<Storage> bin_t;
-
private:
- bin_t *bin;
- params_t *params;
+ Stat *stat;
int offset;
int len;
- void *stat;
private:
- mutable VResult *vec;
+ mutable VResult vec;
- Storage *data(int index) {
+ typename Stat::Storage *
+ data(int index)
+ {
assert(index < len);
- return bin->data(offset + index, *params);
+ return stat->data(offset + index);
}
- const Storage *data(int index) const {
- bin_t *_bin = const_cast<bin_t *>(bin);
- params_t *_params = const_cast<params_t *>(params);
- return _bin->data(offset + index, *_params);
+ const typename Stat::Storage *
+ data(int index) const
+ {
+ assert(index < len);
+ return const_cast<Stat *>(stat)->data(offset + index);
}
public:
- const VResult &result() const {
- if (vec)
- vec->resize(size());
- else
- vec = new VResult(size());
+ const VResult &
+ result() const
+ {
+ vec.resize(size());
for (int i = 0; i < size(); ++i)
- (*vec)[i] = data(i)->result(*params);
+ vec[i] = data(i)->result(stat->params);
- return *vec;
+ return vec;
}
- Result total() const {
- Result total = 0.0;
+ Result
+ total() const
+ {
+ Result total = 0;
for (int i = 0; i < size(); ++i)
- total += data(i)->result(*params);
+ total += data(i)->result(stat->params);
return total;
}
public:
- VectorProxy(bin_t &b, params_t &p, int o, int l, void *s)
- : bin(&b), params(&p), offset(o), len(l), stat(s), vec(NULL)
+ VectorProxy(Stat *s, int o, int l)
+ : stat(s), offset(o), len(l)
{
}
VectorProxy(const VectorProxy &sp)
- : bin(sp.bin), params(sp.params), offset(sp.offset), len(sp.len),
- stat(sp.stat), vec(NULL)
+ : stat(sp.stat), offset(sp.offset), len(sp.len)
{
}
- ~VectorProxy()
+ const VectorProxy &
+ operator=(const VectorProxy &sp)
{
- if (vec)
- delete vec;
- }
-
- const VectorProxy &operator=(const VectorProxy &sp)
- {
- bin = sp.bin;
- params = sp.params;
+ stat = sp.stat;
offset = sp.offset;
len = sp.len;
- stat = sp.stat;
- if (vec)
- delete vec;
- vec = NULL;
return *this;
}
- ScalarProxy<Storage, Bin> operator[](int index)
+ ScalarProxy<Stat> operator[](int index)
{
assert (index >= 0 && index < size());
- return ScalarProxy<Storage, Bin>(*bin, *params, offset + index, stat);
+ return ScalarProxy<Stat>(stat, offset + index);
}
size_t size() const { return len; }
/**
- * Return true if stat is binned.
- *@return false since Proxies aren't printed/binned
- */
- bool binned() const { return false; }
-
- /**
* This stat has no state. Nothing to reset.
*/
void reset() { }
};
-template <class Storage, class Bin>
-inline VectorProxy<Storage, Bin>
-Vector2dBase<Storage, Bin>::operator[](int index)
+template <class Stor>
+class Vector2dBase : public DataAccess
{
- int offset = index * y;
- assert (index >= 0 && offset < size());
- return VectorProxy<Storage, Bin>(bin, params, offset, y, this);
-}
+ public:
+ typedef Stor Storage;
+ typedef typename Storage::Params Params;
+ typedef VectorProxy<Vector2dBase<Storage> > Proxy;
+ friend class ScalarProxy<Vector2dBase<Storage> >;
+ friend class VectorProxy<Vector2dBase<Storage> >;
+
+ protected:
+ size_t x;
+ size_t y;
+ size_t _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();
+ }
+
+ public:
+ Vector2dBase()
+ : storage(NULL)
+ {}
+
+ ~Vector2dBase()
+ {
+ if (!storage)
+ return;
+
+ for (int i = 0; i < _size; ++i)
+ data(i)->~Storage();
+ delete [] reinterpret_cast<char *>(storage);
+ }
+
+ void
+ update(Vector2dData *newdata)
+ {
+ int size = this->size();
+ newdata->cvec.resize(size);
+ for (int i = 0; i < size; ++i)
+ newdata->cvec[i] = data(i)->value(params);
+ }
+
+ std::string ysubname(int i) const { return (*this->y_subnames)[i]; }
+
+ Proxy
+ operator[](int index)
+ {
+ int offset = index * y;
+ assert (index >= 0 && offset + index < size());
+ return Proxy(this, offset, y);
+ }
+
+
+ size_t
+ size() const
+ {
+ return _size;
+ }
+
+ bool
+ zero() const
+ {
+ return data(0)->zero();
+#if 0
+ for (int i = 0; i < size(); ++i)
+ if (!data(i)->zero())
+ return false;
+ return true;
+#endif
+ }
+
+ /**
+ * Reset stat value to default
+ */
+ void
+ reset()
+ {
+ for (int i = 0; i < size(); ++i)
+ data(i)->reset();
+ }
+
+ bool
+ check()
+ {
+ return storage != NULL;
+ }
+};
//////////////////////////////////////////////////////////////////////
//
@@ -1373,14 +1391,8 @@ struct DistStor
VCounter cvec;
public:
- /**
- * Construct this storage with the supplied params.
- * @param params The parameters.
- */
DistStor(const Params &params)
- : min_val(INT_MAX), max_val(INT_MIN), underflow(Counter()),
- overflow(Counter()), sum(Counter()), squares(Counter()),
- samples(Counter()), cvec(params.size)
+ : cvec(params.size)
{
reset();
}
@@ -1615,36 +1627,46 @@ struct AvgFancy
* Implementation of a distribution stat. The type of distribution is
* determined by the Storage template. @sa ScalarBase
*/
-template <class Storage, class Bin>
+template <class Stor>
class DistBase : public DataAccess
{
public:
+ typedef Stor Storage;
/** Define the params of the storage class. */
- typedef typename Storage::Params params_t;
- /** Define the bin type. */
- typedef typename Bin::template Bin<Storage> bin_t;
+ typedef typename Storage::Params Params;
protected:
- /** The bin of this stat. */
- bin_t bin;
+ /** The storage for this stat. */
+ char storage[sizeof(Storage)];
+
/** The parameters for this stat. */
- params_t params;
+ Params params;
protected:
/**
- * Retrieve the storage from the bin.
+ * Retrieve the storage.
* @return The storage object for this stat.
*/
- Storage *data() { return bin.data(params); }
+ Storage *data()
+ {
+ return reinterpret_cast<Storage *>(storage);
+ }
+
/**
- * Retrieve a const pointer to the storage from the bin.
+ * Retrieve a const pointer to the storage.
* @return A const pointer to the storage object for this stat.
*/
- const Storage *data() const
+ const Storage *
+ data() const
{
- bin_t *_bin = const_cast<bin_t *>(&bin);
- params_t *_params = const_cast<params_t *>(&params);
- return _bin->data(*_params);
+ return reinterpret_cast<const Storage *>(storage);
+ }
+
+ void
+ doInit()
+ {
+ new (storage) Storage(params);
+ setInit();
}
public:
@@ -1675,65 +1697,122 @@ class DistBase : public DataAccess
base->data.fancy = Storage::fancy;
data()->update(&(base->data), params);
}
- /**
- * @return True is stat is binned.
- */
- bool binned() const { return bin_t::binned; }
+
/**
* Reset stat value to default
*/
- void reset()
+ void
+ reset()
{
- bin.reset();
+ data()->reset();
}
- bool check() { return bin.initialized(); }
+ bool
+ check()
+ {
+ return true;
+ }
};
-template <class Storage, class Bin>
+template <class Stat>
class DistProxy;
-template <class Storage, class Bin>
+template <class Stor>
class VectorDistBase : public DataAccess
{
public:
- typedef typename Storage::Params params_t;
- typedef typename Bin::template VectorBin<Storage> bin_t;
+ typedef Stor Storage;
+ typedef typename Storage::Params Params;
+ typedef DistProxy<VectorDistBase<Storage> > Proxy;
+ friend class DistProxy<VectorDistBase<Storage> >;
protected:
- bin_t bin;
- params_t params;
+ Storage *storage;
+ size_t _size;
+ Params params;
protected:
- Storage *data(int index) { return bin.data(index, params); }
- const Storage *data(int index) const
+ Storage *
+ data(int index)
{
- bin_t *_bin = const_cast<bin_t *>(&bin);
- params_t *_params = const_cast<params_t *>(&params);
- return _bin->data(index, *_params);
+ return &storage[index];
+ }
+
+ const Storage *
+ data(int index) const
+ {
+ return &storage[index];
+ }
+
+ void
+ doInit(int s)
+ {
+ assert(s > 0 && "size must be positive!");
+ assert(!storage && "already initialized");
+ _size = s;
+
+ 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();
}
public:
- VectorDistBase() {}
+ VectorDistBase()
+ : storage(NULL)
+ {}
+
+ ~VectorDistBase()
+ {
+ if (!storage)
+ return ;
- friend class DistProxy<Storage, Bin>;
- DistProxy<Storage, Bin> operator[](int index);
- const DistProxy<Storage, Bin> operator[](int index) const;
+ for (int i = 0; i < _size; ++i)
+ data(i)->~Storage();
+ delete [] reinterpret_cast<char *>(storage);
+ }
+
+ Proxy operator[](int index);
+
+ size_t
+ size() const
+ {
+ return _size;
+ }
+
+ bool
+ zero() const
+ {
+ return false;
+#if 0
+ for (int i = 0; i < size(); ++i)
+ if (!data(i)->zero(params))
+ return false;
+ return true;
+#endif
+ }
- size_t size() const { return bin.size(); }
- bool zero() const { return false; }
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- bool binned() const { return bin_t::binned; }
/**
* Reset stat value to default
*/
- void reset() { bin.reset(); }
+ void
+ reset()
+ {
+ for (int i = 0; i < size(); ++i)
+ data(i)->reset();
+ }
- bool check() { return bin.initialized(); }
- void update(VectorDistData *base)
+ bool
+ check()
+ {
+ return storage != NULL;
+ }
+
+ void
+ update(VectorDistData *base)
{
int size = this->size();
base->data.resize(size);
@@ -1744,75 +1823,75 @@ class VectorDistBase : public DataAccess
}
};
-template <class Storage, class Bin>
+template <class Stat>
class DistProxy
{
- public:
- typedef typename Storage::Params params_t;
- typedef typename Bin::template Bin<Storage> bin_t;
- typedef VectorDistBase<Storage, Bin> base_t;
-
private:
- union {
- base_t *stat;
- const base_t *cstat;
- };
+ Stat *stat;
int index;
protected:
- Storage *data() { return stat->data(index); }
- const Storage *data() const { return cstat->data(index); }
+ typename Stat::Storage *data() { return stat->data(index); }
+ const typename Stat::Storage *data() const { return stat->data(index); }
public:
- DistProxy(const VectorDistBase<Storage, Bin> &s, int i)
- : cstat(&s), index(i) {}
+ DistProxy(Stat *s, int i)
+ : stat(s), index(i)
+ {}
+
DistProxy(const DistProxy &sp)
- : cstat(sp.cstat), index(sp.index) {}
- const DistProxy &operator=(const DistProxy &sp) {
- cstat = sp.cstat; index = sp.index; return *this;
+ : stat(sp.stat), index(sp.index)
+ {}
+
+ const DistProxy &operator=(const DistProxy &sp)
+ {
+ stat = sp.stat;
+ index = sp.index;
+ return *this;
}
public:
template <typename U>
- void sample(const U &v, int n = 1) { data()->sample(v, n, cstat->params); }
+ void
+ sample(const U &v, int n = 1)
+ {
+ data()->sample(v, n, stat->params);
+ }
+
+ size_t
+ size() const
+ {
+ return 1;
+ }
+
+ bool
+ zero() const
+ {
+ return data()->zero(stat->params);
+ }
- size_t size() const { return 1; }
- bool zero() const { return data()->zero(cstat->params); }
- /**
- * Return true if stat is binned.
- *@return false since Proxies are not binned/printed.
- */
- bool binned() const { return false; }
/**
* Proxy has no state. Nothing to reset.
*/
void reset() { }
};
-template <class Storage, class Bin>
-inline DistProxy<Storage, Bin>
-VectorDistBase<Storage, Bin>::operator[](int index)
-{
- assert (index >= 0 && index < size());
- return DistProxy<Storage, Bin>(*this, index);
-}
-
-template <class Storage, class Bin>
-inline const DistProxy<Storage, Bin>
-VectorDistBase<Storage, Bin>::operator[](int index) const
+template <class Storage>
+inline typename VectorDistBase<Storage>::Proxy
+VectorDistBase<Storage>::operator[](int index)
{
assert (index >= 0 && index < size());
- return DistProxy<Storage, Bin>(*this, index);
+ return typename VectorDistBase<Storage>::Proxy(this, index);
}
#if 0
-template <class Storage, class Bin>
+template <class Storage>
Result
-VectorDistBase<Storage, Bin>::total(int index) const
+VectorDistBase<Storage>::total(int index) const
{
int total = 0;
- for (int i=0; i < x_size(); ++i) {
- total += data(i)->result(*params);
+ for (int i = 0; i < x_size(); ++i) {
+ total += data(i)->result(stat->params);
}
}
#endif
@@ -1845,11 +1924,6 @@ class Node : public RefCounted
* @return The total of the result vector.
*/
virtual Result total() const = 0;
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- virtual bool binned() const = 0;
/**
*
@@ -1876,11 +1950,6 @@ class ScalarStatNode : public Node
virtual Result total() const { return data->result(); };
virtual size_t size() const { return 1; }
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- virtual bool binned() const { return data->binned(); }
/**
*
@@ -1888,34 +1957,45 @@ class ScalarStatNode : public Node
virtual std::string str() const { return data->name; }
};
-template <class Storage, class Bin>
+template <class Stat>
class ScalarProxyNode : public Node
{
private:
- const ScalarProxy<Storage, Bin> proxy;
+ const ScalarProxy<Stat> proxy;
mutable VResult vresult;
public:
- ScalarProxyNode(const ScalarProxy<Storage, Bin> &p)
- : proxy(p), vresult(1) { }
- virtual const VResult &result() const
+ ScalarProxyNode(const ScalarProxy<Stat> &p)
+ : proxy(p), vresult(1)
+ { }
+
+ virtual const VResult &
+ result() const
{
vresult[0] = proxy.result();
return vresult;
}
- virtual Result total() const { return proxy.result(); };
- virtual size_t size() const { return 1; }
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- virtual bool binned() const { return proxy.binned(); }
+ virtual Result
+ total() const
+ {
+ return proxy.result();
+ }
+
+ virtual size_t
+ size() const
+ {
+ return 1;
+ }
/**
*
*/
- virtual std::string str() const { return proxy.str(); }
+ virtual std::string
+ str() const
+ {
+ return proxy.str();
+ }
};
class VectorStatNode : public Node
@@ -1929,11 +2009,6 @@ class VectorStatNode : public Node
virtual Result total() const { return data->total(); };
virtual size_t size() const { return data->size(); }
- /**
- * Return true if stat is binned.
- *@return True is stat is binned.
- */
- virtual bool binned() const { return data->binned(); }
virtual std::string str() const { return data->name; }
};
@@ -1949,13 +2024,6 @@ class ConstNode : public Node
const VResult &result() const { return vresult; }
virtual Result total() const { return vresult[0]; };
virtual size_t size() const { return 1; }
-
- /**
- * Return true if stat is binned.
- *@return False since constants aren't binned.
- */
- virtual bool binned() const { return false; }
-
virtual std::string str() const { return to_string(vresult[0]); }
};
@@ -2029,11 +2097,6 @@ class UnaryNode : public Node
}
virtual size_t size() const { return l->size(); }
- /**
- * Return true if child of node is binned.
- *@return True if child of node is binned.
- */
- virtual bool binned() const { return l->binned(); }
virtual std::string str() const
{
@@ -2100,11 +2163,6 @@ class BinaryNode : public Node
return ls;
}
}
- /**
- * Return true if any children of node are binned
- *@return True if either child of node is binned.
- */
- virtual bool binned() const { return (l->binned() || r->binned()); }
virtual std::string str() const
{
@@ -2153,11 +2211,6 @@ class SumNode : public Node
}
virtual size_t size() const { return 1; }
- /**
- * Return true if child of node is binned.
- *@return True if child of node is binned.
- */
- virtual bool binned() const { return l->binned(); }
virtual std::string str() const
{
@@ -2173,40 +2226,24 @@ class SumNode : public Node
//////////////////////////////////////////////////////////////////////
/**
* @defgroup VisibleStats "Statistic Types"
- * These are the statistics that are used in the simulator. By default these
- * store counters and don't use binning, but are templatized to accept any type
- * and any Bin class.
+ * These are the statistics that are used in the simulator.
* @{
*/
/**
- * This is an easy way to assign all your stats to be binned or not
- * binned. If the typedef is NoBin, nothing is binned. If it is
- * MainBin, then all stats are binned under that Bin.
- */
-#if STATS_BINNING
-typedef MainBin DefaultBin;
-#else
-typedef NoBin DefaultBin;
-#endif
-
-/**
* This is a simple scalar statistic, like a counter.
* @sa Stat, ScalarBase, StatStor
*/
-template <class Bin = DefaultBin>
-class Scalar
- : public Wrap<Scalar<Bin>,
- ScalarBase<StatStor, Bin>,
- ScalarStatData>
+template<int N = 0>
+class Scalar : public Wrap<Scalar<N>, ScalarBase<StatStor>, ScalarStatData>
{
public:
/** The base implementation. */
- typedef ScalarBase<StatStor, Bin> Base;
+ typedef ScalarBase<StatStor> Base;
Scalar()
{
- this->setInit();
+ this->doInit();
}
/**
@@ -2218,10 +2255,7 @@ class Scalar
void operator=(const U &v) { Base::operator=(v); }
};
-class Value
- : public Wrap<Value,
- ValueBase,
- ScalarStatData>
+class Value : public Wrap<Value, ValueBase, ScalarStatData>
{
public:
/** The base implementation. */
@@ -2246,19 +2280,16 @@ class Value
* A stat that calculates the per cycle average of a value.
* @sa Stat, ScalarBase, AvgStor
*/
-template <class Bin = DefaultBin>
-class Average
- : public Wrap<Average<Bin>,
- ScalarBase<AvgStor, Bin>,
- ScalarStatData>
+template<int N = 0>
+class Average : public Wrap<Average<N>, ScalarBase<AvgStor>, ScalarStatData>
{
public:
/** The base implementation. */
- typedef ScalarBase<AvgStor, Bin> Base;
+ typedef ScalarBase<AvgStor> Base;
Average()
{
- this->setInit();
+ this->doInit();
}
/**
@@ -2274,15 +2305,12 @@ class Average
* A vector of scalar stats.
* @sa Stat, VectorBase, StatStor
*/
-template <class Bin = DefaultBin>
-class Vector
- : public WrapVec<Vector<Bin>,
- VectorBase<StatStor, Bin>,
- VectorStatData>
+template<int N = 0>
+class Vector : public WrapVec<Vector<N>, VectorBase<StatStor>, VectorStatData>
{
public:
/** The base implementation. */
- typedef ScalarBase<StatStor, Bin> Base;
+ typedef ScalarBase<StatStor> Base;
/**
* Set this vector to have the given size.
@@ -2290,9 +2318,7 @@ class Vector
* @return A reference to this stat.
*/
Vector &init(size_t size) {
- this->bin.init(size, this->params);
- this->setInit();
-
+ this->doInit(size);
return *this;
}
};
@@ -2301,11 +2327,9 @@ class Vector
* A vector of Average stats.
* @sa Stat, VectorBase, AvgStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class AverageVector
- : public WrapVec<AverageVector<Bin>,
- VectorBase<AvgStor, Bin>,
- VectorStatData>
+ : public WrapVec<AverageVector<N>, VectorBase<AvgStor>, VectorStatData>
{
public:
/**
@@ -2314,9 +2338,7 @@ class AverageVector
* @return A reference to this stat.
*/
AverageVector &init(size_t size) {
- this->bin.init(size, this->params);
- this->setInit();
-
+ this->doInit(size);
return *this;
}
};
@@ -2325,19 +2347,13 @@ class AverageVector
* A 2-Dimensional vecto of scalar stats.
* @sa Stat, Vector2dBase, StatStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class Vector2d
- : public WrapVec2d<Vector2d<Bin>,
- Vector2dBase<StatStor, Bin>,
- Vector2dStatData>
+ : public WrapVec2d<Vector2d<N>, Vector2dBase<StatStor>, Vector2dStatData>
{
public:
- Vector2d &init(size_t _x, size_t _y) {
- this->statData()->x = this->x = _x;
- this->statData()->y = this->y = _y;
- this->bin.init(this->x * this->y, this->params);
- this->setInit();
-
+ Vector2d &init(size_t x, size_t y) {
+ this->doInit(x, y);
return *this;
}
};
@@ -2346,17 +2362,15 @@ class Vector2d
* A simple distribution stat.
* @sa Stat, DistBase, DistStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class Distribution
- : public Wrap<Distribution<Bin>,
- DistBase<DistStor, Bin>,
- DistStatData>
+ : public Wrap<Distribution<N>, DistBase<DistStor>, DistStatData>
{
public:
/** Base implementation. */
- typedef DistBase<DistStor, Bin> Base;
+ typedef DistBase<DistStor> Base;
/** The Parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
@@ -2371,9 +2385,7 @@ class Distribution
this->params.max = max;
this->params.bucket_size = bkt;
this->params.size = (int)rint((max - min) / bkt + 1.0);
- this->bin.init(this->params);
- this->setInit();
-
+ this->doInit();
return *this;
}
};
@@ -2382,25 +2394,22 @@ class Distribution
* Calculates the mean and variance of all the samples.
* @sa Stat, DistBase, FancyStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class StandardDeviation
- : public Wrap<StandardDeviation<Bin>,
- DistBase<FancyStor, Bin>,
- DistStatData>
+ : public Wrap<StandardDeviation<N>, DistBase<FancyStor>, DistStatData>
{
public:
/** The base implementation */
- typedef DistBase<DistStor, Bin> Base;
+ typedef DistBase<DistStor> Base;
/** The parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
* Construct and initialize this distribution.
*/
StandardDeviation() {
- this->bin.init(this->params);
- this->setInit();
+ this->doInit();
}
};
@@ -2408,17 +2417,15 @@ class StandardDeviation
* Calculates the per cycle mean and variance of the samples.
* @sa Stat, DistBase, AvgFancy
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class AverageDeviation
- : public Wrap<AverageDeviation<Bin>,
- DistBase<AvgFancy, Bin>,
- DistStatData>
+ : public Wrap<AverageDeviation<N>, DistBase<AvgFancy>, DistStatData>
{
public:
/** The base implementation */
- typedef DistBase<DistStor, Bin> Base;
+ typedef DistBase<DistStor> Base;
/** The parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
@@ -2426,8 +2433,7 @@ class AverageDeviation
*/
AverageDeviation()
{
- this->bin.init(this->params);
- this->setInit();
+ this->doInit();
}
};
@@ -2435,17 +2441,17 @@ class AverageDeviation
* A vector of distributions.
* @sa Stat, VectorDistBase, DistStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class VectorDistribution
- : public WrapVec<VectorDistribution<Bin>,
- VectorDistBase<DistStor, Bin>,
+ : public WrapVec<VectorDistribution<N>,
+ VectorDistBase<DistStor>,
VectorDistStatData>
{
public:
/** The base implementation */
- typedef VectorDistBase<DistStor, Bin> Base;
+ typedef VectorDistBase<DistStor> Base;
/** The parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
@@ -2461,9 +2467,7 @@ class VectorDistribution
this->params.max = max;
this->params.bucket_size = bkt;
this->params.size = (int)rint((max - min) / bkt + 1.0);
- this->bin.init(size, this->params);
- this->setInit();
-
+ this->doInit(size);
return *this;
}
};
@@ -2472,17 +2476,17 @@ class VectorDistribution
* This is a vector of StandardDeviation stats.
* @sa Stat, VectorDistBase, FancyStor
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class VectorStandardDeviation
- : public WrapVec<VectorStandardDeviation<Bin>,
- VectorDistBase<FancyStor, Bin>,
+ : public WrapVec<VectorStandardDeviation<N>,
+ VectorDistBase<FancyStor>,
VectorDistStatData>
{
public:
/** The base implementation */
- typedef VectorDistBase<FancyStor, Bin> Base;
+ typedef VectorDistBase<FancyStor> Base;
/** The parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
@@ -2491,9 +2495,7 @@ class VectorStandardDeviation
* @return A reference to this distribution.
*/
VectorStandardDeviation &init(int size) {
- this->bin.init(size, this->params);
- this->setInit();
-
+ this->doInit(size);
return *this;
}
};
@@ -2502,17 +2504,17 @@ class VectorStandardDeviation
* This is a vector of AverageDeviation stats.
* @sa Stat, VectorDistBase, AvgFancy
*/
-template <class Bin = DefaultBin>
+template<int N = 0>
class VectorAverageDeviation
- : public WrapVec<VectorAverageDeviation<Bin>,
- VectorDistBase<AvgFancy, Bin>,
+ : public WrapVec<VectorAverageDeviation<N>,
+ VectorDistBase<AvgFancy>,
VectorDistStatData>
{
public:
/** The base implementation */
- typedef VectorDistBase<AvgFancy, Bin> Base;
+ typedef VectorDistBase<AvgFancy> Base;
/** The parameter type. */
- typedef typename DistStor::Params Params;
+ typedef DistStor::Params Params;
public:
/**
@@ -2521,9 +2523,7 @@ class VectorAverageDeviation
* @return A reference to this distribution.
*/
VectorAverageDeviation &init(int size) {
- this->bin.init(size, this->params);
- this->setInit();
-
+ this->doInit(size);
return *this;
}
};
@@ -2567,13 +2567,6 @@ class FormulaBase : public DataAccess
*/
size_t size() const;
- /**
- * Return true if Formula is binned. i.e. any of its children
- * nodes are binned
- * @return True if Formula is binned.
- */
- bool binned() const;
-
bool check() const { return true; }
/**
@@ -2612,7 +2605,6 @@ class FormulaStatData : public FormulaData
public:
FormulaStatData(Stat &stat) : s(stat) {}
- virtual bool binned() const { return s.binned(); }
virtual bool zero() const { return s.zero(); }
virtual void reset() { s.reset(); }
@@ -2679,7 +2671,6 @@ class FormulaNode : public Node
virtual size_t size() const { return formula.size(); }
virtual const VResult &result() const { formula.result(vec); return vec; }
virtual Result total() const { return formula.total(); }
- virtual bool binned() const { return formula.binned(); }
virtual std::string str() const { return formula.str(); }
};
@@ -2713,8 +2704,8 @@ class Temp
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
- template <class Bin>
- Temp(const Scalar<Bin> &s)
+ template <int N>
+ Temp(const Scalar<N> &s)
: node(new ScalarStatNode(s.statData())) { }
/**
@@ -2728,16 +2719,16 @@ class Temp
* Create a new ScalarStatNode.
* @param s The ScalarStat to place in a node.
*/
- template <class Bin>
- Temp(const Average<Bin> &s)
+ template <int N>
+ Temp(const Average<N> &s)
: node(new ScalarStatNode(s.statData())) { }
/**
* Create a new VectorStatNode.
* @param s The VectorStat to place in a node.
*/
- template <class Bin>
- Temp(const Vector<Bin> &s)
+ template <int N>
+ Temp(const Vector<N> &s)
: node(new VectorStatNode(s.statData())) { }
/**
@@ -2750,9 +2741,9 @@ class Temp
* Create a new ScalarProxyNode.
* @param p The ScalarProxy to place in a node.
*/
- template <class Storage, class Bin>
- Temp(const ScalarProxy<Storage, Bin> &p)
- : node(new ScalarProxyNode<Storage, Bin>(p)) { }
+ template <class Stat>
+ Temp(const ScalarProxy<Stat> &p)
+ : node(new ScalarProxyNode<Stat>(p)) { }
/**
* Create a ConstNode
diff --git a/src/base/stats/events.cc b/src/base/stats/events.cc
index 3191aec13..6ecc5434c 100644
--- a/src/base/stats/events.cc
+++ b/src/base/stats/events.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <vector>
diff --git a/src/base/stats/events.hh b/src/base/stats/events.hh
index 2a23240b4..b09b91c7c 100644
--- a/src/base/stats/events.hh
+++ b/src/base/stats/events.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_EVENTS_HH__
diff --git a/src/base/stats/flags.hh b/src/base/stats/flags.hh
index 00db95bc1..ada1a4a87 100644
--- a/src/base/stats/flags.hh
+++ b/src/base/stats/flags.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_FLAGS_HH__
diff --git a/src/base/stats/mysql.cc b/src/base/stats/mysql.cc
index 6d12b4fc1..0fb31f4ce 100644
--- a/src/base/stats/mysql.cc
+++ b/src/base/stats/mysql.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <cassert>
@@ -156,14 +158,6 @@ MySqlRun::cleanup()
if (mysql.commit())
panic("could not commit transaction\n%s\n", mysql.error);
- mysql.query("DELETE bins "
- "FROM bins "
- "LEFT JOIN data ON bn_id=dt_bin "
- "WHERE dt_bin IS NULL");
-
- if (mysql.commit())
- panic("could not commit transaction\n%s\n", mysql.error);
-
mysql.query("DELETE events"
"FROM events"
"LEFT JOIN runs ON ev_run=rn_id"
@@ -307,52 +301,6 @@ SetupStat::setup()
return statid;
}
-unsigned
-SetupBin(const string &bin)
-{
- static map<string, int> binmap;
-
- using namespace MySQL;
- map<string,int>::const_iterator i = binmap.find(bin);
- if (i != binmap.end())
- return (*i).second;
-
- Connection &mysql = MySqlDB.conn();
- assert(mysql.connected());
-
- uint16_t bin_id;
-
- stringstream select;
- stringstream insert;
- ccprintf(select, "SELECT bn_id FROM bins WHERE bn_name=\"%s\"", bin);
-
- mysql.query(select);
- MySQL::Result result = mysql.store_result();
- if (result) {
- assert(result.num_fields() == 1);
- MySQL::Row row = result.fetch_row();
- if (row) {
- to_number(row[0], bin_id);
- goto exit;
- }
- }
-
- ccprintf(insert, "INSERT INTO bins(bn_name) values(\"%s\")", bin);
-
- mysql.query(insert);
- if (mysql.error)
- panic("could not get a bin\n%s\n", mysql.error);
-
- bin_id = mysql.insert_id();
- if (mysql.commit())
- panic("could not commit transaction\n%s\n", mysql.error);
-
- binmap.insert(make_pair(bin, bin_id));
-
- exit:
- return bin_id;
-}
-
InsertData::InsertData()
{
query = new char[maxsize + 1];
@@ -382,7 +330,7 @@ InsertData::flush()
size = 0;
first = true;
strcpy(query, "INSERT INTO "
- "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_bin,dt_data) "
+ "data(dt_stat,dt_x,dt_y,dt_run,dt_tick,dt_data) "
"values");
size = strlen(query);
}
@@ -400,9 +348,9 @@ InsertData::insert()
first = false;
- size += sprintf(query + size, "(%u,%d,%d,%u,%llu,%u,\"%f\")",
+ size += sprintf(query + size, "(%u,%d,%d,%u,%llu,\"%f\")",
stat, x, y, MySqlDB.run(), (unsigned long long)tick,
- bin, data);
+ data);
}
struct InsertSubData
@@ -654,29 +602,6 @@ MySql::configure(const FormulaData &data)
InsertFormula(find(data.id), data.str());
}
-void
-MySql::output(MainBin *bin)
-{
- MySQL::Connection &mysql = MySqlDB.conn();
-
- if (bin) {
- bin->activate();
- newdata.bin = SetupBin(bin->name());
- } else {
- newdata.bin = 0;
- }
-
- Database::stat_list_t::const_iterator i, end = Database::stats().end();
- for (i = Database::stats().begin(); i != end; ++i) {
- StatData *stat = *i;
- if (bin && stat->binned() || !bin && !stat->binned()) {
- stat->visit(*this);
- if (mysql.commit())
- panic("could not commit transaction\n%s\n", mysql.error);
- }
- }
-}
-
bool
MySql::valid() const
{
@@ -695,11 +620,14 @@ MySql::output()
// store sample #
newdata.tick = curTick;
- output(NULL);
- if (!bins().empty()) {
- bin_list_t::iterator i, end = bins().end();
- for (i = bins().begin(); i != end; ++i)
- output(*i);
+ MySQL::Connection &mysql = MySqlDB.conn();
+
+ Database::stat_list_t::const_iterator i, end = Database::stats().end();
+ for (i = Database::stats().begin(); i != end; ++i) {
+ StatData *stat = *i;
+ stat->visit(*this);
+ if (mysql.commit())
+ panic("could not commit transaction\n%s\n", mysql.error);
}
newdata.flush();
diff --git a/src/base/stats/mysql.hh b/src/base/stats/mysql.hh
index 25ea22b97..50f7d9e97 100644
--- a/src/base/stats/mysql.hh
+++ b/src/base/stats/mysql.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_MYSQL_HH__
@@ -37,7 +39,6 @@
namespace MySQL { class Connection; }
namespace Stats {
-class MainBin;
class DistDataData;
class MySqlRun;
bool MySqlConnected();
@@ -80,7 +81,6 @@ class InsertData
uint64_t tick;
double data;
uint16_t stat;
- uint16_t bin;
int16_t x;
int16_t y;
@@ -131,7 +131,6 @@ class MySql : public Output
protected:
// Output helper
- void output(MainBin *bin);
void output(const DistDataData &data);
void output(const ScalarData &data);
void output(const VectorData &data);
diff --git a/src/base/stats/mysql_run.hh b/src/base/stats/mysql_run.hh
index d8dcb7594..487224551 100644
--- a/src/base/stats/mysql_run.hh
+++ b/src/base/stats/mysql_run.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_MYSQL_RUN_HH__
diff --git a/src/base/stats/output.hh b/src/base/stats/output.hh
index ee6b38d63..4fe93791f 100644
--- a/src/base/stats/output.hh
+++ b/src/base/stats/output.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_OUTPUT_HH__
diff --git a/src/base/stats/statdb.cc b/src/base/stats/statdb.cc
index a6b00ab8a..f9136807a 100644
--- a/src/base/stats/statdb.cc
+++ b/src/base/stats/statdb.cc
@@ -24,12 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/misc.hh"
#include "base/trace.hh"
#include "base/statistics.hh"
-#include "base/stats/bin.hh"
#include "base/stats/statdb.hh"
using namespace std;
@@ -49,17 +50,6 @@ find(void *stat)
}
void
-regBin(MainBin *bin, const std::string &_name)
-{
- bin_list_t::iterator i, end = bins().end();
- for (i = bins().begin(); i != end; ++i)
- if ((*i)->name() == _name)
- panic("re-registering bin %s", _name);
- bins().push_back(bin);
- DPRINTF(Stats, "registering %s\n", _name);
-}
-
-void
regStat(void *stat, StatData *data)
{
if (map().find(stat) != map().end())
diff --git a/src/base/stats/statdb.hh b/src/base/stats/statdb.hh
index eb56d8fac..a5b9be7eb 100644
--- a/src/base/stats/statdb.hh
+++ b/src/base/stats/statdb.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_STATDB_HH__
@@ -38,31 +40,25 @@ class Python;
namespace Stats {
-class MainBin;
class StatData;
namespace Database {
typedef std::map<void *, StatData *> stat_map_t;
typedef std::list<StatData *> stat_list_t;
-typedef std::list<MainBin *> bin_list_t;
// 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;
- bin_list_t bins;
-
};
TheDatabase &db();
inline stat_map_t &map() { return db().map; }
inline stat_list_t &stats() { return db().stats; }
-inline bin_list_t &bins() { return db().bins; }
StatData *find(void *stat);
-void regBin(MainBin *bin, const std::string &name);
void regStat(void *stat, StatData *data);
void regPrint(void *stat);
diff --git a/src/base/stats/text.cc b/src/base/stats/text.cc
index 300737c60..c4448efc9 100644
--- a/src/base/stats/text.cc
+++ b/src/base/stats/text.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#if defined(__APPLE__)
@@ -127,23 +129,9 @@ Text::output()
using namespace Database;
ccprintf(*stream, "\n---------- Begin Simulation Statistics ----------\n");
- if (bins().empty() || bins().size() == 1) {
- stat_list_t::const_iterator i, end = stats().end();
- for (i = stats().begin(); i != end; ++i)
- (*i)->visit(*this);
- } else {
- ccprintf(*stream, "PRINTING BINNED STATS\n");
- bin_list_t::iterator i, end = bins().end();
- for (i = bins().begin(); i != end; ++i) {
- MainBin *bin = *i;
- bin->activate();
- ccprintf(*stream,"---%s Bin------------\n", bin->name());
- stat_list_t::const_iterator i, end = stats().end();
- for (i = stats().begin(); i != end; ++i)
- (*i)->visit(*this);
- ccprintf(*stream, "---------------------------------\n");
- }
- }
+ stat_list_t::const_iterator i, end = stats().end();
+ for (i = stats().begin(); i != end; ++i)
+ (*i)->visit(*this);
ccprintf(*stream, "\n---------- End Simulation Statistics ----------\n");
stream->flush();
}
diff --git a/src/base/stats/text.hh b/src/base/stats/text.hh
index 125cb79fa..b3faf5ad5 100644
--- a/src/base/stats/text.hh
+++ b/src/base/stats/text.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_TEXT_HH__
@@ -44,7 +46,6 @@ class Text : public Output
protected:
bool noOutput(const StatData &data);
- void binout();
public:
bool compat;
diff --git a/src/base/stats/types.hh b/src/base/stats/types.hh
index 57f1564a5..b64e8fb17 100644
--- a/src/base/stats/types.hh
+++ b/src/base/stats/types.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_TYPES_HH__
diff --git a/src/base/stats/visit.cc b/src/base/stats/visit.cc
index dd4d49502..870e4fb77 100644
--- a/src/base/stats/visit.cc
+++ b/src/base/stats/visit.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/stats/visit.hh"
diff --git a/src/base/stats/visit.hh b/src/base/stats/visit.hh
index c0593c670..0087c227c 100644
--- a/src/base/stats/visit.hh
+++ b/src/base/stats/visit.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_STATS_VISIT_HH__
diff --git a/src/base/str.cc b/src/base/str.cc
index 5f7f50286..0a517dff5 100644
--- a/src/base/str.cc
+++ b/src/base/str.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <ctype.h>
diff --git a/src/base/str.hh b/src/base/str.hh
index 79e33a1be..08953caf3 100644
--- a/src/base/str.hh
+++ b/src/base/str.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __STR_HH__
diff --git a/src/base/time.cc b/src/base/time.cc
index 5827c9a85..cbc7256ee 100644
--- a/src/base/time.cc
+++ b/src/base/time.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
diff --git a/src/base/time.hh b/src/base/time.hh
index 5731e3029..24e8a8a53 100644
--- a/src/base/time.hh
+++ b/src/base/time.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_TIME_HH__
diff --git a/src/base/timebuf.hh b/src/base/timebuf.hh
index f6b5b2781..160a97034 100644
--- a/src/base/timebuf.hh
+++ b/src/base/timebuf.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#ifndef __BASE_TIMEBUF_HH__
diff --git a/src/base/trace.cc b/src/base/trace.cc
index 90db7f045..9fa615f4d 100644
--- a/src/base/trace.cc
+++ b/src/base/trace.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <ctype.h>
@@ -244,7 +247,6 @@ DebugOut()
//
// Dump trace buffer to specified file (cout if NULL)
//
-extern "C"
void
dumpTrace(const char *filename)
{
@@ -266,7 +268,6 @@ dumpTrace(const char *filename)
// same facility as the "trace to file" feature, and will print error
// messages rather than clobbering an existing ostream pointer.
//
-extern "C"
void
echoTrace(bool on)
{
@@ -286,7 +287,6 @@ echoTrace(bool on)
}
}
-extern "C"
void
printTraceFlags()
{
@@ -335,14 +335,12 @@ tweakTraceFlag(const char *string, bool value)
cprintf("could not find flag %s\n", string);
}
-extern "C"
void
setTraceFlag(const char *string)
{
tweakTraceFlag(string, true);
}
-extern "C"
void
clearTraceFlag(const char *string)
{
diff --git a/src/base/trace.hh b/src/base/trace.hh
index 5e14f1bff..8df5dd893 100644
--- a/src/base/trace.hh
+++ b/src/base/trace.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __BASE_TRACE_HH__
diff --git a/src/base/traceflags.py b/src/base/traceflags.py
index 3b7dd0f81..327ce6075 100644
--- a/src/base/traceflags.py
+++ b/src/base/traceflags.py
@@ -25,6 +25,9 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
#
# This file generates the header and source files for the flags
@@ -53,6 +56,7 @@ baseFlags = [
'BusBridge',
'Cache',
'Chains',
+ 'Checker',
'Clock',
'Commit',
'CommitRate',
@@ -103,14 +107,22 @@ baseFlags = [
'IdeDisk',
'InstExec',
'Interrupt',
- 'LDSTQ',
+ 'LSQ',
+ 'LSQUnit',
'Loader',
'MC146818',
'MMU',
'MSHR',
'Mbox',
'MemDepUnit',
- 'OoOCPU',
+ 'BaseCPU'
+ 'O3CPU',
+ 'OzoneCPU',
+ 'FE',
+ 'IBE',
+ 'BE',
+ 'O3CPU',
+ 'OzoneLSQ',
'PCEvent',
'PCIA',
'PCIDEV',
@@ -146,6 +158,9 @@ baseFlags = [
'Uart',
'VtoPhys',
'WriteBarrier',
+ 'Activity',
+ 'Scoreboard',
+ 'Writeback',
]
#
@@ -163,7 +178,8 @@ compoundFlagMap = {
'EthernetAll' : [ 'Ethernet', 'EthernetPIO', 'EthernetDMA', 'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
'EthernetNoData' : [ 'Ethernet', 'EthernetPIO', 'EthernetDesc', 'EthernetIntr', 'EthernetSM', 'EthernetCksum' ],
'IdeAll' : [ 'IdeCtrl', 'IdeDisk' ],
- 'FullCPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LDSTQ', 'StoreSet', 'MemDepUnit', 'DynInst', 'FullCPU']
+ 'O3CPUAll' : [ 'Fetch', 'Decode', 'Rename', 'IEW', 'Commit', 'IQ', 'ROB', 'FreeList', 'RenameMap', 'LSQ', 'LSQUnit', 'StoreSet', 'MemDepUnit', 'DynInst', 'O3CPU', 'Activity','Scoreboard','Writeback'],
+ 'OzoneCPUAll' : [ 'BE', 'FE', 'IBE', 'OzoneLSQ', 'OzoneCPU']
}
#############################################################
diff --git a/src/base/userinfo.cc b/src/base/userinfo.cc
index 15bd72224..62f7b7b5c 100644
--- a/src/base/userinfo.cc
+++ b/src/base/userinfo.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
diff --git a/src/base/userinfo.hh b/src/base/userinfo.hh
index d8ebd443c..a2838ab3e 100644
--- a/src/base/userinfo.hh
+++ b/src/base/userinfo.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_USERINFO_HH__
diff --git a/src/cpu/SConscript b/src/cpu/SConscript
index 34fb6df78..3dcc2f1ec 100644
--- a/src/cpu/SConscript
+++ b/src/cpu/SConscript
@@ -25,6 +25,8 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
import os
import os.path
@@ -58,6 +60,21 @@ virtual Fault completeAcc(Packet *pkt, %s *xc,
{ panic("completeAcc not defined!"); };
'''
+mem_ini_sig_template = '''
+virtual Fault initiateAcc(%s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); };
+'''
+
+mem_comp_sig_template = '''
+virtual Fault completeAcc(uint8_t *data, %s *xc, Trace::InstRecord *traceData) const { panic("Not defined!"); return NoFault; };
+'''
+
+# Generate a temporary CPU list, including the CheckerCPU if
+# it's enabled. This isn't used for anything else other than StaticInst
+# headers.
+temp_cpu_list = env['CPU_MODELS']
+if env['USE_CHECKER']:
+ temp_cpu_list.append('CheckerCPU')
+
# Generate header.
def gen_cpu_exec_signatures(target, source, env):
f = open(str(target[0]), 'w')
@@ -65,7 +82,7 @@ def gen_cpu_exec_signatures(target, source, env):
#ifndef __CPU_STATIC_INST_EXEC_SIGS_HH__
#define __CPU_STATIC_INST_EXEC_SIGS_HH__
'''
- for cpu in env['CPU_MODELS']:
+ 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, '''
@@ -75,12 +92,19 @@ def gen_cpu_exec_signatures(target, source, env):
# Generate string that gets printed when header is rebuilt
def gen_sigs_string(target, source, env):
return "Generating static_inst_exec_sigs.hh: " \
- + ', '.join(env['CPU_MODELS'])
+ + ', '.join(temp_cpu_list)
# Add command to generate header to environment.
env.Command('static_inst_exec_sigs.hh', models_db,
Action(gen_cpu_exec_signatures, gen_sigs_string,
- varlist = ['CPU_MODELS']))
+ varlist = temp_cpu_list))
+
+env.Depends('static_inst_exec_sigs.hh', Value(env['USE_CHECKER']))
+env.Depends('static_inst_exec_sigs.hh', Value(env['CPU_MODELS']))
+
+# List of suppported CPUs by the Checker. Errors out if USE_CHECKER=True
+# and one of these are not being used.
+CheckerSupportedCPUList = ['O3CPU', 'OzoneCPU']
#################################################################
#
@@ -106,33 +130,64 @@ if need_simple_base:
if 'FastCPU' in env['CPU_MODELS']:
sources += Split('fast/cpu.cc')
-if 'AlphaFullCPU' in env['CPU_MODELS']:
+if 'O3CPU' in env['CPU_MODELS']:
+ sources += SConscript('o3/SConscript', exports = 'env')
sources += Split('''
o3/2bit_local_pred.cc
- o3/alpha_dyn_inst.cc
- o3/alpha_cpu.cc
- o3/alpha_cpu_builder.cc
+ o3/base_dyn_inst.cc
o3/bpred_unit.cc
o3/btb.cc
o3/commit.cc
o3/decode.cc
o3/fetch.cc
o3/free_list.cc
+ o3/fu_pool.cc
o3/cpu.cc
o3/iew.cc
o3/inst_queue.cc
- o3/ldstq.cc
+ o3/lsq_unit.cc
+ o3/lsq.cc
o3/mem_dep_unit.cc
o3/ras.cc
o3/rename.cc
o3/rename_map.cc
o3/rob.cc
- o3/sat_counter.cc
+ o3/scoreboard.cc
o3/store_set.cc
o3/tournament_pred.cc
''')
+ if env['USE_CHECKER']:
+ sources += Split('o3/checker_builder.cc')
-# FullCPU sources are included from m5/SConscript since they're not
+if 'OzoneCPU' in env['CPU_MODELS']:
+ sources += Split('''
+ ozone/base_dyn_inst.cc
+ ozone/bpred_unit.cc
+ ozone/cpu.cc
+ ozone/cpu_builder.cc
+ ozone/dyn_inst.cc
+ ozone/front_end.cc
+ ozone/lw_back_end.cc
+ ozone/lw_lsq.cc
+ ozone/rename_table.cc
+ ''')
+ if env['USE_CHECKER']:
+ sources += Split('ozone/checker_builder.cc')
+
+if env['USE_CHECKER']:
+ sources += Split('checker/cpu.cc')
+ checker_supports = False
+ for i in CheckerSupportedCPUList:
+ if i in env['CPU_MODELS']:
+ checker_supports = True
+ if not checker_supports:
+ print "Checker only supports CPU models %s, please " \
+ "set USE_CHECKER=False or use one of those CPU models" \
+ % CheckerSupportedCPUList
+ Exit(1)
+
+
+# FullCPU sources are included from src/SConscript since they're not
# below this point in the file hierarchy.
# Convert file names to SCons File objects. This takes care of the
diff --git a/src/cpu/activity.cc b/src/cpu/activity.cc
new file mode 100644
index 000000000..9a0f6d98d
--- /dev/null
+++ b/src/cpu/activity.cc
@@ -0,0 +1,157 @@
+/*
+ * 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
+ */
+
+#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)
+{
+ stageActive = new bool[numStages];
+ memset(stageActive, 0, numStages);
+}
+
+void
+ActivityRecorder::activity()
+{
+ // If we've already recorded activity for this cycle, we don't
+ // want to increment the count any more.
+ if (activityBuffer[0]) {
+ return;
+ }
+
+ activityBuffer[0] = true;
+
+ ++activityCount;
+
+ DPRINTF(Activity, "Activity: %i\n", activityCount);
+}
+
+void
+ActivityRecorder::advance()
+{
+ // If there's a 1 in the slot that is about to be erased once the
+ // time buffer advances, then decrement the activityCount.
+ if (activityBuffer[-longestLatency]) {
+ --activityCount;
+
+ assert(activityCount >= 0);
+
+ DPRINTF(Activity, "Activity: %i\n", activityCount);
+
+ if (activityCount == 0) {
+ DPRINTF(Activity, "No activity left!\n");
+ }
+ }
+
+ activityBuffer.advance();
+}
+
+void
+ActivityRecorder::activateStage(const int idx)
+{
+ // Increment the activity count if this stage wasn't already active.
+ if (!stageActive[idx]) {
+ ++activityCount;
+
+ stageActive[idx] = true;
+
+ DPRINTF(Activity, "Activity: %i\n", activityCount);
+ } else {
+ DPRINTF(Activity, "Stage %i already active.\n", idx);
+ }
+
+// assert(activityCount < longestLatency + numStages + 1);
+}
+
+void
+ActivityRecorder::deactivateStage(const int idx)
+{
+ // Decrement the activity count if this stage was active.
+ if (stageActive[idx]) {
+ --activityCount;
+
+ stageActive[idx] = false;
+
+ DPRINTF(Activity, "Activity: %i\n", activityCount);
+ } else {
+ DPRINTF(Activity, "Stage %i already inactive.\n", idx);
+ }
+
+ assert(activityCount >= 0);
+}
+
+void
+ActivityRecorder::reset()
+{
+ activityCount = 0;
+ memset(stageActive, 0, numStages);
+ for (int i = 0; i < longestLatency + 1; ++i)
+ activityBuffer.advance();
+}
+
+void
+ActivityRecorder::dump()
+{
+ for (int i = 0; i <= longestLatency; ++i) {
+ cprintf("[Idx:%i %i] ", i, activityBuffer[-i]);
+ }
+
+ cprintf("\n");
+
+ for (int i = 0; i < numStages; ++i) {
+ cprintf("[Stage:%i %i]\n", i, stageActive[i]);
+ }
+
+ cprintf("\n");
+
+ cprintf("Activity count: %i\n", activityCount);
+}
+
+void
+ActivityRecorder::validate()
+{
+ int count = 0;
+ for (int i = 0; i <= longestLatency; ++i) {
+ if (activityBuffer[-i]) {
+ count++;
+ }
+ }
+
+ for (int i = 0; i < numStages; ++i) {
+ if (stageActive[i]) {
+ count++;
+ }
+ }
+
+ assert(count == activityCount);
+}
diff --git a/src/cpu/activity.hh b/src/cpu/activity.hh
new file mode 100644
index 000000000..e99927339
--- /dev/null
+++ b/src/cpu/activity.hh
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Kevin Lim
+ */
+
+#ifndef __CPU_ACTIVITY_HH__
+#define __CPU_ACTIVITY_HH__
+
+#include "base/timebuf.hh"
+#include "base/trace.hh"
+
+/**
+ * ActivityRecorder helper class that informs the CPU if it can switch
+ * over to being idle or not. It works by having a time buffer as
+ * long as any time buffer in the CPU, and the CPU and all of its
+ * stages inform the ActivityRecorder when they write to any time
+ * buffer. The ActivityRecorder marks a 1 in the "0" slot of the time
+ * buffer any time a stage writes to a time buffer, and it advances
+ * its time buffer at the same time as all other stages. The
+ * ActivityRecorder also records if a stage has activity to do next
+ * cycle. The recorder keeps a count of these two. Thus any time the
+ * count is non-zero, there is either communication still in flight,
+ * or activity that still must be done, meaning that the CPU can not
+ * idle. If count is zero, then the CPU can safely idle as it has no
+ * more outstanding work to do.
+ */
+class ActivityRecorder {
+ public:
+ ActivityRecorder(int num_stages, int longest_latency, int count);
+
+ /** Records that there is activity this cycle. */
+ void activity();
+
+ /** Advances the activity buffer, decrementing the activityCount
+ * if active communication just left the time buffer, and
+ * determining if there is no activity.
+ */
+ void advance();
+
+ /** Marks a stage as active. */
+ void activateStage(const int idx);
+
+ /** Deactivates a stage. */
+ void deactivateStage(const int idx);
+
+ /** Returns how many things are active within the recorder. */
+ int getActivityCount() { return activityCount; }
+
+ /** Sets the count to a starting value. Can be used to disable
+ * the idling option.
+ */
+ void setActivityCount(int count)
+ { activityCount = count; }
+
+ /** Returns if the CPU should be active. */
+ bool active() { return activityCount; }
+
+ /** Clears the time buffer and the activity count. */
+ void reset();
+
+ /** Debug function to dump the contents of the time buffer. */
+ void dump();
+
+ /** Debug function to ensure that the activity count matches the
+ * contents of the time buffer.
+ */
+ void validate();
+
+ private:
+ /** 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,
+ * the activity buffer should also be written to. The
+ * activityBuffer is advanced along with all the other time
+ * buffers, so it should have a 1 somewhere in it only if there
+ * is active communication in a time buffer.
+ */
+ TimeBuffer<bool> activityBuffer;
+
+ /** Longest latency time buffer in the CPU. */
+ int longestLatency;
+
+ /** Tracks how many stages and cycles of time buffer have
+ * activity. Stages increment this count when they switch to
+ * active, and decrement it when they switch to
+ * inactive. Whenever a cycle that previously had no information
+ * is written in the time buffer, this is incremented. When a
+ * cycle that had information exits the time buffer due to age,
+ * this count is decremented. When the count is 0, there is no
+ * activity in the CPU, and it can be descheduled.
+ */
+ int activityCount;
+
+ /** Number of stages that can be marked as active or inactive. */
+ int numStages;
+
+ /** Records which stages are active/inactive. */
+ bool *stageActive;
+};
+
+#endif // __CPU_ACTIVITY_HH__
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index 9ce458c64..40cec416b 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <iostream>
@@ -35,7 +38,8 @@
#include "base/misc.hh"
#include "base/output.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/cpuevent.hh"
+#include "cpu/thread_context.hh"
#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
#include "sim/param.hh"
@@ -45,10 +49,6 @@
#include "base/trace.hh"
-#if FULL_SYSTEM
-#include "kern/kernel_stats.hh"
-#endif
-
using namespace std;
vector<BaseCPU *> BaseCPU::cpuList;
@@ -89,8 +89,8 @@ BaseCPU::BaseCPU(Params *p)
//
if (p->max_insts_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i)
- new SimExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
- "a thread reached the max instruction count");
+ new SimLoopExitEvent(comInstEventQueue[i], p->max_insts_any_thread,
+ "a thread reached the max instruction count");
if (p->max_insts_all_threads != 0) {
// allocate & initialize shared downcounter: each event will
@@ -114,8 +114,8 @@ BaseCPU::BaseCPU(Params *p)
//
if (p->max_loads_any_thread != 0)
for (int i = 0; i < number_of_threads; ++i)
- new SimExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
- "a thread reached the max load count");
+ new SimLoopExitEvent(comLoadEventQueue[i], p->max_loads_any_thread,
+ "a thread reached the max load count");
if (p->max_loads_all_threads != 0) {
// allocate & initialize shared downcounter: each event will
@@ -153,8 +153,6 @@ BaseCPU::BaseCPU(Params *p)
profileEvent = NULL;
if (params->profile)
profileEvent = new ProfileEvent(this, params->profile);
-
- kernelStats = new Kernel::Statistics(system);
#endif
}
@@ -164,6 +162,7 @@ BaseCPU::Params::Params()
#if FULL_SYSTEM
profile = false;
#endif
+ checker = NULL;
}
void
@@ -174,17 +173,13 @@ BaseCPU::enableFunctionTrace()
BaseCPU::~BaseCPU()
{
-#if FULL_SYSTEM
- if (kernelStats)
- delete kernelStats;
-#endif
}
void
BaseCPU::init()
{
if (!params->deferRegistration)
- registerExecContexts();
+ registerThreadContexts();
}
void
@@ -207,44 +202,42 @@ BaseCPU::regStats()
.desc("number of cpu cycles simulated")
;
- int size = execContexts.size();
+ int size = threadContexts.size();
if (size > 1) {
for (int i = 0; i < size; ++i) {
stringstream namestr;
ccprintf(namestr, "%s.ctx%d", name(), i);
- execContexts[i]->regStats(namestr.str());
+ threadContexts[i]->regStats(namestr.str());
}
} else if (size == 1)
- execContexts[0]->regStats(name());
+ threadContexts[0]->regStats(name());
#if FULL_SYSTEM
- if (kernelStats)
- kernelStats->regStats(name() + ".kern");
#endif
}
void
-BaseCPU::registerExecContexts()
+BaseCPU::registerThreadContexts()
{
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
+ 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;
- xc->setCpuId(system->registerExecContext(xc, id));
+ tc->setCpuId(system->registerThreadContext(tc, id));
#else
- xc->setCpuId(xc->getProcessPtr()->registerExecContext(xc));
+ tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc));
#endif
}
}
void
-BaseCPU::switchOut(Sampler *sampler)
+BaseCPU::switchOut()
{
panic("This CPU doesn't support sampling!");
}
@@ -252,19 +245,22 @@ BaseCPU::switchOut(Sampler *sampler)
void
BaseCPU::takeOverFrom(BaseCPU *oldCPU)
{
- assert(execContexts.size() == oldCPU->execContexts.size());
+ assert(threadContexts.size() == oldCPU->threadContexts.size());
+
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *newTC = threadContexts[i];
+ ThreadContext *oldTC = oldCPU->threadContexts[i];
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *newXC = execContexts[i];
- ExecContext *oldXC = oldCPU->execContexts[i];
+ newTC->takeOverFrom(oldTC);
- newXC->takeOverFrom(oldXC);
- assert(newXC->readCpuId() == oldXC->readCpuId());
+ CpuEvent::replaceThreadContext(oldTC, newTC);
+
+ assert(newTC->readCpuId() == oldTC->readCpuId());
#if FULL_SYSTEM
- system->replaceExecContext(newXC, newXC->readCpuId());
+ system->replaceThreadContext(newTC, newTC->readCpuId());
#else
- assert(newXC->getProcessPtr() == oldXC->getProcessPtr());
- newXC->getProcessPtr()->replaceExecContext(newXC, newXC->readCpuId());
+ assert(newTC->getProcessPtr() == oldTC->getProcessPtr());
+ newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId());
#endif
}
@@ -273,8 +269,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
interrupts[i] = oldCPU->interrupts[i];
intstatus = oldCPU->intstatus;
- for (int i = 0; i < execContexts.size(); ++i)
- execContexts[i]->profileClear();
+ for (int i = 0; i < threadContexts.size(); ++i)
+ threadContexts[i]->profileClear();
if (profileEvent)
profileEvent->schedule(curTick);
@@ -290,9 +286,9 @@ BaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)
void
BaseCPU::ProfileEvent::process()
{
- for (int i = 0, size = cpu->execContexts.size(); i < size; ++i) {
- ExecContext *xc = cpu->execContexts[i];
- xc->profileSample();
+ for (int i = 0, size = cpu->threadContexts.size(); i < size; ++i) {
+ ThreadContext *tc = cpu->threadContexts[i];
+ tc->profileSample();
}
schedule(curTick + interval);
@@ -345,12 +341,6 @@ BaseCPU::serialize(std::ostream &os)
{
SERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
SERIALIZE_SCALAR(intstatus);
-
-#if FULL_SYSTEM
- if (kernelStats)
- kernelStats->serialize(os);
-#endif
-
}
void
@@ -358,11 +348,6 @@ BaseCPU::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ARRAY(interrupts, TheISA::NumInterruptLevels);
UNSERIALIZE_SCALAR(intstatus);
-
-#if FULL_SYSTEM
- if (kernelStats)
- kernelStats->unserialize(cp, section);
-#endif
}
#endif // FULL_SYSTEM
diff --git a/src/cpu/base.hh b/src/cpu/base.hh
index 79700c117..51f3bb905 100644
--- a/src/cpu/base.hh
+++ b/src/cpu/base.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CPU_BASE_HH__
@@ -38,10 +41,10 @@
#include "sim/sim_object.hh"
#include "arch/isa_traits.hh"
-class System;
-namespace Kernel { class Statistics; }
class BranchPred;
-class ExecContext;
+class CheckerCPU;
+class ThreadContext;
+class System;
class BaseCPU : public SimObject
{
@@ -89,7 +92,7 @@ class BaseCPU : public SimObject
#endif
protected:
- std::vector<ExecContext *> execContexts;
+ std::vector<ThreadContext *> threadContexts;
public:
@@ -125,6 +128,7 @@ class BaseCPU : public SimObject
int cpu_id;
Tick profile;
#endif
+ BaseCPU *checker;
Params();
};
@@ -140,11 +144,11 @@ class BaseCPU : public SimObject
virtual void activateWhenReady(int tid) {};
- void registerExecContexts();
+ void registerThreadContexts();
/// Prepare for another CPU to take over execution. When it is
/// is ready (drained pipe) it signals the sampler.
- virtual void switchOut(Sampler *);
+ virtual void switchOut();
/// Take over execution from the given CPU. Used for warm-up and
/// sampling.
@@ -232,10 +236,6 @@ class BaseCPU : public SimObject
public:
// Number of CPU cycles simulated
Stats::Scalar<> numCycles;
-
-#if FULL_SYSTEM
- Kernel::Statistics *kernelStats;
-#endif
};
#endif // __CPU_BASE_HH__
diff --git a/src/cpu/base_dyn_inst.cc b/src/cpu/base_dyn_inst.cc
deleted file mode 100644
index bf7c35cad..000000000
--- a/src/cpu/base_dyn_inst.cc
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __CPU_BASE_DYN_INST_CC__
-#define __CPU_BASE_DYN_INST_CC__
-
-#include <iostream>
-#include <string>
-#include <sstream>
-
-#include "base/cprintf.hh"
-#include "base/trace.hh"
-
-#include "arch/faults.hh"
-#include "cpu/exetrace.hh"
-#include "mem/mem_req.hh"
-
-#include "cpu/base_dyn_inst.hh"
-#include "cpu/o3/alpha_impl.hh"
-#include "cpu/o3/alpha_cpu.hh"
-
-using namespace std;
-using namespace TheISA;
-
-#define NOHASH
-#ifndef NOHASH
-
-#include "base/hashmap.hh"
-
-unsigned int MyHashFunc(const BaseDynInst *addr)
-{
- unsigned a = (unsigned)addr;
- unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
-
- return hash;
-}
-
-typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc> my_hash_t;
-my_hash_t thishash;
-#endif
-
-template <class Impl>
-BaseDynInst<Impl>::BaseDynInst(MachInst machInst, Addr inst_PC,
- Addr pred_PC, InstSeqNum seq_num,
- FullCPU *cpu)
- : staticInst(machInst), traceData(NULL), cpu(cpu), cpuXC(cpu->cpuXCBase())
-{
- seqNum = seq_num;
-
- PC = inst_PC;
- nextPC = PC + sizeof(MachInst);
- predPC = pred_PC;
-
- initVars();
-}
-
-template <class Impl>
-BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst)
- : staticInst(_staticInst), traceData(NULL)
-{
- initVars();
-}
-
-template <class Impl>
-void
-BaseDynInst<Impl>::initVars()
-{
- effAddr = MemReq::inval_addr;
- physEffAddr = MemReq::inval_addr;
-
- readyRegs = 0;
-
- completed = false;
- canIssue = false;
- issued = false;
- executed = false;
- canCommit = false;
- squashed = false;
- squashedInIQ = false;
- eaCalcDone = false;
-
- blockingInst = false;
- recoverInst = false;
-
- // Eventually make this a parameter.
- threadNumber = 0;
-
- // Also make this a parameter, or perhaps get it from xc or cpu.
- asid = 0;
-
- // Initialize the fault to be unimplemented opcode.
- fault = new UnimplementedOpcodeFault;
-
- ++instcount;
-
- DPRINTF(FullCPU, "DynInst: Instruction created. Instcount=%i\n",
- instcount);
-}
-
-template <class Impl>
-BaseDynInst<Impl>::~BaseDynInst()
-{
- --instcount;
- DPRINTF(FullCPU, "DynInst: Instruction destroyed. Instcount=%i\n",
- instcount);
-}
-
-template <class Impl>
-void
-BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags)
-{
- // This is the "functional" implementation of prefetch. Not much
- // happens here since prefetches don't affect the architectural
- // state.
-
- // Generate a MemReq so we can translate the effective address.
- MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), 1, flags);
- req->asid = asid;
-
- // Prefetches never cause faults.
- fault = NoFault;
-
- // note this is a local, not BaseDynInst::fault
- Fault trans_fault = cpuXC->translateDataReadReq(req);
-
- if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
- // It's a valid address to cacheable space. Record key MemReq
- // parameters so we can generate another one just like it for
- // the timing access without calling translate() again (which
- // might mess up the TLB).
- effAddr = req->vaddr;
- physEffAddr = req->paddr;
- memReqFlags = req->flags;
- } else {
- // Bogus address (invalid or uncacheable space). Mark it by
- // setting the eff_addr to InvalidAddr.
- effAddr = physEffAddr = MemReq::inval_addr;
- }
-
- /**
- * @todo
- * Replace the disjoint functional memory with a unified one and remove
- * this hack.
- */
-#if !FULL_SYSTEM
- req->paddr = req->vaddr;
-#endif
-
- if (traceData) {
- traceData->setAddr(addr);
- }
-}
-
-template <class Impl>
-void
-BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags)
-{
- // Need to create a MemReq here so we can do a translation. This
- // will casue a TLB miss trap if necessary... not sure whether
- // that's the best thing to do or not. We don't really need the
- // MemReq otherwise, since wh64 has no functional effect.
- MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), size, flags);
- req->asid = asid;
-
- fault = cpuXC->translateDataWriteReq(req);
-
- if (fault == NoFault && !(req->flags & UNCACHEABLE)) {
- // Record key MemReq parameters so we can generate another one
- // just like it for the timing access without calling translate()
- // again (which might mess up the TLB).
- effAddr = req->vaddr;
- physEffAddr = req->paddr;
- memReqFlags = req->flags;
- } else {
- // ignore faults & accesses to uncacheable space... treat as no-op
- effAddr = physEffAddr = MemReq::inval_addr;
- }
-
- storeSize = size;
- storeData = 0;
-}
-
-/**
- * @todo Need to find a way to get the cache block size here.
- */
-template <class Impl>
-Fault
-BaseDynInst<Impl>::copySrcTranslate(Addr src)
-{
- MemReqPtr req = new MemReq(src, cpuXC->getProxy(), 64);
- req->asid = asid;
-
- // translate to physical address
- Fault fault = cpuXC->translateDataReadReq(req);
-
- if (fault == NoFault) {
- cpuXC->copySrcAddr = src;
- cpuXC->copySrcPhysAddr = req->paddr;
- } else {
- cpuXC->copySrcAddr = 0;
- cpuXC->copySrcPhysAddr = 0;
- }
- return fault;
-}
-
-/**
- * @todo Need to find a way to get the cache block size here.
- */
-template <class Impl>
-Fault
-BaseDynInst<Impl>::copy(Addr dest)
-{
- uint8_t data[64];
- FunctionalMemory *mem = cpuXC->mem;
- assert(cpuXC->copySrcPhysAddr || cpuXC->misspeculating());
- MemReqPtr req = new MemReq(dest, cpuXC->getProxy(), 64);
- req->asid = asid;
-
- // translate to physical address
- Fault fault = cpuXC->translateDataWriteReq(req);
-
- if (fault == NoFault) {
- Addr dest_addr = req->paddr;
- // Need to read straight from memory since we have more than 8 bytes.
- req->paddr = cpuXC->copySrcPhysAddr;
- mem->read(req, data);
- req->paddr = dest_addr;
- mem->write(req, data);
- }
- return fault;
-}
-
-template <class Impl>
-void
-BaseDynInst<Impl>::dump()
-{
- cprintf("T%d : %#08d `", threadNumber, PC);
- cout << staticInst->disassemble(PC);
- cprintf("'\n");
-}
-
-template <class Impl>
-void
-BaseDynInst<Impl>::dump(std::string &outstring)
-{
- std::ostringstream s;
- s << "T" << threadNumber << " : 0x" << PC << " "
- << staticInst->disassemble(PC);
-
- outstring = s.str();
-}
-
-
-#if 0
-template <class Impl>
-Fault
-BaseDynInst<Impl>::mem_access(mem_cmd cmd, Addr addr, void *p, int nbytes)
-{
- Fault fault;
-
- // check alignments, even speculative this test should always pass
- if ((nbytes & nbytes - 1) != 0 || (addr & nbytes - 1) != 0) {
- for (int i = 0; i < nbytes; i++)
- ((char *) p)[i] = 0;
-
- // I added the following because according to the comment above,
- // we should never get here. The comment lies
-#if 0
- panic("unaligned access. Cycle = %n", curTick);
-#endif
- return NoFault;
- }
-
- MemReqPtr req = new MemReq(addr, thread, nbytes);
- switch(cmd) {
- case Read:
- fault = spec_mem->read(req, (uint8_t *)p);
- break;
-
- case Write:
- fault = spec_mem->write(req, (uint8_t *)p);
- if (fault != NoFault)
- break;
-
- specMemWrite = true;
- storeSize = nbytes;
- switch(nbytes) {
- case sizeof(uint8_t):
- *(uint8_t)&storeData = (uint8_t *)p;
- break;
- case sizeof(uint16_t):
- *(uint16_t)&storeData = (uint16_t *)p;
- break;
- case sizeof(uint32_t):
- *(uint32_t)&storeData = (uint32_t *)p;
- break;
- case sizeof(uint64_t):
- *(uint64_t)&storeData = (uint64_t *)p;
- break;
- }
- break;
-
- default:
- fault = genMachineCheckFault();
- break;
- }
-
- trace_mem(fault, cmd, addr, p, nbytes);
-
- return fault;
-}
-
-#endif
-
-template <class Impl>
-bool
-BaseDynInst<Impl>::eaSrcsReady()
-{
- // For now I am assuming 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)
-
- for (int i = 1; i < numSrcRegs(); ++i)
- {
- if (!_readySrcRegIdx[i])
- return false;
- }
-
- return true;
-}
-
-// Forward declaration
-template class BaseDynInst<AlphaSimpleImpl>;
-
-template <>
-int
-BaseDynInst<AlphaSimpleImpl>::instcount = 0;
-
-#endif // __CPU_BASE_DYN_INST_CC__
diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh
index 3a7852f79..9cc61f74c 100644
--- a/src/cpu/base_dyn_inst.hh
+++ b/src/cpu/base_dyn_inst.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,26 +24,27 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_BASE_DYN_INST_HH__
#define __CPU_BASE_DYN_INST_HH__
+#include <bitset>
+#include <list>
#include <string>
-#include <vector>
+#include "arch/faults.hh"
#include "base/fast_alloc.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/exetrace.hh"
#include "cpu/inst_seq.hh"
-#include "cpu/o3/comm.hh"
+#include "cpu/op_class.hh"
#include "cpu/static_inst.hh"
-#include "encumbered/cpu/full/bpred_update.hh"
-#include "encumbered/cpu/full/op_class.hh"
-#include "encumbered/cpu/full/spec_memory.hh"
-#include "encumbered/cpu/full/spec_state.hh"
-#include "encumbered/mem/functional/main.hh"
+#include "mem/packet.hh"
+#include "sim/system.hh"
/**
* @file
@@ -58,21 +59,32 @@ class BaseDynInst : public FastAlloc, public RefCounted
{
public:
// Typedef for the CPU.
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::CPUType ImplCPU;
+ typedef typename ImplCPU::ImplState ImplState;
- /// Binary machine instruction type.
+ // Binary machine instruction type.
typedef TheISA::MachInst MachInst;
- /// Logical register index type.
+ // Extended machine instruction type
+ typedef TheISA::ExtMachInst ExtMachInst;
+ // Logical register index type.
typedef TheISA::RegIndex RegIndex;
- /// Integer register index type.
+ // Integer register type.
typedef TheISA::IntReg IntReg;
+ // Floating point register type.
+ typedef TheISA::FloatReg FloatReg;
+
+ // The DynInstPtr type.
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ // The list of instructions iterator type.
+ 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 static inst used by this dyn inst. */
+ /** The StaticInst used by this BaseDynInst. */
StaticInstPtr staticInst;
////////////////////////////////////////////
@@ -80,11 +92,27 @@ class BaseDynInst : public FastAlloc, public RefCounted
// INSTRUCTION EXECUTION
//
////////////////////////////////////////////
+ /** InstRecord that tracks this instructions. */
Trace::InstRecord *traceData;
+ /**
+ * 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);
@@ -96,44 +124,37 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** @todo: Consider making this private. */
public:
- /** Is this instruction valid. */
- bool valid;
-
/** The sequence number of the instruction. */
InstSeqNum seqNum;
- /** How many source registers are ready. */
- unsigned readyRegs;
-
- /** Is the instruction completed. */
- bool completed;
-
- /** Can this instruction issue. */
- bool canIssue;
-
- /** Has this instruction issued. */
- bool issued;
-
- /** Has this instruction executed (or made it through execute) yet. */
- bool executed;
-
- /** Can this instruction commit. */
- bool canCommit;
-
- /** Is this instruction squashed. */
- bool squashed;
-
- /** Is this instruction squashed in the instruction queue. */
- bool squashedInIQ;
-
- /** Is this a recover instruction. */
- bool recoverInst;
-
- /** Is this a thread blocking instruction. */
- bool blockingInst; /* this inst has called thread_block() */
+ enum Status {
+ 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
+ };
- /** Is this a thread syncrhonization instruction. */
- bool threadsyncWait;
+ /** The status of this BaseDynInst. Several bits can be set. */
+ std::bitset<NumStatus> status;
/** The thread this instruction is from. */
short threadNumber;
@@ -141,15 +162,24 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** data address space ID, for loads & stores. */
short asid;
- /** Pointer to the FullCPU object. */
- FullCPU *cpu;
+ /** How many source registers are ready. */
+ unsigned readyRegs;
+
+ /** Pointer to the Impl's CPU object. */
+ ImplCPU *cpu;
- /** Pointer to the exec context. Will not exist in the final version. */
- CPUExecContext *cpuXC;
+ /** Pointer to the thread state. */
+ ImplState *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;
+
/** The effective virtual address (lds & stores only). */
Addr effAddr;
@@ -165,12 +195,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** The memory request flags (from translation). */
unsigned memReqFlags;
- /** The size of the data to be stored. */
- int storeSize;
-
- /** The data to be stored. */
- IntReg storeData;
-
union Result {
uint64_t integer;
float fp;
@@ -197,17 +221,29 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** Count of total number of dynamic instructions. */
static int instcount;
- /** Whether or not the source register is ready. Not sure this should be
- * here vs. the derived class.
+#ifdef DEBUG
+ void dumpSNList();
+#endif
+
+ /** Whether or not the source register is ready.
+ * @todo: Not sure this should be here vs the derived class.
*/
bool _readySrcRegIdx[MaxInstSrcRegs];
public:
- /** BaseDynInst constructor given a binary instruction. */
- BaseDynInst(MachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num,
- FullCPU *cpu);
+ /** 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.
+ */
+ BaseDynInst(ExtMachInst inst, Addr PC, Addr pred_PC, InstSeqNum seq_num,
+ ImplCPU *cpu);
- /** BaseDynInst constructor given a static inst pointer. */
+ /** BaseDynInst constructor given a StaticInst pointer.
+ * @param _staticInst The StaticInst for this BaseDynInst.
+ */
BaseDynInst(StaticInstPtr &_staticInst);
/** BaseDynInst destructor. */
@@ -218,13 +254,6 @@ class BaseDynInst : public FastAlloc, public RefCounted
void initVars();
public:
- void
- trace_mem(Fault fault, // last fault
- MemCmd cmd, // last command
- Addr addr, // virtual address of access
- void *p, // memory accessed
- int nbytes); // access size
-
/** Dumps out contents of this BaseDynInst. */
void dump();
@@ -237,6 +266,7 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** 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; }
@@ -252,12 +282,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
Addr readPredTarg() { return predPC; }
/** Returns whether the instruction was predicted taken or not. */
- bool predTaken() {
- return( predPC != (PC + sizeof(MachInst) ) );
- }
+ bool predTaken() { return predPC != (PC + sizeof(MachInst)); }
/** Returns whether the instruction mispredicted. */
- bool mispredicted() { return (predPC != nextPC); }
+ bool mispredicted() { return predPC != nextPC; }
//
// Instruction types. Forward checks to StaticInst object.
@@ -266,6 +294,8 @@ class BaseDynInst : public FastAlloc, public RefCounted
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(); }
@@ -280,9 +310,44 @@ class BaseDynInst : public FastAlloc, public RefCounted
bool isUncondCtrl() const { return staticInst->isUncondCtrl(); }
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(); }
+
+ /** 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]; }
/** Returns the opclass of this instruction. */
OpClass opClass() const { return staticInst->opClass(); }
@@ -290,10 +355,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** Returns the branch target address. */
Addr branchTarget() const { return staticInst->branchTarget(PC); }
- /** Number of source registers. */
- int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
+ /** Returns the number of source registers. */
+ int8_t numSrcRegs() const { return staticInst->numSrcRegs(); }
- /** Number of destination registers. */
+ /** Returns the number of destination registers. */
int8_t numDestRegs() const { return staticInst->numDestRegs(); }
// the following are used to track physical register usage
@@ -302,16 +367,10 @@ class BaseDynInst : public FastAlloc, public RefCounted
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);
- }
+ 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);
- }
+ RegIndex srcRegIdx(int i) const { return staticInst->srcRegIdx(i); }
/** Returns the result of an integer instruction. */
uint64_t readIntResult() { return instResult.integer; }
@@ -322,30 +381,47 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** Returns the result of a floating point (double) instruction. */
double readDoubleResult() { return instResult.dbl; }
- //Push to .cc file.
- /** Records that one of the source registers is ready. */
- void markSrcRegReady()
+ /** Records an integer register being set to a value. */
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
{
- ++readyRegs;
- if(readyRegs == numSrcRegs()) {
- canIssue = true;
- }
+ instResult.integer = val;
}
- /** Marks a specific register as ready.
- * @todo: Move this to .cc file.
- */
- void markSrcRegReady(RegIndex src_idx)
+ /** Records an fp register being set to a value. */
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
{
- ++readyRegs;
+ if (width == 32)
+ instResult.fp = val;
+ else if (width == 64)
+ instResult.dbl = val;
+ else
+ panic("Unsupported width!");
+ }
- _readySrcRegIdx[src_idx] = 1;
+ /** Records an fp register being set to a value. */
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val)
+ {
+ instResult.fp = val;
+ }
- if(readyRegs == numSrcRegs()) {
- canIssue = true;
- }
+ /** Records an fp register being set to an integer value. */
+ void setFloatRegBits(const StaticInst *si, int idx, uint64_t val, int width)
+ {
+ instResult.integer = val;
+ }
+
+ /** Records an fp register being set to an integer value. */
+ void setFloatRegBits(const StaticInst *si, int idx, uint64_t val)
+ {
+ instResult.integer = val;
}
+ /** Records that one of the source registers is ready. */
+ void markSrcRegReady();
+
+ /** Marks a specific register as ready. */
+ void markSrcRegReady(RegIndex src_idx);
+
/** Returns if a source register is ready. */
bool isReadySrcRegIdx(int idx) const
{
@@ -353,66 +429,140 @@ class BaseDynInst : public FastAlloc, public RefCounted
}
/** Sets this instruction as completed. */
- void setCompleted() { completed = true; }
+ 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 whethe or not this instruction is completed. */
- bool isCompleted() const { return completed; }
+ /** Returns whether or not the result is ready. */
+ bool isResultReady() const { return status[ResultReady]; }
/** Sets this instruction as ready to issue. */
- void setCanIssue() { canIssue = true; }
+ void setCanIssue() { status.set(CanIssue); }
/** Returns whether or not this instruction is ready to issue. */
- bool readyToIssue() const { return canIssue; }
+ bool readyToIssue() const { return status[CanIssue]; }
/** Sets this instruction as issued from the IQ. */
- void setIssued() { issued = true; }
+ void setIssued() { status.set(Issued); }
/** Returns whether or not this instruction has issued. */
- bool isIssued() const { return issued; }
+ bool isIssued() const { return status[Issued]; }
/** Sets this instruction as executed. */
- void setExecuted() { executed = true; }
+ void setExecuted() { status.set(Executed); }
/** Returns whether or not this instruction has executed. */
- bool isExecuted() const { return executed; }
+ bool isExecuted() const { return status[Executed]; }
/** Sets this instruction as ready to commit. */
- void setCanCommit() { canCommit = true; }
+ void setCanCommit() { status.set(CanCommit); }
/** Clears this instruction as being ready to commit. */
- void clearCanCommit() { canCommit = false; }
+ void clearCanCommit() { status.reset(CanCommit); }
/** Returns whether or not this instruction is ready to commit. */
- bool readyToCommit() const { return canCommit; }
+ 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() { squashed = true; }
+ void setSquashed() { status.set(Squashed); }
/** Returns whether or not this instruction is squashed. */
- bool isSquashed() const { return squashed; }
+ bool isSquashed() const { return status[Squashed]; }
+
+ //Instruction Queue Entry
+ //-----------------------
+ /** Sets this instruction as a entry the IQ. */
+ void setInIQ() { status.set(IqEntry); }
+
+ /** Sets this instruction as a entry the IQ. */
+ void clearInIQ() { status.reset(IqEntry); }
+
+ /** Returns whether or not this instruction has issued. */
+ bool isInIQ() const { return status[IqEntry]; }
/** Sets this instruction as squashed in the IQ. */
- void setSquashedInIQ() { squashedInIQ = true; }
+ void setSquashedInIQ() { status.set(SquashedInIQ); status.set(Squashed);}
/** Returns whether or not this instruction is squashed in the IQ. */
- bool isSquashedInIQ() const { return squashedInIQ; }
+ bool isSquashedInIQ() const { return status[SquashedInIQ]; }
+
+
+ //Load / Store Queue Functions
+ //-----------------------
+ /** Sets this instruction as a entry the LSQ. */
+ void setInLSQ() { status.set(LsqEntry); }
+
+ /** Sets this instruction as a entry the LSQ. */
+ void removeInLSQ() { status.reset(LsqEntry); }
+
+ /** Returns whether or not this instruction is in the LSQ. */
+ bool isInLSQ() const { return status[LsqEntry]; }
+
+ /** Sets this instruction as squashed in the LSQ. */
+ void setSquashedInLSQ() { status.set(SquashedInLSQ);}
+
+ /** Returns whether or not this instruction is squashed in the LSQ. */
+ bool isSquashedInLSQ() const { return status[SquashedInLSQ]; }
+
+
+ //Reorder Buffer Functions
+ //-----------------------
+ /** Sets this instruction as a entry the ROB. */
+ void setInROB() { status.set(RobEntry); }
+
+ /** Sets this instruction as a entry the ROB. */
+ void clearInROB() { status.reset(RobEntry); }
+
+ /** Returns whether or not this instruction is in the ROB. */
+ bool isInROB() const { return status[RobEntry]; }
+
+ /** Sets this instruction as squashed in the ROB. */
+ void setSquashedInROB() { status.set(SquashedInROB); }
+
+ /** Returns whether or not this instruction is squashed in the ROB. */
+ bool isSquashedInROB() const { return status[SquashedInROB]; }
/** Read the PC of this instruction. */
const Addr readPC() const { return PC; }
/** Set the next PC of this instruction (its actual target). */
- void setNextPC(uint64_t val) { nextPC = val; }
+ void setNextPC(uint64_t val)
+ {
+ nextPC = val;
+ }
- /** Returns the exec context.
- * @todo: Remove this once the ExecContext is no longer used.
- */
- ExecContext *xcBase() { return cpuXC->getProxy(); }
+ /** Sets the ASID. */
+ void setASID(short addr_space_id) { asid = addr_space_id; }
+
+ /** Sets the thread id. */
+ void setTid(unsigned tid) { threadNumber = tid; }
+
+ /** Sets the pointer to the thread state. */
+ void setThreadState(ImplState *state) { thread = state; }
+
+ /** Returns the thread context. */
+ ThreadContext *tcBase() { return thread->getTC(); }
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.
*/
@@ -431,12 +581,24 @@ class BaseDynInst : public FastAlloc, public RefCounted
/** Returns whether or not the eff. addr. source registers are ready. */
bool eaSrcsReady();
+ /** 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; }
};
template<class Impl>
@@ -444,34 +606,47 @@ template<class T>
inline Fault
BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
{
- MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), sizeof(T), flags);
- req->asid = asid;
+ // Sometimes reads will get retried, so they may come through here
+ // twice.
+ if (!req) {
+ req = new Request();
+ req->setVirt(asid, addr, sizeof(T), flags, this->PC);
+ req->setThreadContext(thread->readCpuId(), threadNumber);
+ } else {
+ assert(addr == req->getVaddr());
+ }
- fault = cpu->translateDataReadReq(req);
+ if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() >
+ TheISA::VMPageSize) {
+ return TheISA::genAlignmentFault();
+ }
- // Record key MemReq parameters so we can generate another one
- // just like it for the timing access without calling translate()
- // again (which might mess up the TLB).
- // Do I ever really need this? -KTL 3/05
- effAddr = req->vaddr;
- physEffAddr = req->paddr;
- memReqFlags = req->flags;
-
- /**
- * @todo
- * Replace the disjoint functional memory with a unified one and remove
- * this hack.
- */
-#if !FULL_SYSTEM
- req->paddr = req->vaddr;
-#endif
+ fault = cpu->translateDataReadReq(req, thread);
if (fault == NoFault) {
+ effAddr = req->getVaddr();
+ physEffAddr = req->getPaddr();
+ memReqFlags = req->getFlags();
+
+#if 0
+ if (cpu->system->memctrl->badaddr(physEffAddr)) {
+ fault = TheISA::genMachineCheckFault();
+ data = (T)-1;
+ this->setExecuted();
+ } else {
+ fault = cpu->read(req, data, lqIdx);
+ }
+#else
fault = cpu->read(req, data, lqIdx);
+#endif
} else {
// Return a fixed value to keep simulation deterministic even
// along misspeculated paths.
data = (T)-1;
+
+ // Commit will have to clean up whatever happened. Set this
+ // instruction as executed.
+ this->setExecuted();
}
if (traceData) {
@@ -492,36 +667,38 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
traceData->setData(data);
}
- MemReqPtr req = new MemReq(addr, cpuXC->getProxy(), sizeof(T), flags);
-
- req->asid = asid;
+ assert(req == NULL);
- fault = cpu->translateDataWriteReq(req);
+ req = new Request();
+ req->setVirt(asid, addr, sizeof(T), flags, this->PC);
+ req->setThreadContext(thread->readCpuId(), threadNumber);
- // Record key MemReq parameters so we can generate another one
- // just like it for the timing access without calling translate()
- // again (which might mess up the TLB).
- effAddr = req->vaddr;
- physEffAddr = req->paddr;
- memReqFlags = req->flags;
+ if ((req->getVaddr() & (TheISA::VMPageSize - 1)) + req->getSize() >
+ TheISA::VMPageSize) {
+ return TheISA::genAlignmentFault();
+ }
- /**
- * @todo
- * Replace the disjoint functional memory with a unified one and remove
- * this hack.
- */
-#if !FULL_SYSTEM
- req->paddr = req->vaddr;
-#endif
+ fault = cpu->translateDataWriteReq(req, thread);
if (fault == NoFault) {
+ effAddr = req->getVaddr();
+ physEffAddr = req->getPaddr();
+ memReqFlags = req->getFlags();
+#if 0
+ if (cpu->system->memctrl->badaddr(physEffAddr)) {
+ fault = TheISA::genMachineCheckFault();
+ } else {
+ fault = cpu->write(req, data, sqIdx);
+ }
+#else
fault = cpu->write(req, data, sqIdx);
+#endif
}
if (res) {
// always return some result to keep misspeculated paths
// (which will ignore faults) deterministic
- *res = (fault == NoFault) ? req->result : 0;
+ *res = (fault == NoFault) ? req->getScResult() : 0;
}
return fault;
diff --git a/src/cpu/base_dyn_inst_impl.hh b/src/cpu/base_dyn_inst_impl.hh
new file mode 100644
index 000000000..91424faad
--- /dev/null
+++ b/src/cpu/base_dyn_inst_impl.hh
@@ -0,0 +1,299 @@
+/*
+ * 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 <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/base_dyn_inst.hh"
+
+using namespace std;
+using namespace TheISA;
+
+#define NOHASH
+#ifndef NOHASH
+
+#include "base/hashmap.hh"
+
+unsigned int MyHashFunc(const BaseDynInst *addr)
+{
+ unsigned a = (unsigned)addr;
+ unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+ return hash;
+}
+
+typedef m5::hash_map<const BaseDynInst *, const BaseDynInst *, MyHashFunc>
+my_hash_t;
+
+my_hash_t thishash;
+#endif
+
+template <class Impl>
+BaseDynInst<Impl>::BaseDynInst(ExtMachInst machInst, Addr inst_PC,
+ Addr pred_PC, InstSeqNum seq_num,
+ ImplCPU *cpu)
+ : staticInst(machInst), traceData(NULL), cpu(cpu)
+{
+ seqNum = seq_num;
+
+ PC = inst_PC;
+ nextPC = PC + sizeof(MachInst);
+ predPC = pred_PC;
+
+ initVars();
+}
+
+template <class Impl>
+BaseDynInst<Impl>::BaseDynInst(StaticInstPtr &_staticInst)
+ : staticInst(_staticInst), traceData(NULL)
+{
+ seqNum = 0;
+ initVars();
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::initVars()
+{
+ req = NULL;
+ memData = NULL;
+ effAddr = 0;
+ physEffAddr = 0;
+
+ readyRegs = 0;
+
+ instResult.integer = 0;
+
+ status.reset();
+
+ eaCalcDone = false;
+ memOpDone = false;
+
+ lqIdx = -1;
+ sqIdx = -1;
+
+ // Eventually make this a parameter.
+ threadNumber = 0;
+
+ // Also make this a parameter, or perhaps get it from xc or cpu.
+ asid = 0;
+
+ // Initialize the fault to be NoFault.
+ fault = NoFault;
+
+ ++instcount;
+
+ if (instcount > 1500) {
+ cpu->dumpInsts();
+#ifdef DEBUG
+ dumpSNList();
+#endif
+ assert(instcount <= 1500);
+ }
+
+ DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction created. Instcount=%i\n",
+ seqNum, instcount);
+
+#ifdef DEBUG
+ cpu->snList.insert(seqNum);
+#endif
+}
+
+template <class Impl>
+BaseDynInst<Impl>::~BaseDynInst()
+{
+ if (req) {
+ delete req;
+ }
+
+ if (memData) {
+ delete [] memData;
+ }
+
+ if (traceData) {
+ delete traceData;
+ }
+
+ fault = NoFault;
+
+ --instcount;
+
+ DPRINTF(DynInst, "DynInst: [sn:%lli] Instruction destroyed. Instcount=%i\n",
+ seqNum, instcount);
+#ifdef DEBUG
+ cpu->snList.erase(seqNum);
+#endif
+}
+
+#ifdef DEBUG
+template <class Impl>
+void
+BaseDynInst<Impl>::dumpSNList()
+{
+ std::set<InstSeqNum>::iterator sn_it = cpu->snList.begin();
+
+ int count = 0;
+ while (sn_it != cpu->snList.end()) {
+ cprintf("%i: [sn:%lli] not destroyed\n", count, (*sn_it));
+ count++;
+ sn_it++;
+ }
+}
+#endif
+
+template <class Impl>
+void
+BaseDynInst<Impl>::prefetch(Addr addr, unsigned flags)
+{
+ // This is the "functional" implementation of prefetch. Not much
+ // happens here since prefetches don't affect the architectural
+ // state.
+/*
+ // Generate a MemReq so we can translate the effective address.
+ MemReqPtr req = new MemReq(addr, thread->getXCProxy(), 1, flags);
+ req->asid = asid;
+
+ // Prefetches never cause faults.
+ fault = NoFault;
+
+ // note this is a local, not BaseDynInst::fault
+ Fault trans_fault = cpu->translateDataReadReq(req);
+
+ if (trans_fault == NoFault && !(req->flags & UNCACHEABLE)) {
+ // It's a valid address to cacheable space. Record key MemReq
+ // parameters so we can generate another one just like it for
+ // the timing access without calling translate() again (which
+ // might mess up the TLB).
+ effAddr = req->vaddr;
+ physEffAddr = req->paddr;
+ memReqFlags = req->flags;
+ } else {
+ // Bogus address (invalid or uncacheable space). Mark it by
+ // setting the eff_addr to InvalidAddr.
+ effAddr = physEffAddr = MemReq::inval_addr;
+ }
+
+ if (traceData) {
+ traceData->setAddr(addr);
+ }
+*/
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::writeHint(Addr addr, int size, unsigned flags)
+{
+ // Not currently supported.
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+template <class Impl>
+Fault
+BaseDynInst<Impl>::copySrcTranslate(Addr src)
+{
+ // Not currently supported.
+ return NoFault;
+}
+
+/**
+ * @todo Need to find a way to get the cache block size here.
+ */
+template <class Impl>
+Fault
+BaseDynInst<Impl>::copy(Addr dest)
+{
+ // Not currently supported.
+ return NoFault;
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::dump()
+{
+ cprintf("T%d : %#08d `", threadNumber, PC);
+ cout << staticInst->disassemble(PC);
+ cprintf("'\n");
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::dump(std::string &outstring)
+{
+ std::ostringstream s;
+ s << "T" << threadNumber << " : 0x" << PC << " "
+ << staticInst->disassemble(PC);
+
+ outstring = s.str();
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::markSrcRegReady()
+{
+ if (++readyRegs == numSrcRegs()) {
+ status.set(CanIssue);
+ }
+}
+
+template <class Impl>
+void
+BaseDynInst<Impl>::markSrcRegReady(RegIndex src_idx)
+{
+ _readySrcRegIdx[src_idx] = true;
+
+ markSrcRegReady();
+}
+
+template <class Impl>
+bool
+BaseDynInst<Impl>::eaSrcsReady()
+{
+ // For now I am assuming 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)
+
+ for (int i = 1; i < numSrcRegs(); ++i) {
+ if (!_readySrcRegIdx[i])
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/cpu/checker/cpu.cc b/src/cpu/checker/cpu.cc
new file mode 100644
index 000000000..1540a6b94
--- /dev/null
+++ b/src/cpu/checker/cpu.cc
@@ -0,0 +1,408 @@
+/*
+ * 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
+ */
+
+#include <list>
+#include <string>
+
+#include "cpu/base.hh"
+#include "cpu/checker/cpu.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/static_inst.hh"
+#include "mem/packet_impl.hh"
+#include "sim/byteswap.hh"
+
+#if FULL_SYSTEM
+#include "arch/vtophys.hh"
+#include "kern/kernel_stats.hh"
+#endif // FULL_SYSTEM
+
+using namespace std;
+//The CheckerCPU does alpha only
+using namespace AlphaISA;
+
+void
+CheckerCPU::init()
+{
+}
+
+CheckerCPU::CheckerCPU(Params *p)
+ : BaseCPU(p), thread(NULL), tc(NULL)
+{
+ memReq = NULL;
+
+ numInst = 0;
+ startNumInst = 0;
+ numLoad = 0;
+ startNumLoad = 0;
+ youngestSN = 0;
+
+ changedPC = willChangePC = changedNextPC = false;
+
+ exitOnError = p->exitOnError;
+ warnOnlyOnLoadError = p->warnOnlyOnLoadError;
+#if FULL_SYSTEM
+ itb = p->itb;
+ dtb = p->dtb;
+ systemPtr = NULL;
+#else
+ process = p->process;
+#endif
+
+ result.integer = 0;
+}
+
+CheckerCPU::~CheckerCPU()
+{
+}
+
+void
+CheckerCPU::setMemory(MemObject *mem)
+{
+#if !FULL_SYSTEM
+ memPtr = mem;
+ thread = new SimpleThread(this, /* thread_num */ 0, process,
+ /* asid */ 0, mem);
+
+ thread->setStatus(ThreadContext::Suspended);
+ tc = thread->getTC();
+ threadContexts.push_back(tc);
+#endif
+}
+
+void
+CheckerCPU::setSystem(System *system)
+{
+#if FULL_SYSTEM
+ systemPtr = system;
+
+ thread = new SimpleThread(this, 0, systemPtr, itb, dtb, false);
+
+ thread->setStatus(ThreadContext::Suspended);
+ tc = thread->getTC();
+ threadContexts.push_back(tc);
+ delete thread->kernelStats;
+ thread->kernelStats = NULL;
+#endif
+}
+
+void
+CheckerCPU::setIcachePort(Port *icache_port)
+{
+ icachePort = icache_port;
+}
+
+void
+CheckerCPU::setDcachePort(Port *dcache_port)
+{
+ dcachePort = dcache_port;
+}
+
+void
+CheckerCPU::serialize(ostream &os)
+{
+/*
+ BaseCPU::serialize(os);
+ SERIALIZE_SCALAR(inst);
+ nameOut(os, csprintf("%s.xc", name()));
+ thread->serialize(os);
+ cacheCompletionEvent.serialize(os);
+*/
+}
+
+void
+CheckerCPU::unserialize(Checkpoint *cp, const string &section)
+{
+/*
+ BaseCPU::unserialize(cp, section);
+ UNSERIALIZE_SCALAR(inst);
+ thread->unserialize(cp, csprintf("%s.xc", section));
+*/
+}
+
+Fault
+CheckerCPU::copySrcTranslate(Addr src)
+{
+ panic("Unimplemented!");
+}
+
+Fault
+CheckerCPU::copy(Addr dest)
+{
+ panic("Unimplemented!");
+}
+
+template <class T>
+Fault
+CheckerCPU::read(Addr addr, T &data, unsigned flags)
+{
+ // need to fill in CPU & thread IDs here
+ memReq = new Request();
+
+ memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
+
+ // translate to physical address
+ translateDataReadReq(memReq);
+
+ Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
+
+ pkt->dataStatic(&data);
+
+ if (!(memReq->getFlags() & UNCACHEABLE)) {
+ // Access memory to see if we have the same data
+ dcachePort->sendFunctional(pkt);
+ } else {
+ // Assume the data is correct if it's an uncached access
+ memcpy(&data, &unverifiedResult.integer, sizeof(T));
+ }
+
+ delete pkt;
+
+ return NoFault;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template
+Fault
+CheckerCPU::read(Addr addr, uint64_t &data, unsigned flags);
+
+template
+Fault
+CheckerCPU::read(Addr addr, uint32_t &data, unsigned flags);
+
+template
+Fault
+CheckerCPU::read(Addr addr, uint16_t &data, unsigned flags);
+
+template
+Fault
+CheckerCPU::read(Addr addr, uint8_t &data, unsigned flags);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+CheckerCPU::read(Addr addr, double &data, unsigned flags)
+{
+ return read(addr, *(uint64_t*)&data, flags);
+}
+
+template<>
+Fault
+CheckerCPU::read(Addr addr, float &data, unsigned flags)
+{
+ return read(addr, *(uint32_t*)&data, flags);
+}
+
+template<>
+Fault
+CheckerCPU::read(Addr addr, int32_t &data, unsigned flags)
+{
+ return read(addr, (uint32_t&)data, flags);
+}
+
+template <class T>
+Fault
+CheckerCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
+{
+ // need to fill in CPU & thread IDs here
+ memReq = new Request();
+
+ memReq->setVirt(0, addr, sizeof(T), flags, thread->readPC());
+
+ // translate to physical address
+ thread->translateDataWriteReq(memReq);
+
+ // Can compare the write data and result only if it's cacheable,
+ // not a store conditional, or is a store conditional that
+ // succeeded.
+ // @todo: Verify that actual memory matches up with these values.
+ // Right now it only verifies that the instruction data is the
+ // same as what was in the request that got sent to memory; there
+ // is no verification that it is the same as what is in memory.
+ // This is because the LSQ would have to be snooped in the CPU to
+ // verify this data.
+ if (unverifiedReq &&
+ !(unverifiedReq->getFlags() & UNCACHEABLE) &&
+ (!(unverifiedReq->getFlags() & LOCKED) ||
+ ((unverifiedReq->getFlags() & LOCKED) &&
+ unverifiedReq->getScResult() == 1))) {
+ T inst_data;
+/*
+ // This code would work if the LSQ allowed for snooping.
+ Packet *pkt = new Packet(memReq, Packet::ReadReq, Packet::Broadcast);
+ pkt.dataStatic(&inst_data);
+
+ dcachePort->sendFunctional(pkt);
+
+ delete pkt;
+*/
+ memcpy(&inst_data, unverifiedMemData, sizeof(T));
+
+ if (data != inst_data) {
+ warn("%lli: Store value does not match value in memory! "
+ "Instruction: %#x, memory: %#x",
+ curTick, inst_data, data);
+ handleError();
+ }
+ }
+
+ // Assume the result was the same as the one passed in. This checker
+ // doesn't check if the SC should succeed or fail, it just checks the
+ // value.
+ if (res && unverifiedReq->scResultValid())
+ *res = unverifiedReq->getScResult();
+
+ return NoFault;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+CheckerCPU::write(uint64_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+CheckerCPU::write(uint32_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+CheckerCPU::write(uint16_t data, Addr addr, unsigned flags, uint64_t *res);
+
+template
+Fault
+CheckerCPU::write(uint8_t data, Addr addr, unsigned flags, uint64_t *res);
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
+
+template<>
+Fault
+CheckerCPU::write(double data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint64_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+CheckerCPU::write(float data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write(*(uint32_t*)&data, addr, flags, res);
+}
+
+template<>
+Fault
+CheckerCPU::write(int32_t data, Addr addr, unsigned flags, uint64_t *res)
+{
+ return write((uint32_t)data, addr, flags, res);
+}
+
+
+#if FULL_SYSTEM
+Addr
+CheckerCPU::dbg_vtophys(Addr addr)
+{
+ return vtophys(tc, 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.
+ unsigned flags = unverifiedReq->getFlags();
+ unsigned mask = LOCKED | PHYSICAL | VPTE | ALTMODE | UNCACHEABLE | NO_FAULT;
+ flags = flags & (mask);
+ if (flags == req->getFlags()) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void
+CheckerCPU::dumpAndExit()
+{
+ warn("%lli: Checker PC:%#x, next PC:%#x",
+ curTick, thread->readPC(), thread->readNextPC());
+ panic("Checker found an error!");
+}
diff --git a/src/cpu/checker/cpu.hh b/src/cpu/checker/cpu.hh
new file mode 100644
index 000000000..785387e60
--- /dev/null
+++ b/src/cpu/checker/cpu.hh
@@ -0,0 +1,402 @@
+/*
+ * 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_CHECKER_CPU_HH__
+#define __CPU_CHECKER_CPU_HH__
+
+#include <list>
+#include <queue>
+#include <map>
+
+#include "arch/types.hh"
+#include "base/statistics.hh"
+#include "config/full_system.hh"
+#include "cpu/base.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/pc_event.hh"
+#include "cpu/static_inst.hh"
+#include "sim/eventq.hh"
+
+// forward declarations
+#if FULL_SYSTEM
+class Processor;
+class AlphaITB;
+class AlphaDTB;
+class PhysicalMemory;
+
+class RemoteGDB;
+class GDBListener;
+
+#else
+
+class Process;
+
+#endif // FULL_SYSTEM
+template <class>
+class BaseDynInst;
+class ThreadContext;
+class MemInterface;
+class Checkpoint;
+class Request;
+class Sampler;
+
+/**
+ * CheckerCPU class. Dynamically verifies instructions as they are
+ * completed by making sure that the instruction and its results match
+ * the independent execution of the benchmark inside the checker. The
+ * checker verifies instructions in order, regardless of the order in
+ * which instructions complete. There are certain results that can
+ * not be verified, specifically the result of a store conditional or
+ * the values of uncached accesses. In these cases, and with
+ * instructions marked as "IsUnverifiable", the checker assumes that
+ * the value from the main CPU's execution is correct and simply
+ * copies that value. It provides a CheckerThreadContext (see
+ * checker/thread_context.hh) that provides hooks for updating the
+ * Checker's state through any ThreadContext accesses. This allows the
+ * checker to be able to correctly verify instructions, even with
+ * external accesses to the ThreadContext that change state.
+ */
+class CheckerCPU : public BaseCPU
+{
+ protected:
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+ public:
+ virtual void init();
+
+ struct Params : public BaseCPU::Params
+ {
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+#else
+ Process *process;
+#endif
+ bool exitOnError;
+ bool warnOnlyOnLoadError;
+ };
+
+ public:
+ CheckerCPU(Params *p);
+ virtual ~CheckerCPU();
+
+ Process *process;
+
+ void setMemory(MemObject *mem);
+
+ MemObject *memPtr;
+
+ void setSystem(System *system);
+
+ System *systemPtr;
+
+ void setIcachePort(Port *icache_port);
+
+ Port *icachePort;
+
+ void setDcachePort(Port *dcache_port);
+
+ Port *dcachePort;
+
+ public:
+ // Primary thread being run.
+ SimpleThread *thread;
+
+ ThreadContext *tc;
+
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+
+#if FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
+#endif
+
+ union Result {
+ uint64_t integer;
+ float fp;
+ double dbl;
+ };
+
+ Result result;
+
+ // current instruction
+ MachInst machInst;
+
+ // Pointer to the one memory request.
+ RequestPtr memReq;
+
+ StaticInstPtr curStaticInst;
+
+ // number of simulated instructions
+ Counter numInst;
+ Counter startNumInst;
+
+ std::queue<int> miscRegIdxs;
+
+ virtual Counter totalInstructions() const
+ {
+ return numInst - startNumInst;
+ }
+
+ // number of simulated loads
+ Counter numLoad;
+ Counter startNumLoad;
+
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+ // These functions are only used in CPU models that split
+ // effective address computation from the actual memory access.
+ void setEA(Addr EA) { panic("SimpleCPU::setEA() not implemented\n"); }
+ Addr getEA() { panic("SimpleCPU::getEA() not implemented\n"); }
+
+ void prefetch(Addr addr, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ void writeHint(Addr addr, int size, unsigned flags)
+ {
+ // need to do this...
+ }
+
+ Fault copySrcTranslate(Addr src);
+
+ Fault copy(Addr dest);
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntReg(const StaticInst *si, int idx)
+ {
+ return thread->readIntReg(si->srcRegIdx(idx));
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx, int width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return thread->readFloatReg(reg_idx, width);
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return thread->readFloatReg(reg_idx);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return thread->readFloatRegBits(reg_idx, width);
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
+ {
+ int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
+ return thread->readFloatRegBits(reg_idx);
+ }
+
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
+ {
+ thread->setIntReg(si->destRegIdx(idx), val);
+ result.integer = val;
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ thread->setFloatReg(reg_idx, val, width);
+ switch(width) {
+ case 32:
+ result.fp = val;
+ break;
+ case 64:
+ result.dbl = val;
+ break;
+ };
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ thread->setFloatReg(reg_idx, val);
+ result.fp = val;
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val,
+ int width)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ thread->setFloatRegBits(reg_idx, val, width);
+ result.integer = val;
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
+ {
+ int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
+ thread->setFloatRegBits(reg_idx, val);
+ result.integer = val;
+ }
+
+ uint64_t readPC() { return thread->readPC(); }
+
+ uint64_t readNextPC() { return thread->readNextPC(); }
+
+ void setNextPC(uint64_t val) {
+ thread->setNextPC(val);
+ }
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return thread->readMiscReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return thread->readMiscRegWithEffect(misc_reg, fault);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ result.integer = val;
+ miscRegIdxs.push(misc_reg);
+ return thread->setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ miscRegIdxs.push(misc_reg);
+ return thread->setMiscRegWithEffect(misc_reg, val);
+ }
+
+ void recordPCChange(uint64_t val) { changedPC = true; }
+ void recordNextPCChange(uint64_t val) { changedNextPC = true; }
+
+ bool translateInstReq(Request *req);
+ void translateDataWriteReq(Request *req);
+ void translateDataReadReq(Request *req);
+
+#if FULL_SYSTEM
+ Fault hwrei() { return thread->hwrei(); }
+ int readIntrFlag() { return thread->readIntrFlag(); }
+ void setIntrFlag(int val) { thread->setIntrFlag(val); }
+ bool inPalMode() { return thread->inPalMode(); }
+ void ev5_trap(Fault fault) { fault->invoke(tc); }
+ bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
+#else
+ // Assume that the normal CPU's call to syscall was successful.
+ // The checker's state would have already been updated by the syscall.
+ void syscall(uint64_t callnum) { }
+#endif
+
+ void handleError()
+ {
+ if (exitOnError)
+ dumpAndExit();
+ }
+
+ bool checkFlags(Request *req);
+
+ void dumpAndExit();
+
+ ThreadContext *tcBase() { return tc; }
+ SimpleThread *threadBase() { return thread; }
+
+ Result unverifiedResult;
+ Request *unverifiedReq;
+ uint8_t *unverifiedMemData;
+
+ bool changedPC;
+ bool willChangePC;
+ uint64_t newPC;
+ bool changedNextPC;
+ bool exitOnError;
+ bool warnOnlyOnLoadError;
+
+ InstSeqNum youngestSN;
+};
+
+/**
+ * Templated Checker class. This Checker class is templated on the
+ * DynInstPtr of the instruction type that will be verified. Proper
+ * template instantiations of the Checker must be placed at the bottom
+ * of checker/cpu.cc.
+ */
+template <class DynInstPtr>
+class Checker : public CheckerCPU
+{
+ public:
+ Checker(Params *p)
+ : CheckerCPU(p)
+ { }
+
+ void switchOut(Sampler *s);
+ void takeOverFrom(BaseCPU *oldCPU);
+
+ void verify(DynInstPtr &inst);
+
+ void validateInst(DynInstPtr &inst);
+ void validateExecution(DynInstPtr &inst);
+ void validateState();
+
+ void copyResult(DynInstPtr &inst);
+
+ private:
+ void handleError(DynInstPtr &inst)
+ {
+ if (exitOnError)
+ dumpAndExit(inst);
+ }
+
+ void dumpAndExit(DynInstPtr &inst);
+
+ std::list<DynInstPtr> instList;
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+ void dumpInsts();
+};
+
+#endif // __CPU_CHECKER_CPU_HH__
diff --git a/src/cpu/checker/cpu_impl.hh b/src/cpu/checker/cpu_impl.hh
new file mode 100644
index 000000000..137e1c46d
--- /dev/null
+++ b/src/cpu/checker/cpu_impl.hh
@@ -0,0 +1,460 @@
+/*
+ * 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
+ */
+
+#include <list>
+#include <string>
+
+#include "base/refcnt.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/checker/cpu.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/static_inst.hh"
+#include "mem/packet_impl.hh"
+#include "sim/byteswap.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+#if FULL_SYSTEM
+#include "arch/vtophys.hh"
+#endif // FULL_SYSTEM
+
+using namespace std;
+//The CheckerCPU does alpha only
+using namespace AlphaISA;
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::verify(DynInstPtr &completed_inst)
+{
+ DynInstPtr inst;
+
+ // Either check this instruction, or add it to a list of
+ // instructions waiting to be checked. Instructions must be
+ // checked in program order, so if a store has committed yet not
+ // completed, there may be some instructions that are waiting
+ // behind it that have completed and must be checked.
+ if (!instList.empty()) {
+ if (youngestSN < completed_inst->seqNum) {
+ DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
+ completed_inst->seqNum, completed_inst->readPC());
+ instList.push_back(completed_inst);
+ youngestSN = completed_inst->seqNum;
+ }
+
+ if (!instList.front()->isCompleted()) {
+ return;
+ } else {
+ inst = instList.front();
+ instList.pop_front();
+ }
+ } else {
+ if (!completed_inst->isCompleted()) {
+ if (youngestSN < completed_inst->seqNum) {
+ DPRINTF(Checker, "Adding instruction [sn:%lli] PC:%#x to list.\n",
+ completed_inst->seqNum, completed_inst->readPC());
+ instList.push_back(completed_inst);
+ youngestSN = completed_inst->seqNum;
+ }
+ return;
+ } else {
+ if (youngestSN < completed_inst->seqNum) {
+ inst = completed_inst;
+ youngestSN = completed_inst->seqNum;
+ } else {
+ return;
+ }
+ }
+ }
+
+ // Try to check all instructions that are completed, ending if we
+ // run out of instructions to check or if an instruction is not
+ // yet completed.
+ while (1) {
+ DPRINTF(Checker, "Processing instruction [sn:%lli] PC:%#x.\n",
+ inst->seqNum, inst->readPC());
+ unverifiedResult.integer = inst->readIntResult();
+ unverifiedReq = inst->req;
+ unverifiedMemData = inst->memData;
+ numCycles++;
+
+ Fault fault = NoFault;
+
+ // maintain $r0 semantics
+ thread->setIntReg(ZeroReg, 0);
+#ifdef TARGET_ALPHA
+ thread->setFloatRegDouble(ZeroReg, 0.0);
+#endif // TARGET_ALPHA
+
+ // Check if any recent PC changes match up with anything we
+ // expect to happen. This is mostly to check if traps or
+ // PC-based events have occurred in both the checker and CPU.
+ if (changedPC) {
+ DPRINTF(Checker, "Changed PC recently to %#x\n",
+ thread->readPC());
+ if (willChangePC) {
+ if (newPC == thread->readPC()) {
+ DPRINTF(Checker, "Changed PC matches expected PC\n");
+ } else {
+ warn("%lli: Changed PC does not match expected PC, "
+ "changed: %#x, expected: %#x",
+ curTick, thread->readPC(), newPC);
+ CheckerCPU::handleError();
+ }
+ willChangePC = false;
+ }
+ changedPC = false;
+ }
+ if (changedNextPC) {
+ DPRINTF(Checker, "Changed NextPC recently to %#x\n",
+ thread->readNextPC());
+ changedNextPC = false;
+ }
+
+ // Try to fetch the instruction
+
+#if FULL_SYSTEM
+#define IFETCH_FLAGS(pc) ((pc) & 1) ? PHYSICAL : 0
+#else
+#define IFETCH_FLAGS(pc) 0
+#endif
+
+ uint64_t fetch_PC = thread->readPC() & ~3;
+
+ // set up memory request for instruction fetch
+ memReq = new Request(inst->threadNumber, fetch_PC,
+ sizeof(uint32_t),
+ IFETCH_FLAGS(thread->readPC()),
+ fetch_PC, thread->readCpuId(), inst->threadNumber);
+
+ bool succeeded = translateInstReq(memReq);
+
+ if (!succeeded) {
+ if (inst->getFault() == NoFault) {
+ // In this case the instruction was not a dummy
+ // instruction carrying an ITB fault. In the single
+ // threaded case the ITB should still be able to
+ // translate this instruction; in the SMT case it's
+ // possible that its ITB entry was kicked out.
+ warn("%lli: Instruction PC %#x was not found in the ITB!",
+ curTick, thread->readPC());
+ handleError(inst);
+
+ // go to the next instruction
+ thread->setPC(thread->readNextPC());
+ thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
+
+ return;
+ } else {
+ // The instruction is carrying an ITB fault. Handle
+ // the fault and see if our results match the CPU on
+ // the next tick().
+ fault = inst->getFault();
+ }
+ }
+
+ if (fault == NoFault) {
+ Packet *pkt = new Packet(memReq, Packet::ReadReq,
+ Packet::Broadcast);
+
+ pkt->dataStatic(&machInst);
+
+ icachePort->sendFunctional(pkt);
+
+ delete pkt;
+
+ // keep an instruction count
+ numInst++;
+
+ // decode the instruction
+ machInst = gtoh(machInst);
+ // Checks that the instruction matches what we expected it to be.
+ // Checks both the machine instruction and the PC.
+ validateInst(inst);
+
+ curStaticInst = StaticInst::decode(makeExtMI(machInst,
+ thread->readPC()));
+
+#if FULL_SYSTEM
+ thread->setInst(machInst);
+#endif // FULL_SYSTEM
+
+ fault = inst->getFault();
+ }
+
+ // Discard fetch's memReq.
+ delete memReq;
+ memReq = NULL;
+
+ // Either the instruction was a fault and we should process the fault,
+ // or we should just go ahead execute the instruction. This assumes
+ // that the instruction is properly marked as a fault.
+ if (fault == NoFault) {
+
+ thread->funcExeInst++;
+
+ fault = curStaticInst->execute(this, NULL);
+
+ // Checks to make sure instrution results are correct.
+ validateExecution(inst);
+
+ if (curStaticInst->isLoad()) {
+ ++numLoad;
+ }
+ }
+
+ if (fault != NoFault) {
+#if FULL_SYSTEM
+ fault->invoke(tc);
+ willChangePC = true;
+ newPC = thread->readPC();
+ DPRINTF(Checker, "Fault, PC is now %#x\n", newPC);
+#else // !FULL_SYSTEM
+ fatal("fault (%d) detected @ PC 0x%08p", fault, thread->readPC());
+#endif // FULL_SYSTEM
+ } else {
+#if THE_ISA != MIPS_ISA
+ // go to the next instruction
+ thread->setPC(thread->readNextPC());
+ thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
+#else
+ // go to the next instruction
+ thread->setPC(thread->readNextPC());
+ thread->setNextPC(thread->readNextNPC());
+ thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
+#endif
+
+ }
+
+#if FULL_SYSTEM
+ // @todo: Determine if these should happen only if the
+ // instruction hasn't faulted. In the SimpleCPU case this may
+ // not be true, but in the O3 or Ozone case this may be true.
+ Addr oldpc;
+ int count = 0;
+ do {
+ oldpc = thread->readPC();
+ system->pcEventQueue.service(tc);
+ count++;
+ } while (oldpc != thread->readPC());
+ if (count > 1) {
+ willChangePC = true;
+ newPC = thread->readPC();
+ DPRINTF(Checker, "PC Event, PC is now %#x\n", newPC);
+ }
+#endif
+
+ // @todo: Optionally can check all registers. (Or just those
+ // that have been modified).
+ validateState();
+
+ if (memReq) {
+ delete memReq;
+ memReq = NULL;
+ }
+
+ // Continue verifying instructions if there's another completed
+ // instruction waiting to be verified.
+ if (instList.empty()) {
+ break;
+ } else if (instList.front()->isCompleted()) {
+ inst = instList.front();
+ instList.pop_front();
+ } else {
+ break;
+ }
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::switchOut(Sampler *s)
+{
+ instList.clear();
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::takeOverFrom(BaseCPU *oldCPU)
+{
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateInst(DynInstPtr &inst)
+{
+ if (inst->readPC() != thread->readPC()) {
+ warn("%lli: PCs do not match! Inst: %#x, checker: %#x",
+ curTick, inst->readPC(), thread->readPC());
+ if (changedPC) {
+ warn("%lli: Changed PCs recently, may not be an error",
+ curTick);
+ } else {
+ handleError(inst);
+ }
+ }
+
+ MachInst mi = static_cast<MachInst>(inst->staticInst->machInst);
+
+ if (mi != machInst) {
+ warn("%lli: Binary instructions do not match! Inst: %#x, "
+ "checker: %#x",
+ curTick, mi, machInst);
+ handleError(inst);
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateExecution(DynInstPtr &inst)
+{
+ bool result_mismatch = false;
+ if (inst->numDestRegs()) {
+ // @todo: Support more destination registers.
+ if (inst->isUnverifiable()) {
+ // Unverifiable instructions assume they were executed
+ // properly by the CPU. Grab the result from the
+ // instruction and write it to the register.
+ copyResult(inst);
+ } else if (result.integer != inst->readIntResult()) {
+ result_mismatch = true;
+ }
+ }
+
+ if (result_mismatch) {
+ warn("%lli: Instruction results do not match! (Values may not "
+ "actually be integers) Inst: %#x, checker: %#x",
+ curTick, inst->readIntResult(), result.integer);
+
+ // It's useful to verify load values from memory, but in MP
+ // systems the value obtained at execute may be different than
+ // the value obtained at completion. Similarly DMA can
+ // present the same problem on even UP systems. Thus there is
+ // the option to only warn on loads having a result error.
+ if (inst->isLoad() && warnOnlyOnLoadError) {
+ copyResult(inst);
+ } else {
+ handleError(inst);
+ }
+ }
+
+ if (inst->readNextPC() != thread->readNextPC()) {
+ warn("%lli: Instruction next PCs do not match! Inst: %#x, "
+ "checker: %#x",
+ curTick, inst->readNextPC(), thread->readNextPC());
+ handleError(inst);
+ }
+
+ // Checking side effect registers can be difficult if they are not
+ // checked simultaneously with the execution of the instruction.
+ // This is because other valid instructions may have modified
+ // these registers in the meantime, and their values are not
+ // stored within the DynInst.
+ while (!miscRegIdxs.empty()) {
+ int misc_reg_idx = miscRegIdxs.front();
+ miscRegIdxs.pop();
+
+ if (inst->tcBase()->readMiscReg(misc_reg_idx) !=
+ thread->readMiscReg(misc_reg_idx)) {
+ warn("%lli: Misc reg idx %i (side effect) does not match! "
+ "Inst: %#x, checker: %#x",
+ curTick, misc_reg_idx,
+ inst->tcBase()->readMiscReg(misc_reg_idx),
+ thread->readMiscReg(misc_reg_idx));
+ handleError(inst);
+ }
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::validateState()
+{
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::copyResult(DynInstPtr &inst)
+{
+ RegIndex idx = inst->destRegIdx(0);
+ if (idx < TheISA::FP_Base_DepTag) {
+ thread->setIntReg(idx, inst->readIntResult());
+ } else if (idx < TheISA::Fpcr_DepTag) {
+ thread->setFloatRegBits(idx, inst->readIntResult());
+ } else {
+ thread->setMiscReg(idx, inst->readIntResult());
+ }
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::dumpAndExit(DynInstPtr &inst)
+{
+ cprintf("Error detected, instruction information:\n");
+ cprintf("PC:%#x, nextPC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Completed:%i\n",
+ inst->readPC(),
+ inst->readNextPC(),
+ inst->seqNum,
+ inst->threadNumber,
+ inst->isCompleted());
+ inst->dump();
+ CheckerCPU::dumpAndExit();
+}
+
+template <class DynInstPtr>
+void
+Checker<DynInstPtr>::dumpInsts()
+{
+ int num = 0;
+
+ InstListIt inst_list_it = --(instList.end());
+
+ cprintf("Inst list size: %i\n", instList.size());
+
+ while (inst_list_it != instList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Completed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isCompleted());
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+}
diff --git a/src/cpu/checker/thread_context.hh b/src/cpu/checker/thread_context.hh
new file mode 100644
index 000000000..c0ac8f01d
--- /dev/null
+++ b/src/cpu/checker/thread_context.hh
@@ -0,0 +1,306 @@
+/*
+ * 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_CHECKER_THREAD_CONTEXT_HH__
+#define __CPU_CHECKER_THREAD_CONTEXT_HH__
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+
+class EndQuiesceEvent;
+namespace Kernel {
+ class Statistics;
+};
+
+/**
+ * Derived ThreadContext class for use with the Checker. The template
+ * parameter is the ThreadContext class used by the specific CPU being
+ * verified. This CheckerThreadContext is then used by the main CPU
+ * in place of its usual ThreadContext class. It handles updating the
+ * checker's state any time state is updated externally through the
+ * ThreadContext.
+ */
+template <class TC>
+class CheckerThreadContext : public ThreadContext
+{
+ public:
+ CheckerThreadContext(TC *actual_tc,
+ CheckerCPU *checker_cpu)
+ : actualTC(actual_tc), checkerTC(checker_cpu->thread),
+ checkerCPU(checker_cpu)
+ { }
+
+ private:
+ /** The main CPU's ThreadContext, or class that implements the
+ * ThreadContext interface. */
+ TC *actualTC;
+ /** The checker's own SimpleThread. Will be updated any time
+ * anything uses this ThreadContext to externally update a
+ * thread's state. */
+ SimpleThread *checkerTC;
+ /** Pointer to the checker CPU. */
+ CheckerCPU *checkerCPU;
+
+ public:
+
+ BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
+
+ void setCpuId(int id)
+ {
+ actualTC->setCpuId(id);
+ checkerTC->setCpuId(id);
+ }
+
+ int readCpuId() { return actualTC->readCpuId(); }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return actualTC->getSystemPtr(); }
+
+ PhysicalMemory *getPhysMemPtr() { return actualTC->getPhysMemPtr(); }
+
+ AlphaITB *getITBPtr() { return actualTC->getITBPtr(); }
+
+ AlphaDTB *getDTBPtr() { return actualTC->getDTBPtr(); }
+
+ Kernel::Statistics *getKernelStats() { return actualTC->getKernelStats(); }
+
+ FunctionalPort *getPhysPort() { return actualTC->getPhysPort(); }
+
+ VirtualPort *getVirtPort(ThreadContext *tc = NULL)
+ { return actualTC->getVirtPort(); }
+
+ void delVirtPort(VirtualPort *vp) { actualTC->delVirtPort(vp); }
+#else
+ TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
+
+ Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+#endif
+
+ Status status() const { return actualTC->status(); }
+
+ void setStatus(Status new_status)
+ {
+ actualTC->setStatus(new_status);
+ checkerTC->setStatus(new_status);
+ }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1) { actualTC->activate(delay); }
+
+ /// Set the status to Suspended.
+ void suspend() { actualTC->suspend(); }
+
+ /// Set the status to Unallocated.
+ void deallocate() { actualTC->deallocate(); }
+
+ /// Set the status to Halted.
+ void halt() { actualTC->halt(); }
+
+#if FULL_SYSTEM
+ void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
+#endif
+
+ void takeOverFrom(ThreadContext *oldContext)
+ {
+ actualTC->takeOverFrom(oldContext);
+ checkerTC->takeOverFrom(oldContext);
+ }
+
+ void regStats(const std::string &name) { actualTC->regStats(name); }
+
+ void serialize(std::ostream &os) { actualTC->serialize(os); }
+ void unserialize(Checkpoint *cp, const std::string &section)
+ { actualTC->unserialize(cp, section); }
+
+#if FULL_SYSTEM
+ EndQuiesceEvent *getQuiesceEvent() { return actualTC->getQuiesceEvent(); }
+
+ Tick readLastActivate() { return actualTC->readLastActivate(); }
+ Tick readLastSuspend() { return actualTC->readLastSuspend(); }
+
+ 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(); }
+
+ // @todo: Do I need this?
+ void copyArchRegs(ThreadContext *tc)
+ {
+ actualTC->copyArchRegs(tc);
+ checkerTC->copyArchRegs(tc);
+ }
+
+ void clearArchRegs()
+ {
+ actualTC->clearArchRegs();
+ checkerTC->clearArchRegs();
+ }
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ { return actualTC->readIntReg(reg_idx); }
+
+ FloatReg readFloatReg(int reg_idx, int width)
+ { return actualTC->readFloatReg(reg_idx, width); }
+
+ FloatReg readFloatReg(int reg_idx)
+ { return actualTC->readFloatReg(reg_idx); }
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width)
+ { return actualTC->readFloatRegBits(reg_idx, width); }
+
+ FloatRegBits readFloatRegBits(int reg_idx)
+ { return actualTC->readFloatRegBits(reg_idx); }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ {
+ actualTC->setIntReg(reg_idx, val);
+ checkerTC->setIntReg(reg_idx, val);
+ }
+
+ void setFloatReg(int reg_idx, FloatReg val, int width)
+ {
+ actualTC->setFloatReg(reg_idx, val, width);
+ checkerTC->setFloatReg(reg_idx, val, width);
+ }
+
+ void setFloatReg(int reg_idx, FloatReg val)
+ {
+ actualTC->setFloatReg(reg_idx, val);
+ checkerTC->setFloatReg(reg_idx, val);
+ }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width)
+ {
+ actualTC->setFloatRegBits(reg_idx, val, width);
+ checkerTC->setFloatRegBits(reg_idx, val, width);
+ }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val)
+ {
+ actualTC->setFloatRegBits(reg_idx, val);
+ checkerTC->setFloatRegBits(reg_idx, val);
+ }
+
+ uint64_t readPC() { return actualTC->readPC(); }
+
+ void setPC(uint64_t val)
+ {
+ actualTC->setPC(val);
+ checkerTC->setPC(val);
+ checkerCPU->recordPCChange(val);
+ }
+
+ uint64_t readNextPC() { return actualTC->readNextPC(); }
+
+ void setNextPC(uint64_t val)
+ {
+ actualTC->setNextPC(val);
+ checkerTC->setNextPC(val);
+ checkerCPU->recordNextPCChange(val);
+ }
+
+ uint64_t readNextNPC() { return actualTC->readNextNPC(); }
+
+ void setNextNPC(uint64_t val)
+ {
+ actualTC->setNextNPC(val);
+ checkerTC->setNextNPC(val);
+ checkerCPU->recordNextPCChange(val);
+ }
+
+ MiscReg readMiscReg(int misc_reg)
+ { return actualTC->readMiscReg(misc_reg); }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ { return actualTC->readMiscRegWithEffect(misc_reg, fault); }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ checkerTC->setMiscReg(misc_reg, val);
+ return actualTC->setMiscReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ checkerTC->setMiscRegWithEffect(misc_reg, val);
+ return actualTC->setMiscRegWithEffect(misc_reg, val);
+ }
+
+ unsigned readStCondFailures()
+ { return actualTC->readStCondFailures(); }
+
+ void setStCondFailures(unsigned sc_failures)
+ {
+ checkerTC->setStCondFailures(sc_failures);
+ actualTC->setStCondFailures(sc_failures);
+ }
+#if FULL_SYSTEM
+ bool inPalMode() { return actualTC->inPalMode(); }
+#endif
+
+ // @todo: Fix this!
+ 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(RegFile::ContextParam param,
+ RegFile::ContextVal 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 8d0a15f61..1add32745 100644
--- a/src/cpu/cpu_models.py
+++ b/src/cpu/cpu_models.py
@@ -23,6 +23,12 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
+
+import os
+import os.path
+import sys
################
# CpuModel class
@@ -45,7 +51,6 @@ class CpuModel:
# Add self to dict
CpuModel.dict[name] = self
-
#
# Define CPU models.
#
@@ -65,7 +70,27 @@ CpuModel('TimingSimpleCPU', 'timing_simple_cpu_exec.cc',
CpuModel('FullCPU', 'full_cpu_exec.cc',
'#include "encumbered/cpu/full/dyn_inst.hh"',
{ 'CPU_exec_context': 'DynInst' })
-CpuModel('AlphaFullCPU', 'alpha_o3_exec.cc',
- '#include "cpu/o3/alpha_dyn_inst.hh"',
- { 'CPU_exec_context': 'AlphaDynInst<AlphaSimpleImpl>' })
+CpuModel('OzoneSimpleCPU', 'ozone_simple_exec.cc',
+ '#include "cpu/ozone/dyn_inst.hh"',
+ { 'CPU_exec_context': 'OzoneDynInst<SimpleImpl>' })
+CpuModel('OzoneCPU', 'ozone_exec.cc',
+ '#include "cpu/ozone/dyn_inst.hh"',
+ { 'CPU_exec_context': 'OzoneDynInst<OzoneImpl>' })
+CpuModel('CheckerCPU', 'checker_cpu_exec.cc',
+ '#include "cpu/checker/cpu.hh"',
+ { 'CPU_exec_context': 'CheckerCPU' })
+
+# Maybe there is a more clever way to determine ISA
+# here but since the environment variable isnt passed through
+# here the easiest way is this...
+sub_template = 'not found'
+for argument in sys.argv:
+ if 'ALPHA' in argument:
+ sub_template = 'AlphaDynInst<AlphaSimpleImpl>'
+
+if sub_template == 'not found':
+ sys.exit('NO CPU_exec_context substitution defined for this ISA')
+CpuModel('O3CPU', 'o3_cpu_exec.cc',
+ '#include "cpu/o3/isa_specific.hh"',
+ { 'CPU_exec_context': sub_template })
diff --git a/src/cpu/cpuevent.cc b/src/cpu/cpuevent.cc
new file mode 100644
index 000000000..679244a6b
--- /dev/null
+++ b/src/cpu/cpuevent.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#include "cpu/cpuevent.hh"
+
+/** Static list of all CpuEvent objects so we can modify their thread
+ * contexts as needed. */
+CpuEvent::CpuEventList CpuEvent::cpuEventList;
+
+CpuEvent::~CpuEvent()
+{
+ CpuEventList::iterator i;
+
+ // delete the event from the global list
+ for (i = cpuEventList.begin(); i != cpuEventList.end(); ) {
+ if (*i == this)
+ i = cpuEventList.erase(i);
+ else
+ i++;
+ }
+}
+
+void
+CpuEvent::replaceThreadContext(ThreadContext *oldTc, ThreadContext *newTc)
+{
+ CpuEventList::iterator i;
+
+ // Update any events that have the old thread context with the new thread
+ // context
+ for (i = cpuEventList.begin(); i != cpuEventList.end(); i++) {
+ if ((*i)->tc == oldTc)
+ (*i)->tc = newTc;
+ }
+}
diff --git a/src/cpu/cpuevent.hh b/src/cpu/cpuevent.hh
new file mode 100644
index 000000000..9dfae27cf
--- /dev/null
+++ b/src/cpu/cpuevent.hh
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __CPU_CPUEVENT_HH__
+#define __CPU_CPUEVENT_HH__
+
+#include <vector>
+#include "sim/eventq.hh"
+
+class ThreadContext;
+
+/** This class creates a global list of events that need a pointer to a
+ * thread context. When a switchover takes place the events can be migrated
+ * to the new thread context, otherwise you could have a wake timer interrupt
+ * go off on a switched out cpu or other unfortunate events. This object MUST be
+ * dynamically allocated to avoid it being deleted after a cpu switch happens.
+ * */
+class CpuEvent : public Event
+{
+ private:
+ /** type of global list of cpu events. */
+ typedef std::vector<CpuEvent *> CpuEventList;
+
+ /** Static list of cpu events that is searched every time a cpu switch
+ * happens. */
+ static CpuEventList cpuEventList;
+
+ /** The thread context that is switched to the new cpus. */
+ ThreadContext *tc;
+
+ public:
+ CpuEvent(EventQueue *q, ThreadContext *_tc, Priority p = Default_Pri)
+ : Event(q, p), tc(_tc)
+ { cpuEventList.push_back(this); }
+
+ /** delete the cpu event from the global list. */
+ ~CpuEvent();
+
+ /** Update all events switching old tc to new tc.
+ * @param oldTc the old thread context we are switching from
+ * @param newTc the new thread context we are switching to.
+ */
+ static void replaceThreadContext(ThreadContext *oldTc,
+ ThreadContext *newTc);
+};
+
+template <class T, void (T::* F)(ThreadContext *tc)>
+class CpuEventWrapper : public CpuEvent
+{
+ private:
+ T *object;
+
+ public:
+ CpuEventWrapper(T *obj, ThreadContext *_tc, EventQueue *q = &mainEventQueue,
+ Priority p = Default_Pri)
+ : CpuEvent(q, _tc, p), object(obj)
+ { }
+ void process() { (object->*F)(tc); }
+};
+
+#endif // __CPU_CPUEVENT_HH__
+
diff --git a/src/cpu/exec_context.hh b/src/cpu/exec_context.hh
index 1f26183ab..f6e8d7c25 100644
--- a/src/cpu/exec_context.hh
+++ b/src/cpu/exec_context.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
+ * 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
@@ -24,427 +24,138 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_EXEC_CONTEXT_HH__
-#define __CPU_EXEC_CONTEXT_HH__
-
-#include "config/full_system.hh"
-#include "mem/request.hh"
-#include "sim/faults.hh"
-#include "sim/host.hh"
-#include "sim/serialize.hh"
-#include "sim/byteswap.hh"
-
-// @todo: Figure out a more architecture independent way to obtain the ITB and
-// DTB pointers.
-class AlphaDTB;
-class AlphaITB;
-class BaseCPU;
-class Event;
-class TranslatingPort;
-class FunctionalPort;
-class VirtualPort;
-class Process;
-class System;
-
-class ExecContext
-{
- protected:
- typedef TheISA::RegFile RegFile;
- typedef TheISA::MachInst MachInst;
- typedef TheISA::IntReg IntReg;
- typedef TheISA::FloatReg FloatReg;
- typedef TheISA::FloatRegBits FloatRegBits;
- typedef TheISA::MiscRegFile MiscRegFile;
- typedef TheISA::MiscReg MiscReg;
- public:
- enum Status
- {
- /// Initialized but not running yet. All CPUs start in
- /// this state, but most transition to Active on cycle 1.
- /// In MP or SMT systems, non-primary contexts will stay
- /// in this state until a thread is assigned to them.
- Unallocated,
-
- /// Running. Instructions should be executed only when
- /// the context is in this state.
- Active,
-
- /// Temporarily inactive. Entered while waiting for
- /// synchronization, etc.
- Suspended,
-
- /// Permanently shut down. Entered when target executes
- /// m5exit pseudo-instruction. When all contexts enter
- /// this state, the simulation will terminate.
- Halted
- };
-
- virtual ~ExecContext() { };
-
- virtual BaseCPU *getCpuPtr() = 0;
-
- virtual void setCpuId(int id) = 0;
-
- virtual int readCpuId() = 0;
-
-#if FULL_SYSTEM
- virtual System *getSystemPtr() = 0;
-
- virtual AlphaITB *getITBPtr() = 0;
-
- virtual AlphaDTB * getDTBPtr() = 0;
-
- virtual FunctionalPort *getPhysPort() = 0;
-
- virtual VirtualPort *getVirtPort(ExecContext *xc = NULL) = 0;
-
- virtual void delVirtPort(VirtualPort *vp) = 0;
-#else
- virtual TranslatingPort *getMemPort() = 0;
-
- virtual Process *getProcessPtr() = 0;
-#endif
-
- virtual Status status() const = 0;
-
- virtual void setStatus(Status new_status) = 0;
-
- /// Set the status to Active. Optional delay indicates number of
- /// cycles to wait before beginning execution.
- virtual void activate(int delay = 1) = 0;
-
- /// Set the status to Suspended.
- virtual void suspend() = 0;
-
- /// Set the status to Unallocated.
- virtual void deallocate() = 0;
-
- /// Set the status to Halted.
- virtual void halt() = 0;
-
-#if FULL_SYSTEM
- virtual void dumpFuncProfile() = 0;
-#endif
-
- virtual void takeOverFrom(ExecContext *old_context) = 0;
-
- virtual void regStats(const std::string &name) = 0;
-
- virtual void serialize(std::ostream &os) = 0;
- virtual void unserialize(Checkpoint *cp, const std::string &section) = 0;
-
-#if FULL_SYSTEM
- virtual Event *getQuiesceEvent() = 0;
-
- // Not necessarily the best location for these...
- // Having an extra function just to read these is obnoxious
- virtual Tick readLastActivate() = 0;
- virtual Tick readLastSuspend() = 0;
-
- virtual void profileClear() = 0;
- virtual void profileSample() = 0;
-#endif
-
- virtual int getThreadNum() = 0;
-
- virtual int getInstAsid() = 0;
- virtual int getDataAsid() = 0;
-
- virtual Fault translateInstReq(RequestPtr &req) = 0;
-
- virtual Fault translateDataReadReq(RequestPtr &req) = 0;
-
- virtual Fault translateDataWriteReq(RequestPtr &req) = 0;
-
- // Also somewhat obnoxious. Really only used for the TLB fault.
- // However, may be quite useful in SPARC.
- virtual TheISA::MachInst getInst() = 0;
-
- virtual void copyArchRegs(ExecContext *xc) = 0;
-
- virtual void clearArchRegs() = 0;
-
- //
- // New accessors for new decoder.
- //
- virtual uint64_t readIntReg(int reg_idx) = 0;
-
- virtual FloatReg readFloatReg(int reg_idx, int width) = 0;
-
- virtual FloatReg readFloatReg(int reg_idx) = 0;
-
- virtual FloatRegBits readFloatRegBits(int reg_idx, int width) = 0;
-
- virtual FloatRegBits readFloatRegBits(int reg_idx) = 0;
-
- virtual void setIntReg(int reg_idx, uint64_t val) = 0;
-
- virtual void setFloatReg(int reg_idx, FloatReg val, int width) = 0;
-
- virtual void setFloatReg(int reg_idx, FloatReg val) = 0;
-
- virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0;
-
- virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width) = 0;
-
- virtual uint64_t readPC() = 0;
-
- virtual void setPC(uint64_t val) = 0;
-
- virtual uint64_t readNextPC() = 0;
-
- virtual void setNextPC(uint64_t val) = 0;
-
- virtual uint64_t readNextNPC() = 0;
-
- virtual void setNextNPC(uint64_t val) = 0;
-
- virtual MiscReg readMiscReg(int misc_reg) = 0;
-
- virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0;
-
- virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0;
-
- virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0;
-
- // Also not necessarily the best location for these two. Hopefully will go
- // away once we decide upon where st cond failures goes.
- virtual unsigned readStCondFailures() = 0;
-
- virtual void setStCondFailures(unsigned sc_failures) = 0;
-
-#if FULL_SYSTEM
- virtual int readIntrFlag() = 0;
- virtual void setIntrFlag(int val) = 0;
- virtual Fault hwrei() = 0;
- virtual bool inPalMode() = 0;
- virtual bool simPalCheck(int palFunc) = 0;
-#endif
-
- // Only really makes sense for old CPU model. Still could be useful though.
- virtual bool misspeculating() = 0;
-
-#if !FULL_SYSTEM
- virtual IntReg getSyscallArg(int i) = 0;
-
- // used to shift args for indirect syscall
- virtual void setSyscallArg(int i, IntReg val) = 0;
-
- virtual void setSyscallReturn(SyscallReturn return_value) = 0;
-
- virtual void syscall(int64_t callnum) = 0;
-
- // Same with st cond failures.
- virtual Counter readFuncExeInst() = 0;
-
- virtual void setFuncExeInst(Counter new_val) = 0;
-#endif
-
- virtual void changeRegFileContext(RegFile::ContextParam param,
- RegFile::ContextVal val) = 0;
-};
-
-template <class XC>
-class ProxyExecContext : public ExecContext
-{
- public:
- ProxyExecContext(XC *actual_xc)
- { actualXC = actual_xc; }
-
- private:
- XC *actualXC;
-
- public:
+#error "Cannot include this file"
- BaseCPU *getCpuPtr() { return actualXC->getCpuPtr(); }
-
- void setCpuId(int id) { actualXC->setCpuId(id); }
-
- int readCpuId() { return actualXC->readCpuId(); }
+/**
+ * The ExecContext is not a usable class. It is simply here for
+ * documentation purposes. It shows the interface that is used by the
+ * ISA to access and change CPU state.
+ */
+class ExecContext {
+ // 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 reduce 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).
+
+ /** Reads an integer register. */
+ uint64_t readIntReg(const StaticInst *si, int idx);
+
+ /** Reads a floating point register of a specific width. */
+ FloatReg readFloatReg(const StaticInst *si, int idx, int width);
+
+ /** Reads a floating point register of single register width. */
+ FloatReg readFloatReg(const StaticInst *si, int idx);
+
+ /** Reads a floating point register of a specific width in its
+ * binary format, instead of by value. */
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width);
+
+ /** Reads a floating point register in its binary format, instead
+ * of by value. */
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx);
+
+ /** Sets an integer register to a value. */
+ void setIntReg(const StaticInst *si, int idx, uint64_t val);
+
+ /** Sets a floating point register of a specific width to a value. */
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width);
+
+ /** Sets a floating point register of single width to a value. */
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val);
+
+ /** Sets the bits of a floating point register of a specific width
+ * to a binary value. */
+ void setFloatRegBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width);
+
+ /** Sets the bits of a floating point register of single width
+ * to a binary value. */
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val);
+
+ /** Reads the PC. */
+ uint64_t readPC();
+ /** Reads the NextPC. */
+ uint64_t readNextPC();
+ /** Reads the Next-NextPC. Only for architectures like SPARC or MIPS. */
+ uint64_t readNextNPC();
+
+ /** Sets the PC. */
+ void setPC(uint64_t val);
+ /** Sets the NextPC. */
+ void setNextPC(uint64_t val);
+ /** Sets the Next-NextPC. Only for architectures like SPARC or MIPS. */
+ void setNextNPC(uint64_t val);
+
+ /** Reads a miscellaneous register. */
+ MiscReg readMiscReg(int misc_reg);
+
+ /** Reads a miscellaneous register, handling any architectural
+ * side effects due to reading that register. */
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault);
+
+ /** Sets a miscellaneous register. */
+ Fault setMiscReg(int misc_reg, const MiscReg &val);
+
+ /** Sets a miscellaneous register, handling any architectural
+ * side effects due to writing that register. */
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val);
+
+ /** Records the effective address of the instruction. Only valid
+ * for memory ops. */
+ void setEA(Addr EA);
+ /** Returns the effective address of the instruction. Only valid
+ * for memory ops. */
+ Addr getEA();
+
+ /** Returns a pointer to the ThreadContext. */
+ ThreadContext *tcBase();
+
+ /** Reads an address, creating a memory request with the given
+ * flags. Stores result of read in data. */
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ /** Writes to an address, creating a memory request with the given
+ * flags. Writes data to memory. For store conditionals, returns
+ * the result of the store in res. */
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+ /** Prefetches an address, creating a memory request with the
+ * given flags. */
+ void prefetch(Addr addr, unsigned flags);
+
+ /** Hints to the memory system that an address will be written to
+ * soon, with the given size. Creates a memory request with the
+ * given flags. */
+ void writeHint(Addr addr, int size, unsigned flags);
#if FULL_SYSTEM
- System *getSystemPtr() { return actualXC->getSystemPtr(); }
-
- AlphaITB *getITBPtr() { return actualXC->getITBPtr(); }
-
- AlphaDTB *getDTBPtr() { return actualXC->getDTBPtr(); }
-
- FunctionalPort *getPhysPort() { return actualXC->getPhysPort(); }
-
- VirtualPort *getVirtPort(ExecContext *xc = NULL) { return actualXC->getVirtPort(xc); }
-
- void delVirtPort(VirtualPort *vp) { return actualXC->delVirtPort(vp); }
+ /** Somewhat Alpha-specific function that handles returning from
+ * an error or interrupt. */
+ Fault hwrei();
+ /** Reads the interrupt flags. */
+ int readIntrFlag();
+ /** Sets the interrupt flags to a value. */
+ void setIntrFlag(int val);
+
+ /**
+ * Check for special simulator handling of specific PAL calls. If
+ * return value is false, actual PAL call will be suppressed.
+ */
+ bool simPalCheck(int palFunc);
#else
- TranslatingPort *getMemPort() { return actualXC->getMemPort(); }
-
- Process *getProcessPtr() { return actualXC->getProcessPtr(); }
-#endif
-
- Status status() const { return actualXC->status(); }
-
- void setStatus(Status new_status) { actualXC->setStatus(new_status); }
-
- /// Set the status to Active. Optional delay indicates number of
- /// cycles to wait before beginning execution.
- void activate(int delay = 1) { actualXC->activate(delay); }
-
- /// Set the status to Suspended.
- void suspend() { actualXC->suspend(); }
-
- /// Set the status to Unallocated.
- void deallocate() { actualXC->deallocate(); }
-
- /// Set the status to Halted.
- void halt() { actualXC->halt(); }
-
-#if FULL_SYSTEM
- void dumpFuncProfile() { actualXC->dumpFuncProfile(); }
-#endif
-
- void takeOverFrom(ExecContext *oldContext)
- { actualXC->takeOverFrom(oldContext); }
-
- void regStats(const std::string &name) { actualXC->regStats(name); }
-
- void serialize(std::ostream &os) { actualXC->serialize(os); }
- void unserialize(Checkpoint *cp, const std::string &section)
- { actualXC->unserialize(cp, section); }
-
-#if FULL_SYSTEM
- Event *getQuiesceEvent() { return actualXC->getQuiesceEvent(); }
-
- Tick readLastActivate() { return actualXC->readLastActivate(); }
- Tick readLastSuspend() { return actualXC->readLastSuspend(); }
-
- void profileClear() { return actualXC->profileClear(); }
- void profileSample() { return actualXC->profileSample(); }
+ /** Executes a syscall specified by the callnum. */
+ void syscall(int64_t callnum);
#endif
-
- int getThreadNum() { return actualXC->getThreadNum(); }
-
- int getInstAsid() { return actualXC->getInstAsid(); }
- int getDataAsid() { return actualXC->getDataAsid(); }
-
- Fault translateInstReq(RequestPtr &req)
- { return actualXC->translateInstReq(req); }
-
- Fault translateDataReadReq(RequestPtr &req)
- { return actualXC->translateDataReadReq(req); }
-
- Fault translateDataWriteReq(RequestPtr &req)
- { return actualXC->translateDataWriteReq(req); }
-
- // @todo: Do I need this?
- MachInst getInst() { return actualXC->getInst(); }
-
- // @todo: Do I need this?
- void copyArchRegs(ExecContext *xc) { actualXC->copyArchRegs(xc); }
-
- void clearArchRegs() { actualXC->clearArchRegs(); }
-
- //
- // New accessors for new decoder.
- //
- uint64_t readIntReg(int reg_idx)
- { return actualXC->readIntReg(reg_idx); }
-
- FloatReg readFloatReg(int reg_idx, int width)
- { return actualXC->readFloatReg(reg_idx, width); }
-
- FloatReg readFloatReg(int reg_idx)
- { return actualXC->readFloatReg(reg_idx); }
-
- FloatRegBits readFloatRegBits(int reg_idx, int width)
- { return actualXC->readFloatRegBits(reg_idx, width); }
-
- FloatRegBits readFloatRegBits(int reg_idx)
- { return actualXC->readFloatRegBits(reg_idx); }
-
- void setIntReg(int reg_idx, uint64_t val)
- { actualXC->setIntReg(reg_idx, val); }
-
- void setFloatReg(int reg_idx, FloatReg val, int width)
- { actualXC->setFloatReg(reg_idx, val, width); }
-
- void setFloatReg(int reg_idx, FloatReg val)
- { actualXC->setFloatReg(reg_idx, val); }
-
- void setFloatRegBits(int reg_idx, FloatRegBits val, int width)
- { actualXC->setFloatRegBits(reg_idx, val, width); }
-
- void setFloatRegBits(int reg_idx, FloatRegBits val)
- { actualXC->setFloatRegBits(reg_idx, val); }
-
- uint64_t readPC() { return actualXC->readPC(); }
-
- void setPC(uint64_t val) { actualXC->setPC(val); }
-
- uint64_t readNextPC() { return actualXC->readNextPC(); }
-
- void setNextPC(uint64_t val) { actualXC->setNextPC(val); }
-
- uint64_t readNextNPC() { return actualXC->readNextNPC(); }
-
- void setNextNPC(uint64_t val) { actualXC->setNextNPC(val); }
-
- MiscReg readMiscReg(int misc_reg)
- { return actualXC->readMiscReg(misc_reg); }
-
- MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
- { return actualXC->readMiscRegWithEffect(misc_reg, fault); }
-
- Fault setMiscReg(int misc_reg, const MiscReg &val)
- { return actualXC->setMiscReg(misc_reg, val); }
-
- Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
- { return actualXC->setMiscRegWithEffect(misc_reg, val); }
-
- unsigned readStCondFailures()
- { return actualXC->readStCondFailures(); }
-
- void setStCondFailures(unsigned sc_failures)
- { actualXC->setStCondFailures(sc_failures); }
-
-#if FULL_SYSTEM
- int readIntrFlag() { return actualXC->readIntrFlag(); }
-
- void setIntrFlag(int val) { actualXC->setIntrFlag(val); }
-
- Fault hwrei() { return actualXC->hwrei(); }
-
- bool inPalMode() { return actualXC->inPalMode(); }
-
- bool simPalCheck(int palFunc) { return actualXC->simPalCheck(palFunc); }
-#endif
-
- // @todo: Fix this!
- bool misspeculating() { return actualXC->misspeculating(); }
-
-#if !FULL_SYSTEM
- IntReg getSyscallArg(int i) { return actualXC->getSyscallArg(i); }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- { actualXC->setSyscallArg(i, val); }
-
- void setSyscallReturn(SyscallReturn return_value)
- { actualXC->setSyscallReturn(return_value); }
-
- void syscall(int64_t callnum) { actualXC->syscall(callnum); }
-
- Counter readFuncExeInst() { return actualXC->readFuncExeInst(); }
-
- void setFuncExeInst(Counter new_val)
- { return actualXC->setFuncExeInst(new_val); }
-#endif
-
- void changeRegFileContext(RegFile::ContextParam param,
- RegFile::ContextVal val)
- {
- actualXC->changeRegFileContext(param, val);
- }
};
-
-#endif
diff --git a/src/cpu/exetrace.cc b/src/cpu/exetrace.cc
index 0ed3b43c4..7fdad5113 100644
--- a/src/cpu/exetrace.cc
+++ b/src/cpu/exetrace.cc
@@ -24,6 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
+ * Nathan Binkert
+ * Steve Raasch
*/
#include <fstream>
@@ -82,7 +87,8 @@ Trace::InstRecord::dump(ostream &outs)
std::string sym_str;
Addr sym_addr;
if (debugSymbolTable
- && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)) {
+ && debugSymbolTable->findNearestSymbol(PC, sym_str, sym_addr)
+ && flags[PC_SYMBOL]) {
if (PC != sym_addr)
sym_str += csprintf("+%d", PC - sym_addr);
outs << "@" << sym_str << " : ";
@@ -190,6 +196,8 @@ Param<bool> exe_trace_print_fetchseq(&exeTraceParams, "print_fetchseq",
"print fetch sequence number", false);
Param<bool> exe_trace_print_cp_seq(&exeTraceParams, "print_cpseq",
"print correct-path sequence number", false);
+Param<bool> exe_trace_pc_symbol(&exeTraceParams, "pc_symbol",
+ "Use symbols for the PC if available", true);
Param<bool> exe_trace_intel_format(&exeTraceParams, "intel_format",
"print trace in intel compatible format", false);
Param<string> exe_trace_system(&exeTraceParams, "trace_system",
@@ -214,6 +222,7 @@ Trace::InstRecord::setParams()
flags[PRINT_INT_REGS] = exe_trace_print_iregs;
flags[PRINT_FETCH_SEQ] = exe_trace_print_fetchseq;
flags[PRINT_CP_SEQ] = exe_trace_print_cp_seq;
+ flags[PC_SYMBOL] = exe_trace_pc_symbol;
flags[INTEL_FORMAT] = exe_trace_intel_format;
trace_system = exe_trace_system;
}
diff --git a/src/cpu/exetrace.hh b/src/cpu/exetrace.hh
index a26cdc517..95f8b449c 100644
--- a/src/cpu/exetrace.hh
+++ b/src/cpu/exetrace.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __EXETRACE_HH__
@@ -35,7 +38,7 @@
#include "sim/host.hh"
#include "cpu/inst_seq.hh" // for InstSeqNum
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/static_inst.hh"
class BaseCPU;
@@ -144,6 +147,7 @@ class InstRecord : public Record
PRINT_INT_REGS,
PRINT_FETCH_SEQ,
PRINT_CP_SEQ,
+ PC_SYMBOL,
INTEL_FORMAT,
NUM_BITS
};
@@ -169,14 +173,14 @@ InstRecord::setRegs(const IntRegFile &regs)
inline
InstRecord *
-getInstRecord(Tick cycle, ExecContext *xc, BaseCPU *cpu,
+getInstRecord(Tick cycle, ThreadContext *tc, BaseCPU *cpu,
const StaticInstPtr staticInst,
Addr pc, int thread = 0)
{
if (DTRACE(InstExec) &&
- (InstRecord::traceMisspec() || !xc->misspeculating())) {
+ (InstRecord::traceMisspec() || !tc->misspeculating())) {
return new InstRecord(cycle, cpu, staticInst, pc,
- xc->misspeculating(), thread);
+ tc->misspeculating(), thread);
}
return NULL;
diff --git a/src/cpu/func_unit.cc b/src/cpu/func_unit.cc
new file mode 100644
index 000000000..c20578a43
--- /dev/null
+++ b/src/cpu/func_unit.cc
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2002-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Raasch
+ */
+
+#include <sstream>
+
+#include "base/misc.hh"
+#include "cpu/func_unit.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+
+////////////////////////////////////////////////////////////////////////////
+//
+// The funciton unit
+//
+FuncUnit::FuncUnit()
+{
+ capabilityList.reset();
+}
+
+
+// Copy constructor
+FuncUnit::FuncUnit(const FuncUnit &fu)
+{
+
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ opLatencies[i] = fu.opLatencies[i];
+ issueLatencies[i] = fu.issueLatencies[i];
+ }
+
+ capabilityList = fu.capabilityList;
+}
+
+
+void
+FuncUnit::addCapability(OpClass cap, unsigned oplat, unsigned issuelat)
+{
+ if (issuelat == 0 || oplat == 0)
+ panic("FuncUnit: you don't really want a zero-cycle latency do you?");
+
+ capabilityList.set(cap);
+
+ opLatencies[cap] = oplat;
+ issueLatencies[cap] = issuelat;
+}
+
+bool
+FuncUnit::provides(OpClass capability)
+{
+ return capabilityList[capability];
+}
+
+bitset<Num_OpClasses>
+FuncUnit::capabilities()
+{
+ return capabilityList;
+}
+
+unsigned &
+FuncUnit::opLatency(OpClass cap)
+{
+ return opLatencies[cap];
+}
+
+unsigned
+FuncUnit::issueLatency(OpClass capability)
+{
+ return issueLatencies[capability];
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// The SimObjects we use to get the FU information into the simulator
+//
+////////////////////////////////////////////////////////////////////////////
+
+//
+// We use 2 objects to specify this data in the INI file:
+// (1) OpDesc - Describes the operation class & latencies
+// (multiple OpDesc objects can refer to the same
+// operation classes)
+// (2) FUDesc - Describes the operations available in the unit &
+// the number of these units
+//
+//
+
+
+//
+// The operation-class description object
+//
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(OpDesc)
+
+ SimpleEnumParam<OpClass> opClass;
+ Param<unsigned> opLat;
+ Param<unsigned> issueLat;
+
+END_DECLARE_SIM_OBJECT_PARAMS(OpDesc)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(OpDesc)
+
+ INIT_ENUM_PARAM(opClass, "type of operation", opClassStrings),
+ INIT_PARAM(opLat, "cycles until result is available"),
+ INIT_PARAM(issueLat, "cycles until another can be issued")
+
+END_INIT_SIM_OBJECT_PARAMS(OpDesc)
+
+
+CREATE_SIM_OBJECT(OpDesc)
+{
+ return new OpDesc(getInstanceName(), opClass, opLat, issueLat);
+}
+
+REGISTER_SIM_OBJECT("OpDesc", OpDesc)
+
+
+//
+// The FuDesc object
+//
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(FUDesc)
+
+ SimObjectVectorParam<OpDesc *> opList;
+ Param<unsigned> count;
+
+END_DECLARE_SIM_OBJECT_PARAMS(FUDesc)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(FUDesc)
+
+ INIT_PARAM(opList, "list of operation classes for this FU type"),
+ INIT_PARAM(count, "number of these FU's available")
+
+END_INIT_SIM_OBJECT_PARAMS(FUDesc)
+
+
+CREATE_SIM_OBJECT(FUDesc)
+{
+ return new FUDesc(getInstanceName(), opList, count);
+}
+
+REGISTER_SIM_OBJECT("FUDesc", FUDesc)
+
diff --git a/src/cpu/func_unit.hh b/src/cpu/func_unit.hh
new file mode 100644
index 000000000..780143096
--- /dev/null
+++ b/src/cpu/func_unit.hh
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2002-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Raasch
+ */
+
+#ifndef __CPU_FUNC_UNIT_HH__
+#define __CPU_FUNC_UNIT_HH__
+
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include "cpu/op_class.hh"
+#include "sim/sim_object.hh"
+
+////////////////////////////////////////////////////////////////////////////
+//
+// Structures used ONLY during the initialization phase...
+//
+//
+//
+
+struct OpDesc : public SimObject
+{
+ OpClass opClass;
+ unsigned opLat;
+ unsigned issueLat;
+
+ OpDesc(std::string name, OpClass c, unsigned o, unsigned i)
+ : SimObject(name), opClass(c), opLat(o), issueLat(i) {};
+};
+
+struct FUDesc : public SimObject
+{
+ std::vector<OpDesc *> opDescList;
+ unsigned number;
+
+ FUDesc(std::string name, std::vector<OpDesc *> l, unsigned n)
+ : SimObject(name), opDescList(l), number(n) {};
+};
+
+typedef std::vector<OpDesc *>::iterator OPDDiterator;
+typedef std::vector<FUDesc *>::iterator FUDDiterator;
+
+
+
+
+////////////////////////////////////////////////////////////////////////////
+//
+// The actual FU object
+//
+//
+//
+class FuncUnit
+{
+ private:
+ unsigned opLatencies[Num_OpClasses];
+ unsigned issueLatencies[Num_OpClasses];
+ std::bitset<Num_OpClasses> capabilityList;
+
+ public:
+ FuncUnit();
+ FuncUnit(const FuncUnit &fu);
+
+ std::string name;
+
+ void addCapability(OpClass cap, unsigned oplat, unsigned issuelat);
+
+ bool provides(OpClass capability);
+ std::bitset<Num_OpClasses> capabilities();
+
+ unsigned &opLatency(OpClass capability);
+ unsigned issueLatency(OpClass capability);
+};
+
+#endif // __FU_POOL_HH__
diff --git a/src/cpu/inst_seq.hh b/src/cpu/inst_seq.hh
index 8de047af7..e7acd215f 100644
--- a/src/cpu/inst_seq.hh
+++ b/src/cpu/inst_seq.hh
@@ -24,11 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
*/
#ifndef __STD_TYPES_HH__
#define __STD_TYPES_HH__
+#include <stdint.h>
+
// inst sequence type, used to order instructions in the ready list,
// if this rolls over the ready list order temporarily will get messed
// up, but execution will continue and complete correctly
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
index 43e7f654c..4cbc86891 100644
--- a/src/cpu/intr_control.cc
+++ b/src/cpu/intr_control.cc
@@ -24,13 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ron Dreslinski
*/
#include <string>
#include <vector>
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/intr_control.hh"
#include "sim/builder.hh"
#include "sim/sim_object.hh"
@@ -48,32 +51,32 @@ IntrControl::IntrControl(const string &name, BaseCPU *c)
void
IntrControl::post(int int_num, int index)
{
- std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
- BaseCPU *temp = xcvec[0]->getCpuPtr();
+ std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts;
+ BaseCPU *temp = tcvec[0]->getCpuPtr();
temp->post_interrupt(int_num, index);
}
void
IntrControl::post(int cpu_id, int int_num, int index)
{
- std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
- BaseCPU *temp = xcvec[cpu_id]->getCpuPtr();
+ std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts;
+ BaseCPU *temp = tcvec[cpu_id]->getCpuPtr();
temp->post_interrupt(int_num, index);
}
void
IntrControl::clear(int int_num, int index)
{
- std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
- BaseCPU *temp = xcvec[0]->getCpuPtr();
+ std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts;
+ BaseCPU *temp = tcvec[0]->getCpuPtr();
temp->clear_interrupt(int_num, index);
}
void
IntrControl::clear(int cpu_id, int int_num, int index)
{
- std::vector<ExecContext *> &xcvec = cpu->system->execContexts;
- BaseCPU *temp = xcvec[cpu_id]->getCpuPtr();
+ std::vector<ThreadContext *> &tcvec = cpu->system->threadContexts;
+ BaseCPU *temp = tcvec[cpu_id]->getCpuPtr();
temp->clear_interrupt(int_num, index);
}
diff --git a/src/cpu/intr_control.hh b/src/cpu/intr_control.hh
index 5ec4e14cb..2e3f9e038 100644
--- a/src/cpu/intr_control.hh
+++ b/src/cpu/intr_control.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ron Dreslinski
*/
#ifndef __INTR_CONTROL_HH__
diff --git a/src/cpu/memtest/memtest.cc b/src/cpu/memtest/memtest.cc
index 54def1012..7ea9eaefc 100644
--- a/src/cpu/memtest/memtest.cc
+++ b/src/cpu/memtest/memtest.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
+ * Steve Reinhardt
*/
// FIX ME: make trackBlkAddr use blocksize from actual cache, not hard coded
@@ -35,7 +38,7 @@
#include "base/misc.hh"
#include "base/statistics.hh"
-#include "cpu/cpu_exec_context.hh"
+#include "cpu/simple_thread.hh"
#include "cpu/memtest/memtest.hh"
#include "mem/cache/base_cache.hh"
#include "sim/builder.hh"
@@ -78,7 +81,7 @@ MemTest::MemTest(const string &name,
vector<string> cmd;
cmd.push_back("/bin/ls");
vector<string> null_vec;
- cpuXC = new CPUExecContext(NULL, 0, mainMem, 0);
+ thread = new SimpleThread(NULL, 0, mainMem, 0);
blockSize = cacheInterface->getBlockSize();
blockAddrMask = blockSize - 1;
@@ -268,7 +271,7 @@ MemTest::tick()
req->data = new uint8_t[req->size];
req->paddr &= ~(req->size - 1);
req->time = curTick;
- req->xc = cpuXC->getProxy();
+ req->xc = thread->getProxy();
if (cmd < percentReads) {
// read
diff --git a/src/cpu/memtest/memtest.hh b/src/cpu/memtest/memtest.hh
index cdb40a26a..42fb235db 100644
--- a/src/cpu/memtest/memtest.hh
+++ b/src/cpu/memtest/memtest.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
+ * Steve Reinhardt
*/
#ifndef __CPU_MEMTEST_MEMTEST_HH__
@@ -39,7 +42,7 @@
#include "sim/sim_object.hh"
#include "sim/stats.hh"
-class ExecContext;
+class ThreadContext;
class MemTest : public SimObject
{
public:
@@ -83,7 +86,7 @@ class MemTest : public SimObject
MemInterface *cacheInterface;
FunctionalMemory *mainMem;
FunctionalMemory *checkMem;
- CPUExecContext *cpuXC;
+ SimpleThread *thread;
unsigned size; // size of testing memory region
diff --git a/src/cpu/o3/2bit_local_pred.cc b/src/cpu/o3/2bit_local_pred.cc
index d9744eec7..77a45ea26 100644
--- a/src/cpu/o3/2bit_local_pred.cc
+++ b/src/cpu/o3/2bit_local_pred.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,29 +24,41 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/intmath.hh"
+#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/o3/2bit_local_pred.hh"
-DefaultBP::DefaultBP(unsigned _localPredictorSize,
- unsigned _localCtrBits,
- unsigned _instShiftAmt)
+LocalBP::LocalBP(unsigned _localPredictorSize,
+ unsigned _localCtrBits,
+ unsigned _instShiftAmt)
: localPredictorSize(_localPredictorSize),
localCtrBits(_localCtrBits),
instShiftAmt(_instShiftAmt)
{
- // Should do checks here to make sure sizes are correct (powers of 2).
+ if (!isPowerOf2(localPredictorSize)) {
+ fatal("Invalid local predictor size!\n");
+ }
+
+ localPredictorSets = localPredictorSize / localCtrBits;
+
+ if (!isPowerOf2(localPredictorSets)) {
+ fatal("Invalid number of local predictor sets! Check localCtrBits.\n");
+ }
// Setup the index mask.
- indexMask = localPredictorSize - 1;
+ indexMask = localPredictorSets - 1;
DPRINTF(Fetch, "Branch predictor: index mask: %#x\n", indexMask);
// Setup the array of counters for the local predictor.
- localCtrs = new SatCounter[localPredictorSize];
+ localCtrs.resize(localPredictorSets);
- for (int i = 0; i < localPredictorSize; ++i)
+ for (int i = 0; i < localPredictorSets; ++i)
localCtrs[i].setBits(_localCtrBits);
DPRINTF(Fetch, "Branch predictor: local predictor size: %i\n",
@@ -58,24 +70,30 @@ DefaultBP::DefaultBP(unsigned _localPredictorSize,
instShiftAmt);
}
+void
+LocalBP::reset()
+{
+ for (int i = 0; i < localPredictorSets; ++i) {
+ localCtrs[i].reset();
+ }
+}
+
bool
-DefaultBP::lookup(Addr &branch_addr)
+LocalBP::lookup(Addr &branch_addr, void * &bp_history)
{
bool taken;
- uint8_t local_prediction;
+ uint8_t counter_val;
unsigned local_predictor_idx = getLocalIndex(branch_addr);
DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n",
local_predictor_idx);
- assert(local_predictor_idx < localPredictorSize);
-
- local_prediction = localCtrs[local_predictor_idx].read();
+ counter_val = localCtrs[local_predictor_idx].read();
DPRINTF(Fetch, "Branch predictor: prediction is %i.\n",
- (int)local_prediction);
+ (int)counter_val);
- taken = getPrediction(local_prediction);
+ taken = getPrediction(counter_val);
#if 0
// Speculative update.
@@ -92,8 +110,9 @@ DefaultBP::lookup(Addr &branch_addr)
}
void
-DefaultBP::update(Addr &branch_addr, bool taken)
+LocalBP::update(Addr &branch_addr, bool taken, void *bp_history)
{
+ assert(bp_history == NULL);
unsigned local_predictor_idx;
// Update the local predictor.
@@ -102,8 +121,6 @@ DefaultBP::update(Addr &branch_addr, bool taken)
DPRINTF(Fetch, "Branch predictor: Looking up index %#x\n",
local_predictor_idx);
- assert(local_predictor_idx < localPredictorSize);
-
if (taken) {
DPRINTF(Fetch, "Branch predictor: Branch updated as taken.\n");
localCtrs[local_predictor_idx].increment();
@@ -115,7 +132,7 @@ DefaultBP::update(Addr &branch_addr, bool taken)
inline
bool
-DefaultBP::getPrediction(uint8_t &count)
+LocalBP::getPrediction(uint8_t &count)
{
// Get the MSB of the count
return (count >> (localCtrBits - 1));
@@ -123,7 +140,7 @@ DefaultBP::getPrediction(uint8_t &count)
inline
unsigned
-DefaultBP::getLocalIndex(Addr &branch_addr)
+LocalBP::getLocalIndex(Addr &branch_addr)
{
return (branch_addr >> instShiftAmt) & indexMask;
}
diff --git a/src/cpu/o3/2bit_local_pred.hh b/src/cpu/o3/2bit_local_pred.hh
index 97433e542..0a2a71d3e 100644
--- a/src/cpu/o3/2bit_local_pred.hh
+++ b/src/cpu/o3/2bit_local_pred.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,43 +24,65 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_2BIT_LOCAL_PRED_HH__
-#define __CPU_O3_CPU_2BIT_LOCAL_PRED_HH__
+#ifndef __CPU_O3_2BIT_LOCAL_PRED_HH__
+#define __CPU_O3_2BIT_LOCAL_PRED_HH__
// For Addr type.
#include "arch/isa_traits.hh"
#include "cpu/o3/sat_counter.hh"
-class DefaultBP
+#include <vector>
+
+/**
+ * Implements a local predictor that uses the PC to index into a table of
+ * counters. Note that any time a pointer to the bp_history is given, it
+ * should be NULL using this predictor because it does not have any branch
+ * predictor state that needs to be recorded or updated; the update can be
+ * determined solely by the branch being taken or not taken.
+ */
+class LocalBP
{
public:
/**
* Default branch predictor constructor.
+ * @param localPredictorSize Size of the local predictor.
+ * @param localCtrBits Number of bits per counter.
+ * @param instShiftAmt Offset amount for instructions to ignore alignment.
*/
- DefaultBP(unsigned localPredictorSize, unsigned localCtrBits,
- unsigned instShiftAmt);
+ LocalBP(unsigned localPredictorSize, unsigned localCtrBits,
+ unsigned instShiftAmt);
/**
* Looks up the given address in the branch predictor and returns
* a true/false value as to whether it is taken.
* @param branch_addr The address of the branch to look up.
+ * @param bp_history Pointer to any bp history state.
* @return Whether or not the branch is taken.
*/
- bool lookup(Addr &branch_addr);
+ bool lookup(Addr &branch_addr, void * &bp_history);
/**
* Updates the branch predictor with the actual result of a branch.
* @param branch_addr The address of the branch to update.
* @param taken Whether or not the branch was taken.
*/
- void update(Addr &branch_addr, bool taken);
+ void update(Addr &branch_addr, bool taken, void *bp_history);
- private:
+ void squash(void *bp_history)
+ { assert(bp_history == NULL); }
- /** Returns the taken/not taken prediction given the value of the
+ void reset();
+
+ private:
+ /**
+ * Returns the taken/not taken prediction given the value of the
* counter.
+ * @param count The value of the counter.
+ * @return The prediction based on the counter value.
*/
inline bool getPrediction(uint8_t &count);
@@ -68,11 +90,14 @@ class DefaultBP
inline unsigned getLocalIndex(Addr &PC);
/** Array of counters that make up the local predictor. */
- SatCounter *localCtrs;
+ std::vector<SatCounter> localCtrs;
/** Size of the local predictor. */
unsigned localPredictorSize;
+ /** Number of sets. */
+ unsigned localPredictorSets;
+
/** Number of bits of the local predictor's counters. */
unsigned localCtrBits;
@@ -83,4 +108,4 @@ class DefaultBP
unsigned indexMask;
};
-#endif // __CPU_O3_CPU_2BIT_LOCAL_PRED_HH__
+#endif // __CPU_O3_2BIT_LOCAL_PRED_HH__
diff --git a/src/cpu/o3/SConscript b/src/cpu/o3/SConscript
new file mode 100755
index 000000000..e65d41411
--- /dev/null
+++ b/src/cpu/o3/SConscript
@@ -0,0 +1,79 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Korey Sewell
+
+import os
+import os.path
+import sys
+
+# Import build environment variable from SConstruct.
+Import('env')
+
+
+#################################################################
+#
+# Include ISA-specific files for the O3 CPU-model
+#
+#################################################################
+
+sources = []
+
+if env['TARGET_ISA'] == 'alpha':
+ sources += Split('''
+ alpha/dyn_inst.cc
+ alpha/cpu.cc
+ alpha/thread_context.cc
+ alpha/cpu_builder.cc
+ ''')
+elif env['TARGET_ISA'] == 'mips':
+ sys.exit('O3 CPU does not support MIPS')
+ #sources += Split('''
+ # mips/dyn_inst.cc
+ # mips/cpu.cc
+ # mips/thread_context.cc
+ # mips/cpu_builder.cc
+ # ''')
+elif env['TARGET_ISA'] == 'sparc':
+ sys.exit('O3 CPU does not support MIPS')
+ #sources += Split('''
+ # sparc/dyn_inst.cc
+ # sparc/cpu.cc
+ # sparc/thread_context.cc
+ # sparc/cpu_builder.cc
+ # ''')
+else:
+ sys.exit('O3 CPU does not support the \'%s\' ISA' % env['TARGET_ISA'])
+
+
+# Convert file names to SCons File objects. This takes care of the
+# path relative to the top of the directory tree.
+sources = [File(s) for s in sources]
+
+Return('sources')
+
diff --git a/src/cpu/o3/alpha_cpu.cc b/src/cpu/o3/alpha/cpu.cc
index 7bc90dae6..ed10b2fd1 100644
--- a/src/cpu/o3/alpha_cpu.cc
+++ b/src/cpu/o3/alpha/cpu.cc
@@ -24,13 +24,15 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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"
+#include "cpu/o3/alpha/impl.hh"
+#include "cpu/o3/alpha/cpu_impl.hh"
+#include "cpu/o3/alpha/dyn_inst.hh"
-// Force instantiation of AlphaFullCPU for all the implemntations that are
+// 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 AlphaFullCPU<AlphaSimpleImpl>;
+template class AlphaO3CPU<AlphaSimpleImpl>;
diff --git a/src/cpu/o3/alpha/cpu.hh b/src/cpu/o3/alpha/cpu.hh
new file mode 100644
index 000000000..b961341d5
--- /dev/null
+++ b/src/cpu/o3/alpha/cpu.hh
@@ -0,0 +1,204 @@
+/*
+ * 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/isa_traits.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>
+{
+ protected:
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MiscRegFile MiscRegFile;
+
+ public:
+ typedef O3ThreadState<Impl> ImplState;
+ typedef O3ThreadState<Impl> Thread;
+ typedef typename Impl::Params Params;
+
+ /** Constructs an AlphaO3CPU with the given parameters. */
+ AlphaO3CPU(Params *params);
+
+#if FULL_SYSTEM
+ /** ITB pointer. */
+ AlphaITB *itb;
+ /** DTB pointer. */
+ AlphaDTB *dtb;
+#endif
+
+ /** Registers statistics. */
+ void regStats();
+
+#if FULL_SYSTEM
+ /** Translates instruction requestion. */
+ Fault translateInstReq(RequestPtr &req, Thread *thread)
+ {
+ return itb->translate(req, thread->getTC());
+ }
+
+ /** Translates data read request. */
+ Fault translateDataReadReq(RequestPtr &req, Thread *thread)
+ {
+ return dtb->translate(req, thread->getTC(), false);
+ }
+
+ /** Translates data write request. */
+ Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
+ {
+ return dtb->translate(req, thread->getTC(), true);
+ }
+
+#else
+ /** Translates instruction requestion in syscall emulation mode. */
+ Fault translateInstReq(RequestPtr &req, Thread *thread)
+ {
+ return thread->getProcessPtr()->pTable->translate(req);
+ }
+
+ /** Translates data read request in syscall emulation mode. */
+ Fault translateDataReadReq(RequestPtr &req, Thread *thread)
+ {
+ return thread->getProcessPtr()->pTable->translate(req);
+ }
+
+ /** Translates data write request in syscall emulation mode. */
+ Fault translateDataWriteReq(RequestPtr &req, Thread *thread)
+ {
+ return thread->getProcessPtr()->pTable->translate(req);
+ }
+
+#endif
+ /** Reads a miscellaneous register. */
+ MiscReg readMiscReg(int misc_reg, unsigned tid);
+
+ /** Reads a misc. register, including any side effects the read
+ * might have as defined by the architecture.
+ */
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault, unsigned tid);
+
+ /** Sets a miscellaneous register. */
+ Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned tid);
+
+ /** Sets a misc. register, including any side effects the write
+ * might have as defined by the architecture.
+ */
+ Fault setMiscRegWithEffect(int misc_reg, const 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);
+ /** Reads the interrupt flag. */
+ int readIntrFlag();
+ /** Sets the interrupt flags. */
+ void setIntrFlag(int val);
+ /** HW return from error interrupt. */
+ Fault hwrei(unsigned tid);
+ /** Returns if a specific PC is a PAL mode PC. */
+ bool inPalMode(uint64_t PC)
+ { return AlphaISA::PcPAL(PC); }
+
+ bool simPalCheck(int palFunc, unsigned tid);
+
+ /** Processes any interrupts. */
+ void processInterrupts();
+
+ /** 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. */
+ IntReg getSyscallArg(int i, int tid);
+
+ /** Used to shift args for indirect syscall. */
+ void setSyscallArg(int i, IntReg val, int tid);
+
+ /** Sets the return value of a syscall. */
+ void setSyscallReturn(SyscallReturn return_value, int tid);
+#endif
+
+ /** 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
index 6025b8ef2..490305cbf 100644
--- a/src/cpu/o3/alpha_cpu_builder.cc
+++ b/src/cpu/o3/alpha/cpu_builder.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,49 +24,32 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/inifile.hh"
-#include "base/loader/symtab.hh"
-#include "base/misc.hh"
+#include <string>
+
#include "cpu/base.hh"
-#include "cpu/exetrace.hh"
-#include "cpu/o3/alpha_cpu.hh"
-#include "cpu/o3/alpha_impl.hh"
-#include "mem/base_mem.hh"
-#include "mem/cache/base_cache.hh"
-#include "mem/mem_interface.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 "sim/builder.hh"
-#include "sim/debug.hh"
-#include "sim/host.hh"
-#include "sim/process.hh"
-#include "sim/sim_events.hh"
-#include "sim/sim_object.hh"
-#include "sim/stats.hh"
-#if FULL_SYSTEM
-#include "base/remote_gdb.hh"
-#include "mem/functional/memory_control.hh"
-#include "mem/functional/physical.hh"
-#include "sim/system.hh"
-#include "arch/tlb.hh"
-#include "arch/vtophys.hh"
-#else // !FULL_SYSTEM
-#include "mem/functional/functional.hh"
-#endif // FULL_SYSTEM
-
-class DerivAlphaFullCPU : public AlphaFullCPU<AlphaSimpleImpl>
+class DerivO3CPU : public AlphaO3CPU<AlphaSimpleImpl>
{
public:
- DerivAlphaFullCPU(AlphaSimpleParams p)
- : AlphaFullCPU<AlphaSimpleImpl>(p)
+ DerivO3CPU(AlphaSimpleParams *p)
+ : AlphaO3CPU<AlphaSimpleImpl>(p)
{ }
};
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU)
Param<int> clock;
Param<int> numThreads;
+Param<int> activity;
#if FULL_SYSTEM
SimObjectParam<System *> system;
@@ -76,15 +59,17 @@ SimObjectParam<AlphaDTB *> dtb;
#else
SimObjectVectorParam<Process *> workload;
#endif // FULL_SYSTEM
-SimObjectParam<FunctionalMemory *> mem;
+
+SimObjectParam<MemObject *> mem;
+
+SimObjectParam<BaseCPU *> checker;
Param<Counter> max_insts_any_thread;
Param<Counter> max_insts_all_threads;
Param<Counter> max_loads_any_thread;
Param<Counter> max_loads_all_threads;
-SimObjectParam<BaseCache *> icache;
-SimObjectParam<BaseCache *> dcache;
+Param<unsigned> cachePorts;
Param<unsigned> decodeToFetchDelay;
Param<unsigned> renameToFetchDelay;
@@ -107,30 +92,25 @@ Param<unsigned> commitToIEWDelay;
Param<unsigned> renameToIEWDelay;
Param<unsigned> issueToExecuteDelay;
Param<unsigned> issueWidth;
-Param<unsigned> executeWidth;
-Param<unsigned> executeIntWidth;
-Param<unsigned> executeFloatWidth;
-Param<unsigned> executeBranchWidth;
-Param<unsigned> executeMemoryWidth;
+SimObjectParam<FUPool *> fuPool;
Param<unsigned> iewToCommitDelay;
Param<unsigned> renameToROBDelay;
Param<unsigned> commitWidth;
Param<unsigned> squashWidth;
+Param<Tick> trapLatency;
+Param<Tick> fetchTrapLatency;
-#if 0
+Param<std::string> predType;
Param<unsigned> localPredictorSize;
-Param<unsigned> localPredictorCtrBits;
-#endif
-Param<unsigned> local_predictor_size;
-Param<unsigned> local_ctr_bits;
-Param<unsigned> local_history_table_size;
-Param<unsigned> local_history_bits;
-Param<unsigned> global_predictor_size;
-Param<unsigned> global_ctr_bits;
-Param<unsigned> global_history_bits;
-Param<unsigned> choice_predictor_size;
-Param<unsigned> choice_ctr_bits;
+Param<unsigned> localCtrBits;
+Param<unsigned> localHistoryTableSize;
+Param<unsigned> localHistoryBits;
+Param<unsigned> globalPredictorSize;
+Param<unsigned> globalCtrBits;
+Param<unsigned> globalHistoryBits;
+Param<unsigned> choicePredictorSize;
+Param<unsigned> choiceCtrBits;
Param<unsigned> BTBEntries;
Param<unsigned> BTBTagSize;
@@ -147,6 +127,16 @@ Param<unsigned> numPhysFloatRegs;
Param<unsigned> numIQEntries;
Param<unsigned> numROBEntries;
+Param<unsigned> smtNumFetchingThreads;
+Param<std::string> smtFetchPolicy;
+Param<std::string> smtLSQPolicy;
+Param<unsigned> smtLSQThreshold;
+Param<std::string> smtIQPolicy;
+Param<unsigned> smtIQThreshold;
+Param<std::string> smtROBPolicy;
+Param<unsigned> smtROBThreshold;
+Param<std::string> smtCommitPolicy;
+
Param<unsigned> instShiftAmt;
Param<bool> defer_registration;
@@ -154,12 +144,13 @@ Param<bool> defer_registration;
Param<bool> function_trace;
Param<Tick> function_trace_start;
-END_DECLARE_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+END_DECLARE_SIM_OBJECT_PARAMS(DerivO3CPU)
-BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+BEGIN_INIT_SIM_OBJECT_PARAMS(DerivO3CPU)
INIT_PARAM(clock, "clock speed"),
INIT_PARAM(numThreads, "number of HW thread contexts"),
+ INIT_PARAM_DFLT(activity, "Initial activity count", 0),
#if FULL_SYSTEM
INIT_PARAM(system, "System object"),
@@ -170,7 +161,9 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
INIT_PARAM(workload, "Processes to run"),
#endif // FULL_SYSTEM
- INIT_PARAM_DFLT(mem, "Memory", NULL),
+ INIT_PARAM(mem, "Memory"),
+
+ INIT_PARAM_DFLT(checker, "Checker CPU", NULL),
INIT_PARAM_DFLT(max_insts_any_thread,
"Terminate when any thread reaches this inst count",
@@ -187,8 +180,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
"count",
0),
- INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL),
- INIT_PARAM_DFLT(dcache, "L1 data cache", NULL),
+ INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200),
INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"),
INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"),
@@ -196,7 +188,6 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
"delay"),
INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"),
INIT_PARAM(fetchWidth, "Fetch width"),
-
INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"),
INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode"
"delay"),
@@ -217,32 +208,26 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal"
"to the IEW stage)"),
INIT_PARAM(issueWidth, "Issue width"),
- INIT_PARAM(executeWidth, "Execute width"),
- INIT_PARAM(executeIntWidth, "Integer execute width"),
- INIT_PARAM(executeFloatWidth, "Floating point execute width"),
- INIT_PARAM(executeBranchWidth, "Branch execute width"),
- INIT_PARAM(executeMemoryWidth, "Memory execute width"),
+ INIT_PARAM_DFLT(fuPool, "Functional unit pool", NULL),
INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit "
"delay"),
INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"),
INIT_PARAM(commitWidth, "Commit width"),
INIT_PARAM(squashWidth, "Squash width"),
-
-#if 0
- INIT_PARAM(localPredictorSize, "Size of the local predictor in entries. "
- "Must be a power of 2."),
- INIT_PARAM(localPredictorCtrBits, "Number of bits per counter for bpred"),
-#endif
- INIT_PARAM(local_predictor_size, "Size of local predictor"),
- INIT_PARAM(local_ctr_bits, "Bits per counter"),
- INIT_PARAM(local_history_table_size, "Size of local history table"),
- INIT_PARAM(local_history_bits, "Bits for the local history"),
- INIT_PARAM(global_predictor_size, "Size of global predictor"),
- INIT_PARAM(global_ctr_bits, "Bits per counter"),
- INIT_PARAM(global_history_bits, "Bits of history"),
- INIT_PARAM(choice_predictor_size, "Size of choice predictor"),
- INIT_PARAM(choice_ctr_bits, "Bits of choice counters"),
+ INIT_PARAM_DFLT(trapLatency, "Number of cycles before the trap is handled", 6),
+ INIT_PARAM_DFLT(fetchTrapLatency, "Number of cycles before the fetch trap is handled", 12),
+
+ INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"),
+ INIT_PARAM(localPredictorSize, "Size of local predictor"),
+ INIT_PARAM(localCtrBits, "Bits per counter"),
+ INIT_PARAM(localHistoryTableSize, "Size of local history table"),
+ INIT_PARAM(localHistoryBits, "Bits for the local history"),
+ INIT_PARAM(globalPredictorSize, "Size of global predictor"),
+ INIT_PARAM(globalCtrBits, "Bits per counter"),
+ INIT_PARAM(globalHistoryBits, "Bits of history"),
+ INIT_PARAM(choicePredictorSize, "Size of choice predictor"),
+ INIT_PARAM(choiceCtrBits, "Bits of choice counters"),
INIT_PARAM(BTBEntries, "Number of BTB entries"),
INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"),
@@ -260,17 +245,27 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
INIT_PARAM(numIQEntries, "Number of instruction queue entries"),
INIT_PARAM(numROBEntries, "Number of reorder buffer entries"),
+ INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1),
+ INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"),
+ INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100),
+ INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100),
+ INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100),
+ INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"),
+
INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"),
INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
INIT_PARAM(function_trace, "Enable function trace"),
INIT_PARAM(function_trace_start, "Cycle to start function trace")
-END_INIT_SIM_OBJECT_PARAMS(DerivAlphaFullCPU)
+END_INIT_SIM_OBJECT_PARAMS(DerivO3CPU)
-CREATE_SIM_OBJECT(DerivAlphaFullCPU)
+CREATE_SIM_OBJECT(DerivO3CPU)
{
- DerivAlphaFullCPU *cpu;
+ DerivO3CPU *cpu;
#if FULL_SYSTEM
// Full-system only supports a single thread for the moment.
@@ -279,114 +274,131 @@ CREATE_SIM_OBJECT(DerivAlphaFullCPU)
// 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.isValid() ? numThreads : workload.size();
+ (numThreads.isValid() && numThreads >= workload.size()) ?
+ numThreads : workload.size();
if (workload.size() == 0) {
fatal("Must specify at least one workload!");
}
-
#endif
- AlphaSimpleParams params;
+ AlphaSimpleParams *params = new AlphaSimpleParams;
- params.clock = clock;
+ params->clock = clock;
- params.name = getInstanceName();
- params.numberOfThreads = actual_num_threads;
+ params->name = getInstanceName();
+ params->numberOfThreads = actual_num_threads;
+ params->activity = activity;
#if FULL_SYSTEM
- params.system = system;
- params.cpu_id = cpu_id;
- params.itb = itb;
- params.dtb = dtb;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->itb = itb;
+ params->dtb = dtb;
#else
- params.workload = workload;
+ params->workload = workload;
#endif // FULL_SYSTEM
- params.mem = mem;
+ params->mem = mem;
+
+ params->checker = checker;
- 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->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.icacheInterface = icache ? icache->getInterface() : NULL;
- params.dcacheInterface = dcache ? dcache->getInterface() : NULL;
-
- 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.issueWidth = issueWidth;
- params.executeWidth = executeWidth;
- params.executeIntWidth = executeIntWidth;
- params.executeFloatWidth = executeFloatWidth;
- params.executeBranchWidth = executeBranchWidth;
- params.executeMemoryWidth = executeMemoryWidth;
-
- params.iewToCommitDelay = iewToCommitDelay;
- params.renameToROBDelay = renameToROBDelay;
- params.commitWidth = commitWidth;
- params.squashWidth = squashWidth;
-#if 0
- params.localPredictorSize = localPredictorSize;
- params.localPredictorCtrBits = localPredictorCtrBits;
-#endif
- params.local_predictor_size = local_predictor_size;
- params.local_ctr_bits = local_ctr_bits;
- params.local_history_table_size = local_history_table_size;
- params.local_history_bits = local_history_bits;
- params.global_predictor_size = global_predictor_size;
- params.global_ctr_bits = global_ctr_bits;
- params.global_history_bits = global_history_bits;
- params.choice_predictor_size = choice_predictor_size;
- params.choice_ctr_bits = choice_ctr_bits;
-
- 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.instShiftAmt = 2;
-
- params.defReg = defer_registration;
-
- params.functionTrace = function_trace;
- params.functionTraceStart = function_trace_start;
-
- cpu = new DerivAlphaFullCPU(params);
+ 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->issueWidth = issueWidth;
+ params->fuPool = fuPool;
+
+ params->iewToCommitDelay = iewToCommitDelay;
+ params->renameToROBDelay = renameToROBDelay;
+ params->commitWidth = commitWidth;
+ params->squashWidth = squashWidth;
+ params->trapLatency = trapLatency;
+ params->fetchTrapLatency = fetchTrapLatency;
+
+ 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;
}
-REGISTER_SIM_OBJECT("DerivAlphaFullCPU", DerivAlphaFullCPU)
+REGISTER_SIM_OBJECT("DerivO3CPU", DerivO3CPU)
diff --git a/src/cpu/o3/alpha/cpu_impl.hh b/src/cpu/o3/alpha/cpu_impl.hh
new file mode 100644
index 000000000..0473e60c2
--- /dev/null
+++ b/src/cpu/o3/alpha/cpu_impl.hh
@@ -0,0 +1,422 @@
+/*
+ * 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 "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 "cpu/quiesce_event.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+#endif
+
+using namespace TheISA;
+
+template <class Impl>
+AlphaO3CPU<Impl>::AlphaO3CPU(Params *params)
+#if FULL_SYSTEM
+ : FullO3CPU<Impl>(params), itb(params->itb), dtb(params->dtb)
+#else
+ : FullO3CPU<Impl>(params)
+#endif
+{
+ 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, params->mem);
+
+ this->thread[i]->setStatus(ThreadContext::Suspended);
+
+#if !FULL_SYSTEM
+ /* Use this port to for syscall emulation writes to memory. */
+ Port *mem_port;
+ TranslatingPort *trans_port;
+ trans_port = new TranslatingPort(csprintf("%s-%d-funcport",
+ name(), i),
+ params->workload[i]->pTable,
+ false);
+ mem_port = params->mem->getPort("functional");
+ mem_port->setPeer(trans_port);
+ trans_port->setPeer(mem_port);
+ this->thread[i]->setMemPort(trans_port);
+#endif
+ //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, params->mem);
+ //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);
+
+ Port *mem_port;
+ FunctionalPort *phys_port;
+ VirtualPort *virt_port;
+ phys_port = new FunctionalPort(csprintf("%s-%d-funcport",
+ name(), i));
+ mem_port = this->system->physmem->getPort("functional");
+ mem_port->setPeer(phys_port);
+ phys_port->setPeer(mem_port);
+
+ virt_port = new VirtualPort(csprintf("%s-%d-vport",
+ name(), i));
+ mem_port = this->system->physmem->getPort("functional");
+ mem_port->setPeer(virt_port);
+ virt_port->setPeer(mem_port);
+
+ this->thread[i]->setPhysPort(phys_port);
+ this->thread[i]->setVirtPort(virt_port);
+#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);
+ }
+
+ // Sets CPU pointers. These must be set at this level because the CPU
+ // pointers are defined to be the highest level of CPU class.
+ this->fetch.setCPU(this);
+ this->decode.setCPU(this);
+ this->rename.setCPU(this);
+ this->iew.setCPU(this);
+ this->commit.setCPU(this);
+
+ this->rob.setCPU(this);
+ this->regFile.setCPU(this);
+
+ lockAddr = 0;
+ lockFlag = false;
+}
+
+template <class Impl>
+void
+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>
+MiscReg
+AlphaO3CPU<Impl>::readMiscReg(int misc_reg, unsigned tid)
+{
+ return this->regFile.readMiscReg(misc_reg, tid);
+}
+
+template <class Impl>
+MiscReg
+AlphaO3CPU<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault,
+ unsigned tid)
+{
+ return this->regFile.readMiscRegWithEffect(misc_reg, fault, tid);
+}
+
+template <class Impl>
+Fault
+AlphaO3CPU<Impl>::setMiscReg(int misc_reg, const MiscReg &val, unsigned tid)
+{
+ return this->regFile.setMiscReg(misc_reg, val, tid);
+}
+
+template <class Impl>
+Fault
+AlphaO3CPU<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val,
+ unsigned tid)
+{
+ return this->regFile.setMiscRegWithEffect(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>
+int
+AlphaO3CPU<Impl>::readIntrFlag()
+{
+ return this->regFile.readIntrFlag();
+}
+
+template <class Impl>
+void
+AlphaO3CPU<Impl>::setIntrFlag(int val)
+{
+ this->regFile.setIntrFlag(val);
+}
+
+template <class Impl>
+Fault
+AlphaO3CPU<Impl>::hwrei(unsigned tid)
+{
+ // Need to clear the lock flag upon returning from an interrupt.
+ this->lockFlag = false;
+
+ this->thread[tid]->kernelStats->hwrei();
+
+ this->checkInterrupts = true;
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+bool
+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>
+void
+AlphaO3CPU<Impl>::processInterrupts()
+{
+ // Check for interrupts here. For now can copy the code that
+ // exists within isa_fullsys_traits.hh. Also assume that thread 0
+ // is the one that handles the interrupts.
+ // @todo: Possibly consolidate the interrupt checking code.
+ // @todo: Allow other threads to handle interrupts.
+
+ // Check if there are any outstanding interrupts
+ //Handle the interrupts
+ int ipl = 0;
+ int summary = 0;
+
+ this->checkInterrupts = false;
+
+ if (this->readMiscReg(IPR_ASTRR, 0))
+ panic("asynchronous traps not implemented\n");
+
+ if (this->readMiscReg(IPR_SIRR, 0)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (this->readMiscReg(IPR_SIRR, 0) & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = this->intr_status();
+
+ if (interrupts) {
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ if (ipl && ipl > this->readMiscReg(IPR_IPLR, 0)) {
+ this->setMiscReg(IPR_ISR, summary, 0);
+ this->setMiscReg(IPR_INTID, ipl, 0);
+ // Checker needs to know these two registers were updated.
+#if USE_CHECKER
+ if (this->checker) {
+ this->checker->threadBase()->setMiscReg(IPR_ISR, summary);
+ this->checker->threadBase()->setMiscReg(IPR_INTID, ipl);
+ }
+#endif
+ this->trap(Fault(new InterruptFault), 0);
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ this->readMiscReg(IPR_IPLR, 0), ipl, summary);
+ }
+}
+
+#endif // FULL_SYSTEM
+
+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)
+{
+ return this->readArchIntReg(AlphaISA::ArgumentReg0 + i, tid);
+}
+
+template <class Impl>
+void
+AlphaO3CPU<Impl>::setSyscallArg(int i, IntReg val, int tid)
+{
+ this->setArchIntReg(AlphaISA::ArgumentReg0 + i, val, tid);
+}
+
+template <class Impl>
+void
+AlphaO3CPU<Impl>::setSyscallReturn(SyscallReturn return_value, int tid)
+{
+ // check for error condition. Alpha syscall convention is to
+ // indicate success/failure in reg a3 (r19) and put the
+ // return value itself in the standard return value reg (v0).
+ if (return_value.successful()) {
+ // no error
+ this->setArchIntReg(SyscallSuccessReg, 0, tid);
+ this->setArchIntReg(ReturnValueReg, return_value.value(), tid);
+ } else {
+ // got an error, return details
+ this->setArchIntReg(SyscallSuccessReg, (IntReg) -1, tid);
+ this->setArchIntReg(ReturnValueReg, -return_value.value(), tid);
+ }
+}
+#endif
diff --git a/src/cpu/o3/alpha_dyn_inst.cc b/src/cpu/o3/alpha/dyn_inst.cc
index 72ac77d95..97d2f3d08 100644
--- a/src/cpu/o3/alpha_dyn_inst.cc
+++ b/src/cpu/o3/alpha/dyn_inst.cc
@@ -24,10 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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"
+#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.
diff --git a/src/cpu/o3/alpha_dyn_inst.hh b/src/cpu/o3/alpha/dyn_inst.hh
index 5b8a05e5c..9dee610b6 100644
--- a/src/cpu/o3/alpha_dyn_inst.hh
+++ b/src/cpu/o3/alpha/dyn_inst.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,36 +24,45 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_ALPHA_DYN_INST_HH__
-#define __CPU_O3_CPU_ALPHA_DYN_INST_HH__
+#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/o3/alpha_cpu.hh"
-#include "cpu/o3/alpha_impl.hh"
#include "cpu/inst_seq.hh"
+#include "cpu/o3/alpha/cpu.hh"
+#include "cpu/o3/alpha/impl.hh"
+
+class Packet;
/**
- * Mostly implementation specific AlphaDynInst. It is templated in case there
- * are other implementations that are similar enough to be able to use this
- * class without changes. This is mainly useful if there are multiple similar
- * CPU implementations of the same ISA.
+ * Mostly implementation & ISA specific AlphaDynInst. As with most
+ * other classes in the new CPU model, it is templated on the Impl to
+ * allow for passing in of all types, such as the CPU type and the ISA
+ * type. The AlphaDynInst serves as the primary interface to the CPU
+ * for instructions that are executing.
*/
-
template <class Impl>
class AlphaDynInst : public BaseDynInst<Impl>
{
public:
/** Typedef for the CPU. */
- typedef typename Impl::FullCPU FullCPU;
+ 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;
@@ -64,60 +73,74 @@ class AlphaDynInst : public BaseDynInst<Impl>
public:
/** BaseDynInst constructor given a binary instruction. */
- AlphaDynInst(MachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num,
- FullCPU *cpu);
+ AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC, InstSeqNum seq_num,
+ O3CPU *cpu);
/** BaseDynInst constructor given a static inst pointer. */
AlphaDynInst(StaticInstPtr &_staticInst);
/** Executes the instruction.*/
- Fault execute()
- {
- return this->fault = this->staticInst->execute(this, this->traceData);
- }
+ Fault execute();
+
+ /** Initiates the access. Only valid for memory operations. */
+ Fault initiateAcc();
+
+ /** Completes the access. Only valid for memory operations. */
+ Fault completeAcc(Packet *pkt);
+
+ private:
+ /** Initializes variables. */
+ void initVars();
public:
+ /** Reads a miscellaneous register. */
MiscReg readMiscReg(int misc_reg)
{
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return 0;
+ return this->cpu->readMiscReg(misc_reg, this->threadNumber);
}
+ /** Reads a misc. register, including any side-effects the read
+ * might have as defined by the architecture.
+ */
MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
{
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return 0;
+ return this->cpu->readMiscRegWithEffect(misc_reg, fault,
+ this->threadNumber);
}
+ /** Sets a misc. register. */
Fault setMiscReg(int misc_reg, const MiscReg &val)
{
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return NoFault;
+ this->instResult.integer = val;
+ return this->cpu->setMiscReg(misc_reg, val, this->threadNumber);
}
+ /** Sets a misc. register, including any side-effects the write
+ * might have as defined by the architecture.
+ */
Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
{
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return NoFault;
+ return this->cpu->setMiscRegWithEffect(misc_reg, val,
+ this->threadNumber);
}
#if FULL_SYSTEM
+ /** Calls hardware return from error interrupt. */
Fault hwrei();
+ /** Reads interrupt flag. */
int readIntrFlag();
+ /** Sets interrupt flag. */
void setIntrFlag(int val);
+ /** Checks if system is in PAL mode. */
bool inPalMode();
+ /** Traps to handle specified fault. */
void trap(Fault fault);
bool simPalCheck(int palFunc);
#else
- void syscall();
+ /** Calls a syscall. */
+ void syscall(int64_t callnum);
#endif
-
-
private:
/** Physical register index of the destination registers of this
* instruction.
@@ -178,32 +201,32 @@ class AlphaDynInst : public BaseDynInst<Impl>
void setIntReg(const StaticInst *si, int idx, uint64_t val)
{
this->cpu->setIntReg(_destRegIdx[idx], val);
- this->instResult.integer = val;
+ BaseDynInst<Impl>::setIntReg(si, idx, val);
}
void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
{
this->cpu->setFloatReg(_destRegIdx[idx], val, width);
- this->instResult.fp = val;
+ BaseDynInst<Impl>::setFloatReg(si, idx, val, width);
}
void setFloatReg(const StaticInst *si, int idx, FloatReg val)
{
this->cpu->setFloatReg(_destRegIdx[idx], val);
- this->instResult.dbl = val;
+ BaseDynInst<Impl>::setFloatReg(si, idx, val);
}
void setFloatRegBits(const StaticInst *si, int idx,
FloatRegBits val, int width)
{
this->cpu->setFloatRegBits(_destRegIdx[idx], val, width);
- this->instResult.integer = val;
+ BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
}
void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
{
this->cpu->setFloatRegBits(_destRegIdx[idx], val);
- this->instResult.integer = val;
+ BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
}
/** Returns the physical register index of the i'th destination
@@ -249,16 +272,24 @@ class AlphaDynInst : public BaseDynInst<Impl>
}
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_CPU_ALPHA_DYN_INST_HH__
+#endif // __CPU_O3_ALPHA_DYN_INST_HH__
diff --git a/src/cpu/o3/alpha_dyn_inst_impl.hh b/src/cpu/o3/alpha/dyn_inst_impl.hh
index 96b7d3430..2d1b4b309 100644
--- a/src/cpu/o3/alpha_dyn_inst_impl.hh
+++ b/src/cpu/o3/alpha/dyn_inst_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,47 +24,87 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
+#include "cpu/o3/alpha/dyn_inst.hh"
template <class Impl>
-AlphaDynInst<Impl>::AlphaDynInst(MachInst inst, Addr PC, Addr Pred_PC,
- InstSeqNum seq_num, FullCPU *cpu)
+AlphaDynInst<Impl>::AlphaDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC,
+ InstSeqNum seq_num, O3CPU *cpu)
: BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu)
{
+ initVars();
+}
+
+template <class Impl>
+AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
+ : BaseDynInst<Impl>(_staticInst)
+{
+ initVars();
+}
+
+template <class Impl>
+void
+AlphaDynInst<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++)
- {
+ for (int i = 0; i < this->staticInst->numDestRegs(); i++) {
_destRegIdx[i] = this->staticInst->destRegIdx(i);
}
- for (int i = 0; i < this->staticInst->numSrcRegs(); i++)
- {
+ for (int i = 0; i < this->staticInst->numSrcRegs(); i++) {
_srcRegIdx[i] = this->staticInst->srcRegIdx(i);
this->_readySrcRegIdx[i] = 0;
}
+}
+
+template <class Impl>
+Fault
+AlphaDynInst<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>
-AlphaDynInst<Impl>::AlphaDynInst(StaticInstPtr &_staticInst)
- : BaseDynInst<Impl>(_staticInst)
+Fault
+AlphaDynInst<Impl>::initiateAcc()
{
- // 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 < _staticInst->numDestRegs(); i++)
- {
- _destRegIdx[i] = _staticInst->destRegIdx(i);
- }
+ // @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;
- for (int i = 0; i < _staticInst->numSrcRegs(); i++)
- {
- _srcRegIdx[i] = _staticInst->srcRegIdx(i);
- }
+ this->fault = this->staticInst->initiateAcc(this, this->traceData);
+
+ this->thread->inSyscall = in_syscall;
+
+ return this->fault;
+}
+
+template <class Impl>
+Fault
+AlphaDynInst<Impl>::completeAcc(Packet *pkt)
+{
+ this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
+
+ return this->fault;
}
#if FULL_SYSTEM
@@ -72,14 +112,26 @@ template <class Impl>
Fault
AlphaDynInst<Impl>::hwrei()
{
- return this->cpu->hwrei();
+ // Can only do a hwrei when in pal mode.
+ if (!this->cpu->inPalMode(this->readPC()))
+ return new AlphaISA::UnimplementedOpcodeFault;
+
+ // Set the next PC based on the value of the EXC_ADDR IPR.
+ this->setNextPC(this->cpu->readMiscReg(AlphaISA::IPR_EXC_ADDR,
+ this->threadNumber));
+
+ // Tell CPU to clear any state it needs to if a hwrei is taken.
+ this->cpu->hwrei(this->threadNumber);
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
}
template <class Impl>
int
AlphaDynInst<Impl>::readIntrFlag()
{
-return this->cpu->readIntrFlag();
+ return this->cpu->readIntrFlag();
}
template <class Impl>
@@ -93,28 +145,28 @@ template <class Impl>
bool
AlphaDynInst<Impl>::inPalMode()
{
- return this->cpu->inPalMode();
+ return this->cpu->inPalMode(this->PC);
}
template <class Impl>
void
AlphaDynInst<Impl>::trap(Fault fault)
{
- this->cpu->trap(fault);
+ this->cpu->trap(fault, this->threadNumber);
}
template <class Impl>
bool
AlphaDynInst<Impl>::simPalCheck(int palFunc)
{
- return this->cpu->simPalCheck(palFunc);
+ return this->cpu->simPalCheck(palFunc, this->threadNumber);
}
#else
template <class Impl>
void
-AlphaDynInst<Impl>::syscall()
+AlphaDynInst<Impl>::syscall(int64_t callnum)
{
- this->cpu->syscall(this->threadNumber);
+ this->cpu->syscall(callnum, this->threadNumber);
}
#endif
diff --git a/src/cpu/o3/alpha_impl.hh b/src/cpu/o3/alpha/impl.hh
index 5e39fcb37..8cd8692c6 100644
--- a/src/cpu/o3/alpha_impl.hh
+++ b/src/cpu/o3/alpha/impl.hh
@@ -24,14 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_ALPHA_IMPL_HH__
-#define __CPU_O3_CPU_ALPHA_IMPL_HH__
+#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/alpha/params.hh"
#include "cpu/o3/cpu_policy.hh"
// Forward declarations.
@@ -39,12 +41,12 @@ template <class Impl>
class AlphaDynInst;
template <class Impl>
-class AlphaFullCPU;
+class AlphaO3CPU;
-/** Implementation specific struct that defines several key things to the
+/** 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 FullCPU, and all of the structs from the time buffers to do
+ * 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.
@@ -54,10 +56,10 @@ struct AlphaSimpleImpl
/** The type of MachInst. */
typedef TheISA::MachInst MachInst;
- /** The CPU policy to be used (ie fetch, decode, etc.). */
+ /** The CPU policy to be used, which defines all of the CPU stages. */
typedef SimpleCPUPolicy<AlphaSimpleImpl> CPUPol;
- /** The DynInst to be used. */
+ /** The DynInst type to be used. */
typedef AlphaDynInst<AlphaSimpleImpl> DynInst;
/** The refcounted DynInst pointer to be used. In most cases this is
@@ -65,15 +67,28 @@ struct AlphaSimpleImpl
*/
typedef RefCountingPtr<DynInst> DynInstPtr;
- /** The FullCPU to be used. */
- typedef AlphaFullCPU<AlphaSimpleImpl> FullCPU;
+ /** 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
+ MaxWidth = 8,
+ MaxThreads = 4
};
};
-#endif // __CPU_O3_CPU_ALPHA_IMPL_HH__
+/** The O3Impl to be used. */
+typedef AlphaSimpleImpl O3CPUImpl;
+
+/** The O3Impl to be used. */
+typedef DynInst O3DynInst;
+
+#endif // __CPU_O3_ALPHA_IMPL_HH__
diff --git a/src/cpu/o3/alpha/params.hh b/src/cpu/o3/alpha/params.hh
new file mode 100644
index 000000000..b1f2a487d
--- /dev/null
+++ b/src/cpu/o3/alpha/params.hh
@@ -0,0 +1,69 @@
+/*
+ * 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_PARAMS_HH__
+#define __CPU_O3_ALPHA_PARAMS_HH__
+
+#include "cpu/o3/cpu.hh"
+#include "cpu/o3/params.hh"
+
+//Forward declarations
+class AlphaDTB;
+class AlphaITB;
+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 AlphaSimpleParams : public O3Params
+{
+ public:
+
+#if FULL_SYSTEM
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+#else
+ std::vector<Process *> workload;
+ Process *process;
+#endif // FULL_SYSTEM
+
+ MemObject *mem;
+
+ BaseCPU *checker;
+
+ unsigned decodeToFetchDelay;
+};
+
+#endif // __CPU_O3_ALPHA_PARAMS_HH__
diff --git a/src/cpu/o3/alpha/thread_context.cc b/src/cpu/o3/alpha/thread_context.cc
new file mode 100755
index 000000000..4a02715bc
--- /dev/null
+++ b/src/cpu/o3/alpha/thread_context.cc
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+
+#include "cpu/o3/thread_context.hh"
+#include "cpu/o3/thread_context_impl.hh"
+
+template class O3ThreadContext<AlphaSimpleImpl>;
+
diff --git a/src/cpu/o3/alpha/thread_context.hh b/src/cpu/o3/alpha/thread_context.hh
new file mode 100644
index 000000000..78b0ee788
--- /dev/null
+++ b/src/cpu/o3/alpha/thread_context.hh
@@ -0,0 +1,87 @@
+/*
+ * 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
+ */
+
+#include "cpu/o3/thread_context.hh"
+
+template <class Impl>
+class AlphaTC : public O3ThreadContext<Impl>
+{
+ public:
+#if FULL_SYSTEM
+ /** Returns a pointer to the ITB. */
+ virtual AlphaITB *getITBPtr() { return this->cpu->itb; }
+
+ /** Returns a pointer to the DTB. */
+ virtual AlphaDTB *getDTBPtr() { return this->cpu->dtb; }
+
+ /** Returns pointer to the quiesce event. */
+ virtual EndQuiesceEvent *getQuiesceEvent()
+ {
+ return this->thread->quiesceEvent;
+ }
+
+ /** Returns if the thread is currently in PAL mode, based on
+ * the PC's value. */
+ virtual bool inPalMode()
+ { return TheISA::PcPAL(this->cpu->readPC(this->thread->readTid())); }
+#endif
+
+ virtual uint64_t readNextNPC()
+ {
+ panic("Alpha has no NextNPC!");
+ return 0;
+ }
+
+ virtual void setNextNPC(uint64_t val)
+ {
+ panic("Alpha has no NextNPC!");
+ }
+
+ virtual void changeRegFileContext(TheISA::RegFile::ContextParam param,
+ TheISA::RegFile::ContextVal val)
+ { panic("Not supported on Alpha!"); }
+
+
+ // 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->cpu->deallocateContext(this->thread->readTid());
+
+ // If there are still threads executing in the system
+ if (this->cpu->numActiveThreads())
+ return 0;
+ else
+ return 1;
+ }
+};
diff --git a/src/cpu/o3/alpha_cpu.hh b/src/cpu/o3/alpha_cpu.hh
deleted file mode 100644
index 8e1e0f42a..000000000
--- a/src/cpu/o3/alpha_cpu.hh
+++ /dev/null
@@ -1,291 +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.
- */
-
-// Todo: Find all the stuff in ExecContext and ev5 that needs to be
-// specifically designed for this CPU.
-
-#ifndef __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
-#define __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
-
-#include "cpu/o3/cpu.hh"
-#include "arch/isa_traits.hh"
-#include "sim/byteswap.hh"
-
-template <class Impl>
-class AlphaFullCPU : public FullO3CPU<Impl>
-{
- protected:
- typedef TheISA::IntReg IntReg;
- typedef TheISA::MiscReg MiscReg;
- typedef TheISA::RegFile RegFile;
- typedef TheISA::MiscRegFile MiscRegFile;
-
- public:
- typedef typename Impl::Params Params;
-
- public:
- AlphaFullCPU(Params &params);
-
-#if FULL_SYSTEM
- AlphaITB *itb;
- AlphaDTB *dtb;
-#endif
-
- public:
- void regStats();
-
-#if FULL_SYSTEM
- //Note that the interrupt stuff from the base CPU might be somewhat
- //ISA specific (ie NumInterruptLevels). These functions might not
- //be needed in FullCPU though.
-// void post_interrupt(int int_num, int index);
-// void clear_interrupt(int int_num, int index);
-// void clear_interrupts();
-
- Fault translateInstReq(MemReqPtr &req)
- {
- return itb->translate(req);
- }
-
- Fault translateDataReadReq(MemReqPtr &req)
- {
- return dtb->translate(req, false);
- }
-
- Fault translateDataWriteReq(MemReqPtr &req)
- {
- return dtb->translate(req, true);
- }
-
-#else
- Fault dummyTranslation(MemReqPtr &req)
- {
-#if 0
- assert((req->vaddr >> 48 & 0xffff) == 0);
-#endif
-
- // put the asid in the upper 16 bits of the paddr
- req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
- req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
- return NoFault;
- }
-
- Fault translateInstReq(MemReqPtr &req)
- {
- return dummyTranslation(req);
- }
-
- Fault translateDataReadReq(MemReqPtr &req)
- {
- return dummyTranslation(req);
- }
-
- Fault translateDataWriteReq(MemReqPtr &req)
- {
- return dummyTranslation(req);
- }
-
-#endif
-
- // Later on may want to remove this misc stuff from the regfile and
- // have it handled at this level. Might prove to be an issue when
- // trying to rename source/destination registers...
- MiscReg readMiscReg(int misc_reg)
- {
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return 0;
- }
-
- Fault setMiscReg(int misc_reg, const MiscReg &val)
- {
- // Dummy function for now.
- // @todo: Fix this once reg file gets fixed.
- return NoFault;
- }
-
- // Most of the full system code and syscall emulation is not yet
- // implemented. These functions do show what the final interface will
- // look like.
-#if FULL_SYSTEM
- int readIntrFlag();
- void setIntrFlag(int val);
- Fault hwrei();
- bool inPalMode() { return AlphaISA::PcPAL(this->regFile.readPC()); }
- bool inPalMode(uint64_t PC)
- { return AlphaISA::PcPAL(PC); }
-
- void trap(Fault fault);
- bool simPalCheck(int palFunc);
-
- void processInterrupts();
-#endif
-
-
-#if !FULL_SYSTEM
- // Need to change these into regfile calls that directly set a certain
- // register. Actually, these functions should handle most of this
- // functionality by themselves; should look up the rename and then
- // set the register.
- IntReg getSyscallArg(int i)
- {
- return this->cpuXC->readIntReg(AlphaISA::ArgumentReg0 + i);
- }
-
- // used to shift args for indirect syscall
- void setSyscallArg(int i, IntReg val)
- {
- this->cpuXC->setIntReg(AlphaISA::ArgumentReg0 + i, val);
- }
-
- void setSyscallReturn(int64_t 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).
- const int RegA3 = 19; // only place this is used
- if (return_value >= 0) {
- // no error
- this->cpuXC->setIntReg(RegA3, 0);
- this->cpuXC->setIntReg(AlphaISA::ReturnValueReg, return_value);
- } else {
- // got an error, return details
- this->cpuXC->setIntReg(RegA3, (IntReg) -1);
- this->cpuXC->setIntReg(AlphaISA::ReturnValueReg, -return_value);
- }
- }
-
- void syscall(short thread_num);
- void squashStages();
-
-#endif
-
- void copyToXC();
- void copyFromXC();
-
- public:
-#if FULL_SYSTEM
- bool palShadowEnabled;
-
- // Not sure this is used anywhere.
- void intr_post(RegFile *regs, Fault fault, Addr pc);
- // Actually used within exec files. Implement properly.
- void swapPALShadow(bool use_shadow);
- // Called by CPU constructor. Can implement as I please.
- void initCPU(RegFile *regs);
- // Called by initCPU. Implement as I please.
- void initIPRs(RegFile *regs);
-
- void halt() { panic("Halt not implemented!\n"); }
-#endif
-
-
- template <class T>
- Fault read(MemReqPtr &req, T &data)
- {
-#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
- if (req->flags & LOCKED) {
- req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
- req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
- }
-#endif
-
- Fault error;
- error = this->mem->read(req, data);
- data = gtoh(data);
- return error;
- }
-
- template <class T>
- Fault read(MemReqPtr &req, T &data, int load_idx)
- {
- return this->iew.ldstQueue.read(req, data, load_idx);
- }
-
- template <class T>
- Fault write(MemReqPtr &req, T &data)
- {
-#if FULL_SYSTEM && THE_ISA == ALPHA_ISA
- ExecContext *xc;
-
- // If this is a store conditional, act appropriately
- if (req->flags & LOCKED) {
- xc = req->xc;
-
- if (req->flags & UNCACHEABLE) {
- // Don't update result register (see stq_c in isa_desc)
- req->result = 2;
- xc->setStCondFailures(0);//Needed? [RGD]
- } else {
- bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
- Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
- req->result = lock_flag;
- if (!lock_flag ||
- ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
- xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
- xc->setStCondFailures(xc->readStCondFailures() + 1);
- if (((xc->readStCondFailures()) % 100000) == 0) {
- std::cerr << "Warning: "
- << xc->readStCondFailures()
- << " consecutive store conditional failures "
- << "on cpu " << req->xc->readCpuId()
- << std::endl;
- }
- return NoFault;
- }
- else xc->setStCondFailures(0);
- }
- }
-
- // Need to clear any locked flags on other proccessors for
- // this address. Only do this for succsful Store Conditionals
- // and all other stores (WH64?). Unsuccessful Store
- // Conditionals would have returned above, and wouldn't fall
- // through.
- for (int i = 0; i < this->system->execContexts.size(); i++){
- xc = this->system->execContexts[i];
- if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
- (req->paddr & ~0xf)) {
- xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
- }
- }
-
-#endif
-
- return this->mem->write(req, (T)htog(data));
- }
-
- template <class T>
- Fault write(MemReqPtr &req, T &data, int store_idx)
- {
- return this->iew.ldstQueue.write(req, data, store_idx);
- }
-
-};
-
-#endif // __CPU_O3_CPU_ALPHA_FULL_CPU_HH__
diff --git a/src/cpu/o3/alpha_cpu_impl.hh b/src/cpu/o3/alpha_cpu_impl.hh
deleted file mode 100644
index 7c4c2b969..000000000
--- a/src/cpu/o3/alpha_cpu_impl.hh
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "arch/alpha/faults.hh"
-#include "base/cprintf.hh"
-#include "base/statistics.hh"
-#include "base/timebuf.hh"
-#include "mem/cache/cache.hh" // for dynamic cast
-#include "mem/mem_interface.hh"
-#include "sim/builder.hh"
-#include "sim/sim_events.hh"
-#include "sim/stats.hh"
-
-#include "cpu/o3/alpha_cpu.hh"
-#include "cpu/o3/alpha_params.hh"
-#include "cpu/o3/comm.hh"
-
-#if FULL_SYSTEM
-#include "arch/alpha/osfpal.hh"
-#include "arch/alpha/isa_traits.hh"
-#endif
-
-template <class Impl>
-AlphaFullCPU<Impl>::AlphaFullCPU(Params &params)
- : FullO3CPU<Impl>(params)
-{
- DPRINTF(FullCPU, "AlphaFullCPU: Creating AlphaFullCPU object.\n");
-
- this->fetch.setCPU(this);
- this->decode.setCPU(this);
- this->rename.setCPU(this);
- this->iew.setCPU(this);
- this->commit.setCPU(this);
-
- this->rob.setCPU(this);
-}
-
-template <class Impl>
-void
-AlphaFullCPU<Impl>::regStats()
-{
- // Register stats for everything that has stats.
- this->fullCPURegStats();
- this->fetch.regStats();
- this->decode.regStats();
- this->rename.regStats();
- this->iew.regStats();
- this->commit.regStats();
-}
-
-#if !FULL_SYSTEM
-
-// Will probably need to know which thread is calling syscall
-// Will need to pass that information in to the DynInst when it is constructed,
-// so that this call can be made with the proper thread number.
-template <class Impl>
-void
-AlphaFullCPU<Impl>::syscall(short thread_num)
-{
- DPRINTF(FullCPU, "AlphaFullCPU: Syscall() called.\n\n");
-
- // Commit stage needs to run as well.
- this->commit.tick();
-
- squashStages();
-
- // Temporarily increase this by one to account for the syscall
- // instruction.
- ++(this->funcExeInst);
-
- // Copy over all important state to xc once all the unrolling is done.
- copyToXC();
-
- // This is hardcoded to thread 0 while the CPU is only single threaded.
- this->thread[0]->syscall();
-
- // Copy over all important state back to CPU.
- copyFromXC();
-
- // Decrease funcExeInst by one as the normal commit will handle
- // incrememnting it.
- --(this->funcExeInst);
-}
-
-// This is not a pretty function, and should only be used if it is necessary
-// to fake having everything squash all at once (ie for non-full system
-// syscalls). Maybe put this at the FullCPU level?
-template <class Impl>
-void
-AlphaFullCPU<Impl>::squashStages()
-{
- InstSeqNum rob_head = this->rob.readHeadSeqNum();
-
- // Now hack the time buffer to put this sequence number in the places
- // where the stages might read it.
- for (int i = 0; i < 5; ++i)
- {
- this->timeBuffer.access(-i)->commitInfo.doneSeqNum = rob_head;
- }
-
- this->fetch.squash(this->rob.readHeadNextPC());
- this->fetchQueue.advance();
-
- this->decode.squash();
- this->decodeQueue.advance();
-
- this->rename.squash();
- this->renameQueue.advance();
- this->renameQueue.advance();
-
- // Be sure to advance the IEW queues so that the commit stage doesn't
- // try to set an instruction as completed at the same time that it
- // might be deleting it.
- this->iew.squash();
- this->iewQueue.advance();
- this->iewQueue.advance();
- // Needs to tell the LSQ to write back all of its data
- this->iew.lsqWriteback();
-
- this->rob.squash(rob_head);
- this->commit.setSquashing();
-
- // Now hack the time buffer to clear the sequence numbers in the places
- // where the stages might read it.?
- for (int i = 0; i < 5; ++i)
- {
- this->timeBuffer.access(-i)->commitInfo.doneSeqNum = 0;
- }
-
-}
-
-#endif // FULL_SYSTEM
-
-template <class Impl>
-void
-AlphaFullCPU<Impl>::copyToXC()
-{
- PhysRegIndex renamed_reg;
-
- // First loop through the integer registers.
- for (int i = 0; i < AlphaISA::NumIntRegs; ++i)
- {
- renamed_reg = this->renameMap.lookup(i);
- this->cpuXC->setIntReg(i, this->regFile.readIntReg(renamed_reg));
- DPRINTF(FullCPU, "FullCPU: Copying register %i, has data %lli.\n",
- renamed_reg, this->regFile.intRegFile[renamed_reg]);
- }
-
- // Then loop through the floating point registers.
- for (int i = 0; i < AlphaISA::NumFloatRegs; ++i)
- {
- renamed_reg = this->renameMap.lookup(i + AlphaISA::FP_Base_DepTag);
- this->cpuXC->setFloatRegBits(i,
- this->regFile.readFloatRegBits(renamed_reg));
- }
-
- this->cpuXC->setMiscReg(AlphaISA::Fpcr_DepTag,
- this->regFile.readMiscReg(AlphaISA::Fpcr_DepTag));
- this->cpuXC->setMiscReg(AlphaISA::Uniq_DepTag,
- this->regFile.readMiscReg(AlphaISA::Uniq_DepTag));
- this->cpuXC->setMiscReg(AlphaISA::Lock_Flag_DepTag,
- this->regFile.readMiscReg(AlphaISA::Lock_Flag_DepTag));
- this->cpuXC->setMiscReg(AlphaISA::Lock_Addr_DepTag,
- this->regFile.readMiscReg(AlphaISA::Lock_Addr_DepTag));
-
- this->cpuXC->setPC(this->rob.readHeadPC());
- this->cpuXC->setNextPC(this->cpuXC->readPC()+4);
-
-#if !FULL_SYSTEM
- this->cpuXC->setFuncExeInst(this->funcExeInst);
-#endif
-}
-
-// This function will probably mess things up unless the ROB is empty and
-// there are no instructions in the pipeline.
-template <class Impl>
-void
-AlphaFullCPU<Impl>::copyFromXC()
-{
- PhysRegIndex renamed_reg;
-
- // First loop through the integer registers.
- for (int i = 0; i < AlphaISA::NumIntRegs; ++i)
- {
- renamed_reg = this->renameMap.lookup(i);
-
- DPRINTF(FullCPU, "FullCPU: Copying over register %i, had data %lli, "
- "now has data %lli.\n",
- renamed_reg, this->regFile.intRegFile[renamed_reg],
- this->cpuXC->readIntReg(i));
-
- this->regFile.setIntReg(renamed_reg, this->cpuXC->readIntReg(i));
- }
-
- // Then loop through the floating point registers.
- for (int i = 0; i < AlphaISA::NumFloatRegs; ++i)
- {
- renamed_reg = this->renameMap.lookup(i + AlphaISA::FP_Base_DepTag);
- this->regFile.setFloatRegBits(renamed_reg,
- this->cpuXC->readFloatRegBits(i));
- }
-
- // Then loop through the misc registers.
- this->regFile.setMiscReg(AlphaISA::Fpcr_DepTag,
- this->cpuXC->readMiscReg(AlphaISA::Fpcr_DepTag));
- this->regFile.setMiscReg(AlphaISA::Uniq_DepTag,
- this->cpuXC->readMiscReg(AlphaISA::Uniq_DepTag));
- this->regFile.setMiscReg(AlphaISA::Lock_Flag_DepTag,
- this->cpuXC->readMiscReg(AlphaISA::Lock_Flag_DepTag));
- this->regFile.setMiscReg(AlphaISA::Lock_Addr_DepTag,
- this->cpuXC->readMiscReg(AlphaISA::Lock_Addr_DepTag));
-
- // Then finally set the PC and the next PC.
-// regFile.pc = cpuXC->regs.pc;
-// regFile.npc = cpuXC->regs.npc;
-#if !FULL_SYSTEM
- this->funcExeInst = this->cpuXC->readFuncExeInst();
-#endif
-}
-
-#if FULL_SYSTEM
-
-template <class Impl>
-int
-AlphaFullCPU<Impl>::readIntrFlag()
-{
- return this->regFile.readIntrFlag();
-}
-
-template <class Impl>
-void
-AlphaFullCPU<Impl>::setIntrFlag(int val)
-{
- this->regFile.setIntrFlag(val);
-}
-
-// Can force commit stage to squash and stuff.
-template <class Impl>
-Fault
-AlphaFullCPU<Impl>::hwrei()
-{
- if (!inPalMode())
- return new AlphaISA::UnimplementedOpcodeFault;
-
- this->setNextPC(this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR));
-
-// kernelStats.hwrei();
-
- if ((this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR) & 1) == 0)
-// AlphaISA::swap_palshadow(&regs, false);
-
- this->checkInterrupts = true;
-
- // FIXME: XXX check for interrupts? XXX
- return NoFault;
-}
-
-template <class Impl>
-bool
-AlphaFullCPU<Impl>::simPalCheck(int palFunc)
-{
-// kernelStats.callpal(palFunc);
-
- switch (palFunc) {
- case PAL::halt:
- halt();
- if (--System::numSystemsRunning == 0)
- new SimExitEvent("all cpus halted");
- break;
-
- case PAL::bpt:
- case PAL::bugchk:
- if (this->system->breakpoint())
- return false;
- break;
- }
-
- return true;
-}
-
-// Probably shouldn't be able to switch to the trap handler as quickly as
-// this. Also needs to get the exception restart address from the commit
-// stage.
-template <class Impl>
-void
-AlphaFullCPU<Impl>::trap(Fault fault)
-{
-/* // Keep in mind that a trap may be initiated by fetch if there's a TLB
- // miss
- uint64_t PC = this->commit.readCommitPC();
-
- DPRINTF(Fault, "Fault %s\n", fault->name());
- this->recordEvent(csprintf("Fault %s", fault->name()));
-
- //kernelStats.fault(fault);
-
- if (fault->isA<ArithmeticFault>())
- panic("Arithmetic traps are unimplemented!");
-
- // exception restart address - Get the commit PC
- if (!fault->isA<InterruptFault>() || !inPalMode(PC))
- this->regFile.miscRegs.setReg(AlphaISA::IPR_EXC_ADDR, PC);
-
- if (fault->isA<PalFault>() || fault->isA<ArithmeticFault>())
- // || fault == InterruptFault && !PC_PAL(regs.pc)
- {
- // traps... skip faulting instruction
- AlphaISA::MiscReg ipr_exc_addr =
- this->regFile.miscRegs.readReg(AlphaISA::IPR_EXC_ADDR);
- this->regFile.miscRegs.setReg(AlphaISA::IPR_EXC_ADDR,
- ipr_exc_addr + 4);
- }
-
- if (!inPalMode(PC))
- swapPALShadow(true);
-
- this->regFile.setPC(this->regFile.miscRegs.readReg(AlphaISA::IPR_PAL_BASE) +
- (dynamic_cast<AlphaFault *>(fault.get()))->vect());
- this->regFile.setNextPC(PC + sizeof(MachInst));*/
-}
-
-template <class Impl>
-void
-AlphaFullCPU<Impl>::processInterrupts()
-{
- // Check for interrupts here. For now can copy the code that exists
- // within isa_fullsys_traits.hh.
-}
-
-// swap_palshadow swaps in the values of the shadow registers and
-// swaps them with the values of the physical registers that map to the
-// same logical index.
-template <class Impl>
-void
-AlphaFullCPU<Impl>::swapPALShadow(bool use_shadow)
-{
- if (palShadowEnabled == use_shadow)
- panic("swap_palshadow: wrong PAL shadow state");
-
- palShadowEnabled = use_shadow;
-
- // Will have to lookup in rename map to get physical registers, then
- // swap.
-}
-
-#endif // FULL_SYSTEM
diff --git a/src/cpu/o3/base_dyn_inst.cc b/src/cpu/o3/base_dyn_inst.cc
new file mode 100644
index 000000000..0979c5c8f
--- /dev/null
+++ b/src/cpu/o3/base_dyn_inst.cc
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cpu/base_dyn_inst_impl.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.cc b/src/cpu/o3/bpred_unit.cc
index 85bd6f0a6..08fd4e8ea 100644
--- a/src/cpu/o3/bpred_unit.cc
+++ b/src/cpu/o3/bpred_unit.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,10 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/bpred_unit_impl.hh"
-#include "cpu/o3/alpha_impl.hh"
-#include "cpu/o3/alpha_dyn_inst.hh"
+#include "cpu/o3/isa_specific.hh"
-template class TwobitBPredUnit<AlphaSimpleImpl>;
+template class BPredUnit<O3CPUImpl>;
diff --git a/src/cpu/o3/bpred_unit.hh b/src/cpu/o3/bpred_unit.hh
index 2725684f7..2c0a39565 100644
--- a/src/cpu/o3/bpred_unit.hh
+++ b/src/cpu/o3/bpred_unit.hh
@@ -24,10 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __BPRED_UNIT_HH__
-#define __BPRED_UNIT_HH__
+#ifndef __CPU_O3_BPRED_UNIT_HH__
+#define __CPU_O3_BPRED_UNIT_HH__
// For Addr type.
#include "arch/isa_traits.hh"
@@ -35,99 +37,220 @@
#include "cpu/inst_seq.hh"
#include "cpu/o3/2bit_local_pred.hh"
-#include "cpu/o3/tournament_pred.hh"
#include "cpu/o3/btb.hh"
#include "cpu/o3/ras.hh"
+#include "cpu/o3/tournament_pred.hh"
#include <list>
/**
* Basically a wrapper class to hold both the branch predictor
- * and the BTB. Right now I'm unsure of the implementation; it would
- * be nicer to have something closer to the CPUPolicy or the Impl where
- * this is just typedefs, but it forces the upper level stages to be
- * aware of the constructors of the BP and the BTB. The nicer thing
- * to do is have this templated on the Impl, accept the usual Params
- * object, and be able to call the constructors on the BP and BTB.
+ * and the BTB.
*/
template<class Impl>
-class TwobitBPredUnit
+class BPredUnit
{
- public:
+ private:
typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
- TwobitBPredUnit(Params &params);
+ enum PredType {
+ Local,
+ Tournament
+ };
+
+ PredType predictor;
+ public:
+
+ /**
+ * @param params The params object, that has the size of the BP and BTB.
+ */
+ BPredUnit(Params *params);
+
+ /**
+ * Registers statistics.
+ */
void regStats();
- bool predict(DynInstPtr &inst, Addr &PC);
+ 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(DynInstPtr &inst, Addr &PC, unsigned tid);
+
+ // @todo: Rename this function.
+ void BPUncond(void * &bp_history);
- void update(const InstSeqNum &done_sn);
+ /**
+ * 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);
- void squash(const InstSeqNum &squashed_sn);
+ /**
+ * 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);
+ bool actually_taken, unsigned tid);
- bool BPLookup(Addr &inst_PC)
- { return BP.lookup(inst_PC); }
+ /**
+ * @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); }
+ { 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); }
+ { return BTB.lookup(inst_PC, 0); }
- // Will want to include global history.
- void BPUpdate(Addr &inst_PC, bool taken)
- { BP.update(inst_PC, taken); }
+ /**
+ * 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); }
+ { 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)
- : seqNum(seq_num), PC(inst_PC), predTaken(pred_taken),
- globalHistory(0), usedRAS(0), wasCall(0), RASIndex(0),
- RASTarget(0)
+ 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;
- bool predTaken;
+ /** The RAS target (only valid if a return). */
+ Addr RASTarget;
- unsigned globalHistory;
+ /** 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;
- unsigned RASIndex;
-
- Addr RASTarget;
+ /** 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;
};
- std::list<PredictorHistory> predHist;
+ 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[Impl::MaxThreads];
+
+ /** The local branch predictor. */
+ LocalBP *localBP;
- DefaultBP BP;
+ /** The tournament branch predictor. */
+ TournamentBP *tournamentBP;
+ /** The BTB. */
DefaultBTB BTB;
- ReturnAddrStack RAS;
+ /** The per-thread return address stack. */
+ ReturnAddrStack RAS[Impl::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 // __BPRED_UNIT_HH__
+#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 8d16a0cdf..0da02145b 100644
--- a/src/cpu/o3/bpred_unit_impl.hh
+++ b/src/cpu/o3/bpred_unit_impl.hh
@@ -24,27 +24,54 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/o3/bpred_unit.hh"
+using namespace std;
+
template<class Impl>
-TwobitBPredUnit<Impl>::TwobitBPredUnit(Params &params)
- : BP(params.local_predictor_size,
- params.local_ctr_bits,
- params.instShiftAmt),
- BTB(params.BTBEntries,
- params.BTBTagSize,
- params.instShiftAmt),
- RAS(params.RASSize)
+BPredUnit<Impl>::BPredUnit(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 < Impl::MaxThreads; i++)
+ RAS[i].init(params->RASSize);
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::regStats()
+BPredUnit<Impl>::regStats()
{
lookups
.name(name() + ".BPredUnit.lookups")
@@ -79,7 +106,7 @@ TwobitBPredUnit<Impl>::regStats()
usedRAS
.name(name() + ".BPredUnit.usedRAS")
- .desc("Number of times the RAS was used.")
+ .desc("Number of times the RAS was used to get a target.")
;
RASIncorrect
@@ -89,12 +116,36 @@ TwobitBPredUnit<Impl>::regStats()
}
template <class Impl>
+void
+BPredUnit<Impl>::switchOut()
+{
+ // Clear any state upon switch out.
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ squash(0, i);
+ }
+}
+
+template <class Impl>
+void
+BPredUnit<Impl>::takeOverFrom()
+{
+ // Can reset all predictor state, but it's not necessarily better
+ // than leaving it be.
+/*
+ for (int i = 0; i < Impl::MaxThreads; ++i)
+ RAS[i].reset();
+
+ BP.reset();
+ BTB.reset();
+*/
+}
+
+template <class Impl>
bool
-TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
+BPredUnit<Impl>::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.
- // Once that's done, speculatively update the predictor?
// Save off record of branch stuff so the RAS can be fixed
// up once it's done.
@@ -105,19 +156,25 @@ TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
++lookups;
+ void *bp_history = NULL;
+
if (inst->isUncondCtrl()) {
- DPRINTF(Fetch, "BranchPred: Unconditional control.\n");
+ DPRINTF(Fetch, "BranchPred: [tid:%i] Unconditional control.\n", tid);
pred_taken = true;
+ // Tell the BP there was an unconditional branch.
+ BPUncond(bp_history);
} else {
++condPredicted;
- pred_taken = BPLookup(PC);
+ pred_taken = BPLookup(PC, bp_history);
- DPRINTF(Fetch, "BranchPred: Branch predictor predicted %i for PC %#x"
- "\n", pred_taken, inst->readPC());
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
+ "for PC %#x\n",
+ tid, pred_taken, inst->readPC());
}
- PredictorHistory predict_record(inst->seqNum, PC, pred_taken);
+ PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
+ bp_history, tid);
// Now lookup in the BTB or RAS.
if (pred_taken) {
@@ -126,45 +183,48 @@ TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
// If it's a function return call, then look up the address
// in the RAS.
- target = RAS.top();
+ target = RAS[tid].top();
// Record the top entry of the RAS, and its index.
predict_record.usedRAS = true;
- predict_record.RASIndex = RAS.topIdx();
+ predict_record.RASIndex = RAS[tid].topIdx();
predict_record.RASTarget = target;
- RAS.pop();
+ assert(predict_record.RASIndex < 16);
- DPRINTF(Fetch, "BranchPred: Instruction %#x is a return, RAS "
- "predicted target: %#x, RAS index: %i.\n",
- inst->readPC(), target, predict_record.RASIndex);
+ RAS[tid].pop();
+
+ DPRINTF(Fetch, "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.push(PC+sizeof(MachInst));
+ 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(Fetch, "BranchPred: Instruction %#x was a call, "
- "adding %#x to the RAS.\n",
- inst->readPC(), PC+sizeof(MachInst));
+ DPRINTF(Fetch, "BranchPred: [tid:%i] Instruction %#x was a call"
+ ", adding %#x to the RAS.\n",
+ tid, inst->readPC(), PC + sizeof(MachInst));
}
- if (BTB.valid(PC)) {
+ if (BTB.valid(PC, tid)) {
++BTBHits;
- //If it's anything else, use the BTB to get the target addr.
- target = BTB.lookup(PC);
+ // If it's not a return, use the BTB to get the target addr.
+ target = BTB.lookup(PC, tid);
- DPRINTF(Fetch, "BranchPred: Instruction %#x predicted target "
- "is %#x.\n", inst->readPC(), target);
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
+ " target is %#x.\n",
+ tid, inst->readPC(), target);
} else {
- DPRINTF(Fetch, "BranchPred: BTB doesn't have a valid entry."
- "\n");
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
+ "valid entry.\n",tid);
pred_taken = false;
}
@@ -180,97 +240,173 @@ TwobitBPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC)
inst->setPredTarg(PC);
}
- predHist.push_front(predict_record);
+ predHist[tid].push_front(predict_record);
- assert(!predHist.empty());
+ DPRINTF(Fetch, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
return pred_taken;
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::update(const InstSeqNum &done_sn)
+BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid)
{
- DPRINTF(Fetch, "BranchPred: Commiting branches until sequence number "
- "%i.\n", done_sn);
-
- while (!predHist.empty() && predHist.back().seqNum <= done_sn) {
- assert(!predHist.empty());
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until sequence"
+ "number %lli.\n", tid, done_sn);
- // Update the branch predictor with the correct results of branches.
- BP.update(predHist.back().PC, predHist.back().predTaken);
+ 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.pop_back();
+ predHist[tid].pop_back();
}
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn)
+BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid)
{
- while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
- if (predHist.front().usedRAS) {
- DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
- "target: %#x.\n",
- predHist.front().RASIndex,
- predHist.front().RASTarget);
-
- RAS.restore(predHist.front().RASIndex,
- predHist.front().RASTarget);
- } else if (predHist.front().wasCall) {
- DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
- "to the RAS.\n");
-
- RAS.pop();
+ History &pred_hist = predHist[tid];
+
+ while (!pred_hist.empty() &&
+ pred_hist.front().seqNum > squashed_sn) {
+ if (pred_hist.front().usedRAS) {
+ DPRINTF(Fetch, "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(Fetch, "BranchPred: [tid:%i]: Removing speculative entry "
+ "added to the RAS.\n",tid);
+
+ RAS[tid].pop();
}
- predHist.pop_front();
+ // This call should delete the bpHistory.
+ BPSquash(pred_hist.front().bpHistory);
+
+ pred_hist.pop_front();
}
+
}
template <class Impl>
void
-TwobitBPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
- const Addr &corr_target,
- const bool actually_taken)
+BPredUnit<Impl>::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(Fetch, "BranchPred: Squashing from sequence number %i, "
+ DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
"setting target to %#x.\n",
- squashed_sn, corr_target);
+ tid, squashed_sn, corr_target);
- while (!predHist.empty() && predHist.front().seqNum > squashed_sn) {
+ squash(squashed_sn, tid);
- if (predHist.front().usedRAS) {
- DPRINTF(Fetch, "BranchPred: Restoring top of RAS to: %i, "
- "target: %#x.\n",
- predHist.front().RASIndex,
- predHist.front().RASTarget);
+ // 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;
+ }
- RAS.restore(predHist.front().RASIndex,
- predHist.front().RASTarget);
- } else if (predHist.front().wasCall) {
- DPRINTF(Fetch, "BranchPred: Removing speculative entry added "
- "to the RAS.\n");
+ BPUpdate(pred_hist.front().PC, actually_taken,
+ pred_hist.front().bpHistory);
- RAS.pop();
- }
+ BTB.update(pred_hist.front().PC, corr_target, tid);
+ pred_hist.pop_front();
+ }
+}
+
+template <class Impl>
+void
+BPredUnit<Impl>::BPUncond(void * &bp_history)
+{
+ // Only the tournament predictor cares about unconditional branches.
+ if (predictor == Tournament) {
+ tournamentBP->uncondBr(bp_history);
+ }
+}
- predHist.pop_front();
+template <class Impl>
+void
+BPredUnit<Impl>::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!");
}
+}
- predHist.front().predTaken = actually_taken;
+template <class Impl>
+bool
+BPredUnit<Impl>::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!");
+ }
+}
- if (predHist.front().usedRAS) {
- ++RASIncorrect;
+template <class Impl>
+void
+BPredUnit<Impl>::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!");
}
+}
+
+template <class Impl>
+void
+BPredUnit<Impl>::dump()
+{
+ typename History::iterator pred_hist_it;
+
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ if (!predHist[i].empty()) {
+ pred_hist_it = predHist[i].begin();
- BP.update(predHist.front().PC, actually_taken);
+ cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());
- BTB.update(predHist.front().PC, corr_target);
+ 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/o3/btb.cc b/src/cpu/o3/btb.cc
index 2d39c3856..01640f4d1 100644
--- a/src/cpu/o3/btb.cc
+++ b/src/cpu/o3/btb.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/intmath.hh"
@@ -39,14 +41,15 @@ DefaultBTB::DefaultBTB(unsigned _numEntries,
tagBits(_tagBits),
instShiftAmt(_instShiftAmt)
{
- // @todo Check to make sure num_entries is valid (a power of 2)
-
DPRINTF(Fetch, "BTB: Creating BTB object.\n");
- btb = new BTBEntry[numEntries];
+ if (!isPowerOf2(numEntries)) {
+ fatal("BTB entries is not a power of 2!");
+ }
- for (int i = 0; i < numEntries; ++i)
- {
+ btb.resize(numEntries);
+
+ for (int i = 0; i < numEntries; ++i) {
btb[i].valid = false;
}
@@ -57,6 +60,14 @@ DefaultBTB::DefaultBTB(unsigned _numEntries,
tagShiftAmt = instShiftAmt + floorLog2(numEntries);
}
+void
+DefaultBTB::reset()
+{
+ for (int i = 0; i < numEntries; ++i) {
+ btb[i].valid = false;
+ }
+}
+
inline
unsigned
DefaultBTB::getIndex(const Addr &inst_PC)
@@ -73,7 +84,7 @@ DefaultBTB::getTag(const Addr &inst_PC)
}
bool
-DefaultBTB::valid(const Addr &inst_PC)
+DefaultBTB::valid(const Addr &inst_PC, unsigned tid)
{
unsigned btb_idx = getIndex(inst_PC);
@@ -81,7 +92,9 @@ DefaultBTB::valid(const Addr &inst_PC)
assert(btb_idx < numEntries);
- if (btb[btb_idx].valid && inst_tag == btb[btb_idx].tag) {
+ if (btb[btb_idx].valid
+ && inst_tag == btb[btb_idx].tag
+ && btb[btb_idx].tid == tid) {
return true;
} else {
return false;
@@ -92,7 +105,7 @@ DefaultBTB::valid(const Addr &inst_PC)
// address is valid, and also the address. For now will just use addr = 0 to
// represent invalid entry.
Addr
-DefaultBTB::lookup(const Addr &inst_PC)
+DefaultBTB::lookup(const Addr &inst_PC, unsigned tid)
{
unsigned btb_idx = getIndex(inst_PC);
@@ -100,7 +113,9 @@ DefaultBTB::lookup(const Addr &inst_PC)
assert(btb_idx < numEntries);
- if (btb[btb_idx].valid && inst_tag == btb[btb_idx].tag) {
+ if (btb[btb_idx].valid
+ && inst_tag == btb[btb_idx].tag
+ && btb[btb_idx].tid == tid) {
return btb[btb_idx].target;
} else {
return 0;
@@ -108,12 +123,13 @@ DefaultBTB::lookup(const Addr &inst_PC)
}
void
-DefaultBTB::update(const Addr &inst_PC, const Addr &target)
+DefaultBTB::update(const Addr &inst_PC, const Addr &target, unsigned tid)
{
unsigned btb_idx = getIndex(inst_PC);
assert(btb_idx < numEntries);
+ btb[btb_idx].tid = tid;
btb[btb_idx].valid = true;
btb[btb_idx].target = target;
btb[btb_idx].tag = getTag(inst_PC);
diff --git a/src/cpu/o3/btb.hh b/src/cpu/o3/btb.hh
index 77bdc32ea..dfa3b7b06 100644
--- a/src/cpu/o3/btb.hh
+++ b/src/cpu/o3/btb.hh
@@ -24,13 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_BTB_HH__
-#define __CPU_O3_CPU_BTB_HH__
+#ifndef __CPU_O3_BTB_HH__
+#define __CPU_O3_BTB_HH__
// For Addr type.
#include "arch/isa_traits.hh"
+#include "base/misc.hh"
class DefaultBTB
{
@@ -42,39 +45,86 @@ class DefaultBTB
{
}
+ /** The entry's tag. */
Addr tag;
+
+ /** The entry's target. */
Addr target;
+
+ /** The entry's thread id. */
+ unsigned tid;
+
+ /** Whether or not the entry is valid. */
bool valid;
};
public:
+ /** Creates a BTB with the given number of entries, number of bits per
+ * tag, and instruction offset amount.
+ * @param numEntries Number of entries for the BTB.
+ * @param tagBits Number of bits for each tag in the BTB.
+ * @param instShiftAmt Offset amount for instructions to ignore alignment.
+ */
DefaultBTB(unsigned numEntries, unsigned tagBits,
unsigned instShiftAmt);
- Addr lookup(const Addr &inst_PC);
-
- bool valid(const Addr &inst_PC);
-
- void update(const Addr &inst_PC, const Addr &target_PC);
+ void reset();
+
+ /** Looks up an address in the BTB. Must call valid() first on the address.
+ * @param inst_PC The address of the branch to look up.
+ * @param tid The thread id.
+ * @return Returns the target of the branch.
+ */
+ Addr lookup(const Addr &inst_PC, unsigned tid);
+
+ /** Checks if a branch is in the BTB.
+ * @param inst_PC The address of the branch to look up.
+ * @param tid The thread id.
+ * @return Whether or not the branch exists in the BTB.
+ */
+ bool valid(const Addr &inst_PC, unsigned tid);
+
+ /** Updates the BTB with the target of a branch.
+ * @param inst_PC The address of the branch being updated.
+ * @param target_PC The target address of the branch.
+ * @param tid The thread id.
+ */
+ void update(const Addr &inst_PC, const Addr &target_PC,
+ unsigned tid);
private:
+ /** Returns the index into the BTB, based on the branch's PC.
+ * @param inst_PC The branch to look up.
+ * @return Returns the index into the BTB.
+ */
inline unsigned getIndex(const Addr &inst_PC);
+ /** Returns the tag bits of a given address.
+ * @param inst_PC The branch's address.
+ * @return Returns the tag bits.
+ */
inline Addr getTag(const Addr &inst_PC);
- BTBEntry *btb;
+ /** The actual BTB. */
+ std::vector<BTBEntry> btb;
+ /** The number of entries in the BTB. */
unsigned numEntries;
+ /** The index mask. */
unsigned idxMask;
+ /** The number of tag bits per entry. */
unsigned tagBits;
+ /** The tag mask. */
unsigned tagMask;
+ /** Number of bits to shift PC when calculating index. */
unsigned instShiftAmt;
+ /** Number of bits to shift PC when calculating tag. */
unsigned tagShiftAmt;
};
-#endif // __CPU_O3_CPU_BTB_HH__
+#endif // __CPU_O3_BTB_HH__
diff --git a/src/cpu/o3/checker_builder.cc b/src/cpu/o3/checker_builder.cc
new file mode 100644
index 000000000..782d963b0
--- /dev/null
+++ b/src/cpu/o3/checker_builder.cc
@@ -0,0 +1,157 @@
+/*
+ * 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
+ */
+
+#include <string>
+
+#include "cpu/checker/cpu_impl.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/alpha/dyn_inst.hh"
+#include "cpu/o3/alpha/impl.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class MemObject;
+
+template
+class Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >;
+
+/**
+ * Specific non-templated derived class used for SimObject configuration.
+ */
+class O3Checker : public Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >
+{
+ public:
+ O3Checker(Params *p)
+ : Checker<RefCountingPtr<AlphaDynInst<AlphaSimpleImpl> > >(p)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// CheckerCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(O3Checker)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+ Param<int> clock;
+
+ Param<bool> defer_registration;
+ Param<bool> exitOnError;
+ Param<bool> warnOnlyOnLoadError;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(O3Checker)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(O3Checker)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(exitOnError, "exit on error"),
+ INIT_PARAM_DFLT(warnOnlyOnLoadError, "warn, but don't exit, if a load "
+ "result errors", false),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(O3Checker)
+
+
+CREATE_SIM_OBJECT(O3Checker)
+{
+ O3Checker::Params *params = new O3Checker::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = 0;
+ params->max_insts_all_threads = 0;
+ params->max_loads_any_thread = 0;
+ params->max_loads_all_threads = 0;
+ params->exitOnError = exitOnError;
+ params->warnOnlyOnLoadError = warnOnlyOnLoadError;
+ params->deferRegistration = defer_registration;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->clock = clock;
+ // Hack to touch all parameters. Consider not deriving Checker
+ // from BaseCPU..it's not really a CPU in the end.
+ Counter temp;
+ temp = max_insts_any_thread;
+ temp = max_insts_all_threads;
+ temp = max_loads_any_thread;
+ temp = max_loads_all_threads;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ O3Checker *cpu = new O3Checker(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("O3Checker", O3Checker)
diff --git a/src/cpu/o3/comm.hh b/src/cpu/o3/comm.hh
index c74c77ddf..bf1bd08e8 100644
--- a/src/cpu/o3/comm.hh
+++ b/src/cpu/o3/comm.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,32 +24,41 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_COMM_HH__
-#define __CPU_O3_CPU_COMM_HH__
+#ifndef __CPU_O3_COMM_HH__
+#define __CPU_O3_COMM_HH__
#include <vector>
+#include "arch/faults.hh"
#include "arch/isa_traits.hh"
#include "cpu/inst_seq.hh"
#include "sim/host.hh"
-// Find better place to put this typedef.
-// The impl might be the best place for this.
+// Typedef for physical register index type. Although the Impl would be the
+// most likely location for this, there are a few classes that need this
+// typedef yet are not templated on the Impl. For now it will be defined here.
typedef short int PhysRegIndex;
+/** Struct that defines the information passed from fetch to decode. */
template<class Impl>
-struct SimpleFetchSimpleDecode {
+struct DefaultFetchDefaultDecode {
typedef typename Impl::DynInstPtr DynInstPtr;
int size;
DynInstPtr insts[Impl::MaxWidth];
+ Fault fetchFault;
+ InstSeqNum fetchFaultSN;
+ bool clearFetchFault;
};
+/** Struct that defines the information passed from decode to rename. */
template<class Impl>
-struct SimpleDecodeSimpleRename {
+struct DefaultDecodeDefaultRename {
typedef typename Impl::DynInstPtr DynInstPtr;
int size;
@@ -57,8 +66,9 @@ struct SimpleDecodeSimpleRename {
DynInstPtr insts[Impl::MaxWidth];
};
+/** Struct that defines the information passed from rename to IEW. */
template<class Impl>
-struct SimpleRenameSimpleIEW {
+struct DefaultRenameDefaultIEW {
typedef typename Impl::DynInstPtr DynInstPtr;
int size;
@@ -66,20 +76,23 @@ struct SimpleRenameSimpleIEW {
DynInstPtr insts[Impl::MaxWidth];
};
+/** Struct that defines the information passed from IEW to commit. */
template<class Impl>
-struct SimpleIEWSimpleCommit {
+struct DefaultIEWDefaultCommit {
typedef typename Impl::DynInstPtr DynInstPtr;
int size;
DynInstPtr insts[Impl::MaxWidth];
- bool squash;
- bool branchMispredict;
- bool branchTaken;
- uint64_t mispredPC;
- uint64_t nextPC;
- InstSeqNum squashedSeqNum;
+ bool squash[Impl::MaxThreads];
+ bool branchMispredict[Impl::MaxThreads];
+ bool branchTaken[Impl::MaxThreads];
+ uint64_t mispredPC[Impl::MaxThreads];
+ uint64_t nextPC[Impl::MaxThreads];
+ InstSeqNum squashedSeqNum[Impl::MaxThreads];
+
+ bool includeSquashInst[Impl::MaxThreads];
};
template<class Impl>
@@ -91,73 +104,95 @@ struct IssueStruct {
DynInstPtr insts[Impl::MaxWidth];
};
+/** Struct that defines all backwards communication. */
+template<class Impl>
struct TimeBufStruct {
struct decodeComm {
bool squash;
- bool stall;
bool predIncorrect;
uint64_t branchAddr;
InstSeqNum doneSeqNum;
- // Might want to package this kind of branch stuff into a single
+ // @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;
};
- decodeComm decodeInfo;
+ decodeComm decodeInfo[Impl::MaxThreads];
- // Rename can't actually tell anything to squash or send a new PC back
- // because it doesn't do anything along those lines. But maybe leave
- // these fields in here to keep the stages mostly orthagonal.
struct renameComm {
- bool squash;
- bool stall;
-
- uint64_t nextPC;
};
- renameComm renameInfo;
+ renameComm renameInfo[Impl::MaxThreads];
struct iewComm {
- bool stall;
-
// Also eventually include skid buffer space.
+ bool usedIQ;
unsigned freeIQEntries;
+ bool usedLSQ;
+ unsigned freeLSQEntries;
+
+ unsigned iqCount;
+ unsigned ldstqCount;
+
+ unsigned dispatched;
+ unsigned dispatchedToLSQ;
};
- iewComm iewInfo;
+ iewComm iewInfo[Impl::MaxThreads];
struct commitComm {
- bool squash;
- bool stall;
+ bool usedROB;
unsigned freeROBEntries;
+ bool emptyROB;
+
+ bool squash;
+ bool robSquashing;
bool branchMispredict;
bool branchTaken;
uint64_t mispredPC;
uint64_t nextPC;
- bool robSquashing;
-
// 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;
- // Extra bit of information so that the LDSTQ only updates when it
- // needs to.
- bool commitIsLoad;
+ //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;
+
+ // Hack for now to send back an uncached access to the IEW stage.
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ bool uncached;
+ DynInstPtr uncachedLoad;
+
+ bool interruptPending;
+ bool clearInterrupt;
};
- commitComm commitInfo;
+ commitComm commitInfo[Impl::MaxThreads];
+
+ bool decodeBlock[Impl::MaxThreads];
+ bool decodeUnblock[Impl::MaxThreads];
+ bool renameBlock[Impl::MaxThreads];
+ bool renameUnblock[Impl::MaxThreads];
+ bool iewBlock[Impl::MaxThreads];
+ bool iewUnblock[Impl::MaxThreads];
+ bool commitBlock[Impl::MaxThreads];
+ bool commitUnblock[Impl::MaxThreads];
};
-#endif //__CPU_O3_CPU_COMM_HH__
+#endif //__CPU_O3_COMM_HH__
diff --git a/src/cpu/o3/commit.cc b/src/cpu/o3/commit.cc
index cf33d7f8b..637d59f52 100644
--- a/src/cpu/o3/commit.cc
+++ b/src/cpu/o3/commit.cc
@@ -24,10 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/commit_impl.hh"
-template class SimpleCommit<AlphaSimpleImpl>;
+template class DefaultCommit<O3CPUImpl>;
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 580c1a316..60b555269 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,95 +24,276 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Todo: Maybe have a special method for handling interrupts/traps.
-//
-// Traps: Have IEW send a signal to commit saying that there's a trap to
-// be handled. Have commit send the PC back to the fetch stage, along
-// with the current commit PC. Fetch will directly access the IPR and save
-// off all the proper stuff. Commit can send out a squash, or something
-// close to it.
-// Do the same for hwrei(). However, requires that commit be specifically
-// built to support that kind of stuff. Probably not horrible to have
-// commit support having the CPU tell it to squash the other stages and
-// restart at a given address. The IPR register does become an issue.
-// Probably not a big deal if the IPR stuff isn't cycle accurate. Can just
-// have the original function handle writing to the IPR register.
-
-#ifndef __CPU_O3_CPU_SIMPLE_COMMIT_HH__
-#define __CPU_O3_CPU_SIMPLE_COMMIT_HH__
+#ifndef __CPU_O3_COMMIT_HH__
+#define __CPU_O3_COMMIT_HH__
+#include "arch/faults.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
-#include "mem/memory_interface.hh"
-
+#include "cpu/exetrace.hh"
+#include "cpu/inst_seq.hh"
+
+template <class>
+class O3ThreadState;
+
+/**
+ * DefaultCommit handles single threaded and SMT commit. Its width is
+ * specified by the parameters; each cycle it tries to commit that
+ * many instructions. The SMT policy decides which thread it tries to
+ * commit instructions from. Non- speculative instructions must reach
+ * the head of the ROB before they are ready to execute; once they
+ * reach the head, commit will broadcast the instruction's sequence
+ * number to the previous stages so that they can issue/ execute the
+ * instruction. Only one non-speculative instruction is handled per
+ * cycle. Commit is responsible for handling all back-end initiated
+ * redirects. It receives the redirect, and then broadcasts it to all
+ * stages, indicating the sequence number they should squash until,
+ * and any necessary branch misprediction information as well. It
+ * priortizes redirects by instruction's age, only broadcasting a
+ * redirect if it corresponds to an instruction that should currently
+ * be in the ROB. This is done by tracking the sequence number of the
+ * youngest instruction in the ROB, which gets updated to any
+ * squashing instruction's sequence number, and only broadcasting a
+ * redirect if it corresponds to an older instruction. Commit also
+ * supports multiple cycle squashing, to model a ROB that can only
+ * remove a certain number of instructions per cycle.
+ */
template<class Impl>
-class SimpleCommit
+class DefaultCommit
{
public:
// Typedefs from the Impl.
- typedef typename Impl::FullCPU FullCPU;
+ 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;
typedef typename CPUPol::ROB ROB;
typedef typename CPUPol::TimeStruct TimeStruct;
+ typedef typename CPUPol::FetchStruct FetchStruct;
typedef typename CPUPol::IEWStruct IEWStruct;
typedef typename CPUPol::RenameStruct RenameStruct;
- public:
- // I don't believe commit can block, so it will only have two
- // statuses for now.
- // Actually if there's a cache access that needs to block (ie
- // uncachable load or just a mem access in commit) then the stage
- // may have to wait.
- enum Status {
+ typedef typename CPUPol::Fetch Fetch;
+ typedef typename CPUPol::IEW IEW;
+
+ typedef O3ThreadState<Impl> Thread;
+
+ /** Event class used to schedule a squash due to a trap (fault or
+ * interrupt) to happen on a specific cycle.
+ */
+ class TrapEvent : public Event {
+ private:
+ DefaultCommit<Impl> *commit;
+ unsigned tid;
+
+ public:
+ TrapEvent(DefaultCommit<Impl> *_commit, unsigned _tid);
+
+ void process();
+ const char *description();
+ };
+
+ /** Overall commit status. Used to determine if the CPU can deschedule
+ * itself due to a lack of activity.
+ */
+ enum CommitStatus{
+ Active,
+ Inactive
+ };
+
+ /** Individual thread status. */
+ enum ThreadStatus {
Running,
Idle,
ROBSquashing,
- DcacheMissStall,
- DcacheMissComplete
+ TrapPending,
+ FetchTrapPending
+ };
+
+ /** Commit policy for SMT mode. */
+ enum CommitPolicy {
+ Aggressive,
+ RoundRobin,
+ OldestReady
};
private:
- Status _status;
+ /** Overall commit status. */
+ CommitStatus _status;
+ /** Next commit status, to be set at the end of the cycle. */
+ CommitStatus _nextStatus;
+ /** Per-thread status. */
+ ThreadStatus commitStatus[Impl::MaxThreads];
+ /** Commit policy used in SMT mode. */
+ CommitPolicy commitPolicy;
public:
- SimpleCommit(Params &params);
+ /** Construct a DefaultCommit with the given parameters. */
+ DefaultCommit(Params *params);
+
+ /** Returns the name of the DefaultCommit. */
+ std::string name() const;
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu_ptr);
+ /** Sets the CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+
+ /** Sets the list of threads. */
+ void setThreads(std::vector<Thread *> &threads);
+ /** Sets the main time buffer pointer, used for backwards communication. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+ void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr);
+
+ /** Sets the pointer to the queue coming from rename. */
void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+ /** Sets the pointer to the queue coming from IEW. */
void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
+ void setFetchStage(Fetch *fetch_stage);
+
+ Fetch *fetchStage;
+
+ /** Sets the pointer to the IEW stage. */
+ void setIEWStage(IEW *iew_stage);
+
+ /** The pointer to the IEW stage. Used solely to ensure that
+ * various events (traps, interrupts, syscalls) do not occur until
+ * all stores have written back.
+ */
+ IEW *iewStage;
+
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Sets pointer to the commited state rename map. */
+ void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]);
+
+ /** Sets pointer to the ROB. */
void setROB(ROB *rob_ptr);
+ /** Initializes stage by sending back the number of free entries. */
+ void initStage();
+
+ /** Initializes the switching out of commit. */
+ void switchOut();
+
+ /** Completes the switch out of commit. */
+ void doSwitchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Ticks the commit stage, which tries to commit instructions. */
void tick();
+ /** Handles any squashes that are sent from IEW, and adds instructions
+ * to the ROB and tries to commit instructions.
+ */
void commit();
+ /** Returns the number of free ROB entries for a specific thread. */
+ unsigned numROBFreeEntries(unsigned tid);
+
+ /** Generates an event to schedule a squash due to a trap. */
+ void generateTrapEvent(unsigned tid);
+
+ /** Records that commit needs to initiate a squash due to an
+ * external state update through the TC.
+ */
+ void generateTCEvent(unsigned tid);
+
private:
+ /** Updates the overall status of commit with the nextStatus, and
+ * tell the CPU if commit is active/inactive.
+ */
+ void updateStatus();
+ /** Sets the next status based on threads' statuses, which becomes the
+ * current status at the end of the cycle.
+ */
+ void setNextStatus();
+
+ /** Checks if the ROB is completed with squashing. This is for the case
+ * where the ROB can take multiple cycles to complete squashing.
+ */
+ bool robDoneSquashing();
+
+ /** Returns if any of the threads have the number of ROB entries changed
+ * on this cycle. Used to determine if the number of free ROB entries needs
+ * to be sent back to previous stages.
+ */
+ bool changedROBEntries();
+
+ /** Squashes all in flight instructions. */
+ void squashAll(unsigned tid);
+
+ /** Handles squashing due to a trap. */
+ void squashFromTrap(unsigned tid);
+
+ /** Handles squashing due to an TC write. */
+ void squashFromTC(unsigned tid);
+
+ /** Commits as many instructions as possible. */
void commitInsts();
+ /** Tries to commit the head ROB instruction passed in.
+ * @param head_inst The instruction to be committed.
+ */
bool commitHead(DynInstPtr &head_inst, unsigned inst_num);
+ /** Gets instructions from rename and inserts them into the ROB. */
void getInsts();
+ /** Marks completed instructions using information sent from IEW. */
void markCompletedInsts();
+ /** Gets the thread to commit, based on the SMT policy. */
+ int getCommittingThread();
+
+ /** Returns the thread ID to use based on a round robin policy. */
+ int roundRobin();
+
+ /** Returns the thread ID to use based on an oldest instruction policy. */
+ int oldestReady();
+
public:
- uint64_t readCommitPC();
+ /** Returns the PC of the head instruction of the ROB.
+ * @todo: Probably remove this function as it returns only thread 0.
+ */
+ uint64_t readPC() { return PC[0]; }
+
+ /** Returns the PC of a specific thread. */
+ uint64_t readPC(unsigned tid) { return PC[tid]; }
+
+ /** Sets the PC of a specific thread. */
+ void setPC(uint64_t val, unsigned tid) { PC[tid] = val; }
+
+ /** Reads the next PC of a specific thread. */
+ uint64_t readNextPC(unsigned tid) { return nextPC[tid]; }
- void setSquashing() { _status = ROBSquashing; }
+ /** Sets the next PC of a specific thread. */
+ void setNextPC(uint64_t val, unsigned tid) { nextPC[tid] = val; }
+
+#if THE_ISA != ALPHA_ISA
+ /** Reads the next NPC of a specific thread. */
+ uint64_t readNextPC(unsigned tid) { return nextNPC[tid]; }
+
+ /** Sets the next NPC of a specific thread. */
+ void setNextPC(uint64_t val, unsigned tid) { nextNPC[tid] = val; }
+#endif
private:
/** Time buffer interface. */
@@ -124,6 +305,10 @@ class SimpleCommit
/** Wire to read information from IEW (for ROB). */
typename TimeBuffer<TimeStruct>::wire robInfoFromIEW;
+ TimeBuffer<FetchStruct> *fetchQueue;
+
+ typename TimeBuffer<FetchStruct>::wire fromFetch;
+
/** IEW instruction queue interface. */
TimeBuffer<IEWStruct> *iewQueue;
@@ -136,45 +321,143 @@ class SimpleCommit
/** Wire to read information from rename queue. */
typename TimeBuffer<RenameStruct>::wire fromRename;
+ public:
/** ROB interface. */
ROB *rob;
- /** Pointer to FullCPU. */
- FullCPU *cpu;
+ private:
+ /** Pointer to O3CPU. */
+ O3CPU *cpu;
+
+ /** Vector of all of the threads. */
+ std::vector<Thread *> thread;
- /** Memory interface. Used for d-cache accesses. */
- MemInterface *dcacheInterface;
+ Fault fetchFault;
+
+ int fetchTrapWait;
+
+ /** Records that commit has written to the time buffer this cycle. Used for
+ * the CPU to determine if it can deschedule itself if there is no activity.
+ */
+ bool wroteToTimeBuffer;
+
+ /** Records if the number of ROB entries has changed this cycle. If it has,
+ * then the number of free entries must be re-broadcast.
+ */
+ bool changedROBNumEntries[Impl::MaxThreads];
+
+ /** A counter of how many threads are currently squashing. */
+ int squashCounter;
+
+ /** Records if a thread has to squash this cycle due to a trap. */
+ bool trapSquash[Impl::MaxThreads];
+
+ /** Records if a thread has to squash this cycle due to an XC write. */
+ bool tcSquash[Impl::MaxThreads];
+
+ /** Priority List used for Commit Policy */
+ std::list<unsigned> priority_list;
- private:
/** IEW to Commit delay, in ticks. */
unsigned iewToCommitDelay;
+ /** Commit to IEW delay, in ticks. */
+ unsigned commitToIEWDelay;
+
/** Rename to ROB delay, in ticks. */
unsigned renameToROBDelay;
+ unsigned fetchToCommitDelay;
+
/** Rename width, in instructions. Used so ROB knows how many
* instructions to get from the rename instruction queue.
*/
unsigned renameWidth;
- /** IEW width, in instructions. Used so ROB knows how many
- * instructions to get from the IEW instruction queue.
- */
- unsigned iewWidth;
-
/** Commit width, in instructions. */
unsigned commitWidth;
+ /** Number of Reorder Buffers */
+ unsigned numRobs;
+
+ /** Number of Active Threads */
+ unsigned numThreads;
+
+ /** Is a switch out pending. */
+ bool switchPending;
+
+ /** Is commit switched out. */
+ bool switchedOut;
+
+ /** The latency to handle a trap. Used when scheduling trap
+ * squash event.
+ */
+ Tick trapLatency;
+
+ Tick fetchTrapLatency;
+
+ Tick fetchFaultTick;
+
+ /** The commit PC of each thread. Refers to the instruction that
+ * is currently being processed/committed.
+ */
+ Addr PC[Impl::MaxThreads];
+
+ /** The next PC of each thread. */
+ Addr nextPC[Impl::MaxThreads];
+
+#if THE_ISA != ALPHA_ISA
+ /** The next NPC of each thread. */
+ Addr nextNPC[Impl::MaxThreads];
+#endif
+
+ /** The sequence number of the youngest valid instruction in the ROB. */
+ InstSeqNum youngestSeqNum[Impl::MaxThreads];
+
+ /** Pointer to the list of active threads. */
+ std::list<unsigned> *activeThreads;
+
+ /** Rename map interface. */
+ RenameMap *renameMap[Impl::MaxThreads];
+
+ /** Updates commit stats based on this instruction. */
+ void updateComInstStats(DynInstPtr &inst);
+
+ /** Stat for the total number of committed instructions. */
Stats::Scalar<> commitCommittedInsts;
+ /** Stat for the total number of squashed instructions discarded by commit.
+ */
Stats::Scalar<> commitSquashedInsts;
+ /** Stat for the total number of times commit is told to squash.
+ * @todo: Actually increment this stat.
+ */
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<> commitCommittedBranches;
- Stats::Scalar<> commitCommittedLoads;
- Stats::Scalar<> commitCommittedMemRefs;
+ /** Stat for the total number of branch mispredicts that caused a squash. */
Stats::Scalar<> branchMispredicts;
-
- Stats::Distribution<> n_committed_dist;
+ /** Distribution of the number of committed instructions each cycle. */
+ Stats::Distribution<> numCommittedDist;
+
+ /** Total number of instructions committed. */
+ Stats::Vector<> statComInst;
+ /** Total number of software prefetches committed. */
+ Stats::Vector<> statComSwp;
+ /** Stat for the total number of committed memory references. */
+ Stats::Vector<> statComRefs;
+ /** Stat for the total number of committed loads. */
+ Stats::Vector<> statComLoads;
+ /** Total number of committed memory barriers. */
+ Stats::Vector<> statComMembars;
+ /** Total number of committed branches. */
+ Stats::Vector<> statComBranches;
+
+ /** Number of cycles where the commit bandwidth limit is reached. */
+ Stats::Scalar<> commitEligibleSamples;
+ /** Number of instructions not committed due to bandwidth limits. */
+ Stats::Vector<> commitEligible;
};
-#endif // __CPU_O3_CPU_SIMPLE_COMMIT_HH__
+#endif // __CPU_O3_COMMIT_HH__
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index e289bc0c0..06b8e8a95 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,28 +24,122 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/full_system.hh"
+#include "config/use_checker.hh"
+
+#include <algorithm>
+#include <string>
+
+#include "base/loader/symtab.hh"
#include "base/timebuf.hh"
-#include "cpu/o3/commit.hh"
#include "cpu/exetrace.hh"
+#include "cpu/o3/commit.hh"
+#include "cpu/o3/thread_state.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
+using namespace std;
template <class Impl>
-SimpleCommit<Impl>::SimpleCommit(Params &params)
- : dcacheInterface(params.dcacheInterface),
- iewToCommitDelay(params.iewToCommitDelay),
- renameToROBDelay(params.renameToROBDelay),
- renameWidth(params.renameWidth),
- iewWidth(params.executeWidth),
- commitWidth(params.commitWidth)
+DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
+ unsigned _tid)
+ : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
{
- _status = Idle;
+ this->setFlags(Event::AutoDelete);
}
template <class Impl>
void
-SimpleCommit<Impl>::regStats()
+DefaultCommit<Impl>::TrapEvent::process()
+{
+ // This will get reset by commit if it was switched out at the
+ // time of this event processing.
+ commit->trapSquash[tid] = true;
+}
+
+template <class Impl>
+const char *
+DefaultCommit<Impl>::TrapEvent::description()
{
+ return "Trap event";
+}
+
+template <class Impl>
+DefaultCommit<Impl>::DefaultCommit(Params *params)
+ : squashCounter(0),
+ iewToCommitDelay(params->iewToCommitDelay),
+ commitToIEWDelay(params->commitToIEWDelay),
+ renameToROBDelay(params->renameToROBDelay),
+ fetchToCommitDelay(params->commitToFetchDelay),
+ renameWidth(params->renameWidth),
+ commitWidth(params->commitWidth),
+ numThreads(params->numberOfThreads),
+ switchPending(false),
+ switchedOut(false),
+ trapLatency(params->trapLatency),
+ fetchTrapLatency(params->fetchTrapLatency)
+{
+ _status = Active;
+ _nextStatus = Inactive;
+ string policy = params->smtCommitPolicy;
+
+ //Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ //Assign commit policy
+ if (policy == "aggressive"){
+ commitPolicy = Aggressive;
+
+ DPRINTF(Commit,"Commit Policy set to Aggressive.");
+ } else if (policy == "roundrobin"){
+ commitPolicy = RoundRobin;
+
+ //Set-Up Priority List
+ for (int tid=0; tid < numThreads; tid++) {
+ priority_list.push_back(tid);
+ }
+
+ DPRINTF(Commit,"Commit Policy set to Round Robin.");
+ } else if (policy == "oldestready"){
+ commitPolicy = OldestReady;
+
+ DPRINTF(Commit,"Commit Policy set to Oldest Ready.");
+ } else {
+ assert(0 && "Invalid SMT Commit Policy. Options Are: {Aggressive,"
+ "RoundRobin,OldestReady}");
+ }
+
+ for (int i=0; i < numThreads; i++) {
+ commitStatus[i] = Idle;
+ changedROBNumEntries[i] = false;
+ trapSquash[i] = false;
+ tcSquash[i] = false;
+ PC[i] = nextPC[i] = 0;
+ }
+
+ fetchFaultTick = 0;
+ fetchTrapWait = 0;
+}
+
+template <class Impl>
+std::string
+DefaultCommit<Impl>::name() const
+{
+ return cpu->name() + ".commit";
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::regStats()
+{
+ using namespace Stats;
commitCommittedInsts
.name(name() + ".commitCommittedInsts")
.desc("The number of committed instructions")
@@ -63,41 +157,97 @@ SimpleCommit<Impl>::regStats()
.desc("The number of times commit has been forced to stall to "
"communicate backwards")
.prereq(commitNonSpecStalls);
- commitCommittedBranches
- .name(name() + ".commitCommittedBranches")
- .desc("The number of committed branches")
- .prereq(commitCommittedBranches);
- commitCommittedLoads
- .name(name() + ".commitCommittedLoads")
- .desc("The number of committed loads")
- .prereq(commitCommittedLoads);
- commitCommittedMemRefs
- .name(name() + ".commitCommittedMemRefs")
- .desc("The number of committed memory references")
- .prereq(commitCommittedMemRefs);
branchMispredicts
.name(name() + ".branchMispredicts")
.desc("The number of times a branch was mispredicted")
.prereq(branchMispredicts);
- n_committed_dist
+ numCommittedDist
.init(0,commitWidth,1)
.name(name() + ".COM:committed_per_cycle")
.desc("Number of insts commited each cycle")
.flags(Stats::pdf)
;
+
+ statComInst
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:count")
+ .desc("Number of instructions committed")
+ .flags(total)
+ ;
+
+ statComSwp
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:swp_count")
+ .desc("Number of s/w prefetches committed")
+ .flags(total)
+ ;
+
+ statComRefs
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:refs")
+ .desc("Number of memory references committed")
+ .flags(total)
+ ;
+
+ statComLoads
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:loads")
+ .desc("Number of loads committed")
+ .flags(total)
+ ;
+
+ statComMembars
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:membars")
+ .desc("Number of memory barriers committed")
+ .flags(total)
+ ;
+
+ statComBranches
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:branches")
+ .desc("Number of branches committed")
+ .flags(total)
+ ;
+
+ commitEligible
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:bw_limited")
+ .desc("number of insts not committed due to BW limits")
+ .flags(total)
+ ;
+
+ commitEligibleSamples
+ .name(name() + ".COM:bw_lim_events")
+ .desc("number cycles where commit BW limit reached")
+ ;
}
template <class Impl>
void
-SimpleCommit<Impl>::setCPU(FullCPU *cpu_ptr)
+DefaultCommit<Impl>::setCPU(O3CPU *cpu_ptr)
{
DPRINTF(Commit, "Commit: Setting CPU pointer.\n");
cpu = cpu_ptr;
+
+ // Commit must broadcast the number of free entries it has at the start of
+ // the simulation, so it starts as active.
+ cpu->activateStage(O3CPU::CommitIdx);
+
+ trapLatency = cpu->cycles(trapLatency);
+ fetchTrapLatency = cpu->cycles(fetchTrapLatency);
}
template <class Impl>
void
-SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+DefaultCommit<Impl>::setThreads(vector<Thread *> &threads)
+{
+ thread = threads;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
DPRINTF(Commit, "Commit: Setting time buffer pointer.\n");
timeBuffer = tb_ptr;
@@ -111,7 +261,18 @@ SimpleCommit<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
template <class Impl>
void
-SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+DefaultCommit<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting fetch queue pointer.\n");
+ fetchQueue = fq_ptr;
+
+ // Setup wire to get instructions from rename (for the ROB).
+ fromFetch = fetchQueue->getWire(-fetchToCommitDelay);
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
{
DPRINTF(Commit, "Commit: Setting rename queue pointer.\n");
renameQueue = rq_ptr;
@@ -122,7 +283,7 @@ SimpleCommit<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
template <class Impl>
void
-SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
+DefaultCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
{
DPRINTF(Commit, "Commit: Setting IEW queue pointer.\n");
iewQueue = iq_ptr;
@@ -133,7 +294,40 @@ SimpleCommit<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
template <class Impl>
void
-SimpleCommit<Impl>::setROB(ROB *rob_ptr)
+DefaultCommit<Impl>::setFetchStage(Fetch *fetch_stage)
+{
+ fetchStage = fetch_stage;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setIEWStage(IEW *iew_stage)
+{
+ iewStage = iew_stage;
+}
+
+template<class Impl>
+void
+DefaultCommit<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(Commit, "Commit: Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
+{
+ DPRINTF(Commit, "Setting rename map pointers.\n");
+
+ for (int i=0; i < numThreads; i++) {
+ renameMap[i] = &rm_ptr[i];
+ }
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setROB(ROB *rob_ptr)
{
DPRINTF(Commit, "Commit: Setting ROB pointer.\n");
rob = rob_ptr;
@@ -141,107 +335,425 @@ SimpleCommit<Impl>::setROB(ROB *rob_ptr)
template <class Impl>
void
-SimpleCommit<Impl>::tick()
-{
- // If the ROB is currently in its squash sequence, then continue
- // to squash. In this case, commit does not do anything. Otherwise
- // run commit.
- if (_status == ROBSquashing) {
- if (rob->isDoneSquashing()) {
- _status = Running;
- } else {
- rob->doSquash();
-
- // Send back sequence number of tail of ROB, so other stages
- // can squash younger instructions. Note that really the only
- // stage that this is important for is the IEW stage; other
- // stages can just clear all their state as long as selective
- // replay isn't used.
- toIEW->commitInfo.doneSeqNum = rob->readTailSeqNum();
- toIEW->commitInfo.robSquashing = true;
+DefaultCommit<Impl>::initStage()
+{
+ rob->setActiveThreads(activeThreads);
+ rob->resetEntries();
+
+ // Broadcast the number of free entries.
+ for (int i=0; i < numThreads; i++) {
+ toIEW->commitInfo[i].usedROB = true;
+ toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
+ }
+
+ cpu->activityThisCycle();
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::switchOut()
+{
+ switchPending = true;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::doSwitchOut()
+{
+ switchedOut = true;
+ switchPending = false;
+ rob->switchOut();
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::takeOverFrom()
+{
+ switchedOut = false;
+ _status = Active;
+ _nextStatus = Inactive;
+ for (int i=0; i < numThreads; i++) {
+ commitStatus[i] = Idle;
+ changedROBNumEntries[i] = false;
+ trapSquash[i] = false;
+ tcSquash[i] = false;
+ }
+ squashCounter = 0;
+ rob->takeOverFrom();
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::updateStatus()
+{
+ // reset ROB changed variable
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+ changedROBNumEntries[tid] = false;
+
+ // Also check if any of the threads has a trap pending
+ if (commitStatus[tid] == TrapPending ||
+ commitStatus[tid] == FetchTrapPending) {
+ _nextStatus = Active;
+ }
+ }
+
+ if (_nextStatus == Inactive && _status == Active) {
+ DPRINTF(Activity, "Deactivating stage.\n");
+ cpu->deactivateStage(O3CPU::CommitIdx);
+ } else if (_nextStatus == Active && _status == Inactive) {
+ DPRINTF(Activity, "Activating stage.\n");
+ cpu->activateStage(O3CPU::CommitIdx);
+ }
+
+ _status = _nextStatus;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::setNextStatus()
+{
+ int squashes = 0;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (commitStatus[tid] == ROBSquashing) {
+ squashes++;
+ }
+ }
+
+ squashCounter = squashes;
+
+ // If commit is currently squashing, then it will have activity for the
+ // next cycle. Set its next status as active.
+ if (squashCounter) {
+ _nextStatus = Active;
+ }
+}
+
+template <class Impl>
+bool
+DefaultCommit<Impl>::changedROBEntries()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (changedROBNumEntries[tid]) {
+ return true;
}
- } else {
- commit();
}
+ return false;
+}
+
+template <class Impl>
+unsigned
+DefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
+{
+ return rob->numFreeEntries(tid);
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
+{
+ DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
+
+ TrapEvent *trap = new TrapEvent(this, tid);
+
+ trap->schedule(curTick + trapLatency);
+
+ thread[tid]->trapPending = true;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::generateTCEvent(unsigned tid)
+{
+ DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
+
+ tcSquash[tid] = true;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::squashAll(unsigned tid)
+{
+ // If we want to include the squashing instruction in the squash,
+ // then use one older sequence number.
+ // Hopefully this doesn't mess things up. Basically I want to squash
+ // all instructions of this thread.
+ InstSeqNum squashed_inst = rob->isEmpty() ?
+ 0 : rob->readHeadInst(tid)->seqNum - 1;;
+
+ // All younger instructions will be squashed. Set the sequence
+ // number as the youngest instruction in the ROB (0 in this case.
+ // Hopefully nothing breaks.)
+ youngestSeqNum[tid] = 0;
+
+ rob->squash(squashed_inst, tid);
+ changedROBNumEntries[tid] = true;
+
+ // Send back the sequence number of the squashed instruction.
+ toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
+
+ // Send back the squash signal to tell stages that they should
+ // squash.
+ toIEW->commitInfo[tid].squash = true;
+
+ // Send back the rob squashing signal so other stages know that
+ // the ROB is in the process of squashing.
+ toIEW->commitInfo[tid].robSquashing = true;
+
+ toIEW->commitInfo[tid].branchMispredict = false;
+
+ toIEW->commitInfo[tid].nextPC = PC[tid];
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::squashFromTrap(unsigned tid)
+{
+ squashAll(tid);
+
+ DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
+
+ thread[tid]->trapPending = false;
+ thread[tid]->inSyscall = false;
+
+ trapSquash[tid] = false;
+
+ commitStatus[tid] = ROBSquashing;
+ cpu->activityThisCycle();
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::squashFromTC(unsigned tid)
+{
+ squashAll(tid);
+
+ DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
+
+ thread[tid]->inSyscall = false;
+ assert(!thread[tid]->trapPending);
+
+ commitStatus[tid] = ROBSquashing;
+ cpu->activityThisCycle();
+
+ tcSquash[tid] = false;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::tick()
+{
+ wroteToTimeBuffer = false;
+ _nextStatus = Inactive;
+
+ if (switchPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
+ cpu->signalSwitched();
+ return;
+ }
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ // Check if any of the threads are done squashing. Change the
+ // status if they are done.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (commitStatus[tid] == ROBSquashing) {
+
+ if (rob->isDoneSquashing(tid)) {
+ commitStatus[tid] = Running;
+ } else {
+ DPRINTF(Commit,"[tid:%u]: Still Squashing, cannot commit any"
+ "insts this cycle.\n", tid);
+ rob->doSquash(tid);
+ toIEW->commitInfo[tid].robSquashing = true;
+ wroteToTimeBuffer = true;
+ }
+ }
+ }
+
+ commit();
+
markCompletedInsts();
- // Writeback number of free ROB entries here.
- DPRINTF(Commit, "Commit: ROB has %d free entries.\n",
- rob->numFreeEntries());
- toIEW->commitInfo.freeROBEntries = rob->numFreeEntries();
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
+ // The ROB has more instructions it can commit. Its next status
+ // will be active.
+ _nextStatus = Active;
+
+ DynInstPtr inst = rob->readHeadInst(tid);
+
+ DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
+ " ROB and ready to commit\n",
+ tid, inst->seqNum, inst->readPC());
+
+ } else if (!rob->isEmpty(tid)) {
+ DynInstPtr inst = rob->readHeadInst(tid);
+
+ DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
+ "%#x is head of ROB and not ready\n",
+ tid, inst->seqNum, inst->readPC());
+ }
+
+ DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
+ tid, rob->countInsts(tid), rob->numFreeEntries(tid));
+ }
+
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity This Cycle.\n");
+ cpu->activityThisCycle();
+ }
+
+ updateStatus();
}
template <class Impl>
void
-SimpleCommit<Impl>::commit()
+DefaultCommit<Impl>::commit()
{
+
//////////////////////////////////////
// Check for interrupts
//////////////////////////////////////
- // Process interrupts if interrupts are enabled and not in PAL mode.
- // Take the PC from commit and write it to the IPR, then squash. The
- // interrupt completing will take care of restoring the PC from that value
- // in the IPR. Look at IPR[EXC_ADDR];
- // hwrei() is what resets the PC to the place where instruction execution
- // beings again.
#if FULL_SYSTEM
- if (//checkInterrupts &&
+ // Process interrupts if interrupts are enabled, not in PAL mode,
+ // and no other traps or external squashes are currently pending.
+ // @todo: Allow other threads to handle interrupts.
+ if (cpu->checkInterrupts &&
cpu->check_interrupts() &&
- !cpu->inPalMode(readCommitPC())) {
- // Will need to squash all instructions currently in flight and have
- // the interrupt handler restart at the last non-committed inst.
- // Most of that can be handled through the trap() function. The
- // processInterrupts() function really just checks for interrupts
- // and then calls trap() if there is an interrupt present.
+ !cpu->inPalMode(readPC()) &&
+ !trapSquash[0] &&
+ !tcSquash[0]) {
+ // Tell fetch that there is an interrupt pending. This will
+ // make fetch wait until it sees a non PAL-mode PC, at which
+ // point it stops fetching instructions.
+ toIEW->commitInfo[0].interruptPending = true;
+
+ // Wait until the ROB is empty and all stores have drained in
+ // order to enter the interrupt.
+ if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
+ // Not sure which thread should be the one to interrupt. For now
+ // always do thread 0.
+ assert(!thread[0]->inSyscall);
+ thread[0]->inSyscall = true;
+
+ // CPU will handle implementation of the interrupt.
+ cpu->processInterrupts();
- // CPU will handle implementation of the interrupt.
- cpu->processInterrupts();
+ // Now squash or record that I need to squash this cycle.
+ commitStatus[0] = TrapPending;
+
+ // Exit state update mode to avoid accidental updating.
+ thread[0]->inSyscall = false;
+
+ // Generate trap squash event.
+ generateTrapEvent(0);
+
+ toIEW->commitInfo[0].clearInterrupt = true;
+
+ DPRINTF(Commit, "Interrupt detected.\n");
+ } else {
+ DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
+ }
}
#endif // FULL_SYSTEM
////////////////////////////////////
- // Check for squash signal, handle that first
+ // Check for any possible squashes, handle them first
////////////////////////////////////
- // Want to mainly check if the IEW stage is telling the ROB to squash.
- // Should I also check if the commit stage is telling the ROB to squah?
- // This might be necessary to keep the same timing between the IQ and
- // the ROB...
- if (fromIEW->squash) {
- DPRINTF(Commit, "Commit: Squashing instructions in the ROB.\n");
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ // Not sure which one takes priority. I think if we have
+ // both, that's a bad sign.
+ if (trapSquash[tid] == true) {
+ assert(!tcSquash[tid]);
+ squashFromTrap(tid);
+ } else if (tcSquash[tid] == true) {
+ squashFromTC(tid);
+ }
+
+ // Squashed sequence number must be older than youngest valid
+ // instruction in the ROB. This prevents squashes from younger
+ // instructions overriding squashes from older instructions.
+ if (fromIEW->squash[tid] &&
+ commitStatus[tid] != TrapPending &&
+ fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
+
+ DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
+ tid,
+ fromIEW->mispredPC[tid],
+ fromIEW->squashedSeqNum[tid]);
- _status = ROBSquashing;
+ DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
+ tid,
+ fromIEW->nextPC[tid]);
- InstSeqNum squashed_inst = fromIEW->squashedSeqNum;
+ commitStatus[tid] = ROBSquashing;
- rob->squash(squashed_inst);
+ // If we want to include the squashing instruction in the squash,
+ // then use one older sequence number.
+ InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
- // Send back the sequence number of the squashed instruction.
- toIEW->commitInfo.doneSeqNum = squashed_inst;
+ if (fromIEW->includeSquashInst[tid] == true)
+ squashed_inst--;
- // Send back the squash signal to tell stages that they should squash.
- toIEW->commitInfo.squash = true;
+ // All younger instructions will be squashed. Set the sequence
+ // number as the youngest instruction in the ROB.
+ youngestSeqNum[tid] = squashed_inst;
- // Send back the rob squashing signal so other stages know that the
- // ROB is in the process of squashing.
- toIEW->commitInfo.robSquashing = true;
+ rob->squash(squashed_inst, tid);
+ changedROBNumEntries[tid] = true;
- toIEW->commitInfo.branchMispredict = fromIEW->branchMispredict;
+ toIEW->commitInfo[tid].doneSeqNum = squashed_inst;
- toIEW->commitInfo.branchTaken = fromIEW->branchTaken;
+ toIEW->commitInfo[tid].squash = true;
- toIEW->commitInfo.nextPC = fromIEW->nextPC;
+ // Send back the rob squashing signal so other stages know that
+ // the ROB is in the process of squashing.
+ toIEW->commitInfo[tid].robSquashing = true;
- toIEW->commitInfo.mispredPC = fromIEW->mispredPC;
+ toIEW->commitInfo[tid].branchMispredict =
+ fromIEW->branchMispredict[tid];
- if (toIEW->commitInfo.branchMispredict) {
- ++branchMispredicts;
+ toIEW->commitInfo[tid].branchTaken =
+ fromIEW->branchTaken[tid];
+
+ toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
+
+ toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
+
+ if (toIEW->commitInfo[tid].branchMispredict) {
+ ++branchMispredicts;
+ }
}
+
}
- if (_status != ROBSquashing) {
+ setNextStatus();
+
+ if (squashCounter != numThreads) {
// If we're not currently squashing, then get instructions.
getInsts();
@@ -249,121 +761,186 @@ SimpleCommit<Impl>::commit()
commitInsts();
}
- // If the ROB is empty, we can set this stage to idle. Use this
- // in the future when the Idle status will actually be utilized.
-#if 0
- if (rob->isEmpty()) {
- DPRINTF(Commit, "Commit: ROB is empty. Status changed to idle.\n");
- _status = Idle;
- // Schedule an event so that commit will actually wake up
- // once something gets put in the ROB.
+ //Check for any activity
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (changedROBNumEntries[tid]) {
+ toIEW->commitInfo[tid].usedROB = true;
+ toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
+
+ if (rob->isEmpty(tid)) {
+ toIEW->commitInfo[tid].emptyROB = true;
+ }
+
+ wroteToTimeBuffer = true;
+ changedROBNumEntries[tid] = false;
+ }
}
-#endif
}
-// Loop that goes through as many instructions in the ROB as possible and
-// tries to commit them. The actual work for committing is done by the
-// commitHead() function.
template <class Impl>
void
-SimpleCommit<Impl>::commitInsts()
+DefaultCommit<Impl>::commitInsts()
{
////////////////////////////////////
// Handle commit
- // Note that commit will be handled prior to the ROB so that the ROB
- // only tries to commit instructions it has in this current cycle, and
- // not instructions it is writing in during this cycle.
- // Can't commit and squash things at the same time...
+ // Note that commit will be handled prior to putting new
+ // instructions in the ROB so that the ROB only tries to commit
+ // instructions it has in this current cycle, and not instructions
+ // it is writing in during this cycle. Can't commit and squash
+ // things at the same time...
////////////////////////////////////
- if (rob->isEmpty())
- return;
-
- DynInstPtr head_inst = rob->readHeadInst();
+ DPRINTF(Commit, "Trying to commit instructions in the ROB.\n");
unsigned num_committed = 0;
+ DynInstPtr head_inst;
+
// Commit as many instructions as possible until the commit bandwidth
// limit is reached, or it becomes impossible to commit any more.
- while (!rob->isEmpty() &&
- head_inst->readyToCommit() &&
- num_committed < commitWidth)
- {
- DPRINTF(Commit, "Commit: Trying to commit head instruction.\n");
+ while (num_committed < commitWidth) {
+ int commit_thread = getCommittingThread();
+
+ if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
+ break;
- // If the head instruction is squashed, it is ready to retire at any
- // time. However, we need to avoid updating any other state
- // incorrectly if it's already been squashed.
+ head_inst = rob->readHeadInst(commit_thread);
+
+ int tid = head_inst->threadNumber;
+
+ assert(tid == commit_thread);
+
+ DPRINTF(Commit, "Trying to commit head instruction, [sn:%i] [tid:%i]\n",
+ head_inst->seqNum, tid);
+
+ // If the head instruction is squashed, it is ready to retire
+ // (be removed from the ROB) at any time.
if (head_inst->isSquashed()) {
- DPRINTF(Commit, "Commit: Retiring squashed instruction from "
+ DPRINTF(Commit, "Retiring squashed instruction from "
"ROB.\n");
- // Tell ROB to retire head instruction. This retires the head
- // inst in the ROB without affecting any other stages.
- rob->retireHead();
+ rob->retireHead(commit_thread);
++commitSquashedInsts;
+ // Record that the number of ROB entries has changed.
+ changedROBNumEntries[tid] = true;
} else {
+ PC[tid] = head_inst->readPC();
+ nextPC[tid] = head_inst->readNextPC();
+
// Increment the total number of non-speculative instructions
// executed.
// Hack for now: it really shouldn't happen until after the
// commit is deemed to be successful, but this count is needed
// for syscalls.
- cpu->funcExeInst++;
+ thread[tid]->funcExeInst++;
// Try to commit the head instruction.
bool commit_success = commitHead(head_inst, num_committed);
- // Update what instruction we are looking at if the commit worked.
if (commit_success) {
++num_committed;
- // Send back which instruction has been committed.
- // @todo: Update this later when a wider pipeline is used.
- // Hmm, can't really give a pointer here...perhaps the
- // sequence number instead (copy).
- toIEW->commitInfo.doneSeqNum = head_inst->seqNum;
+ changedROBNumEntries[tid] = true;
+
+ // Set the doneSeqNum to the youngest committed instruction.
+ toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
++commitCommittedInsts;
- if (!head_inst->isNop()) {
- cpu->instDone();
+ // To match the old model, don't count nops and instruction
+ // prefetches towards the total commit count.
+ if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
+ cpu->instDone(tid);
+ }
+
+ PC[tid] = nextPC[tid];
+ nextPC[tid] = nextPC[tid] + sizeof(TheISA::MachInst);
+#if FULL_SYSTEM
+ int count = 0;
+ Addr oldpc;
+ do {
+ // Debug statement. Checks to make sure we're not
+ // currently updating state while handling PC events.
+ if (count == 0)
+ assert(!thread[tid]->inSyscall &&
+ !thread[tid]->trapPending);
+ oldpc = PC[tid];
+ cpu->system->pcEventQueue.service(
+ thread[tid]->getTC());
+ count++;
+ } while (oldpc != PC[tid]);
+ if (count > 1) {
+ DPRINTF(Commit, "PC skip function event, stopping commit\n");
+ break;
}
+#endif
} else {
+ DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
+ "[tid:%i] [sn:%i].\n",
+ head_inst->readPC(), tid ,head_inst->seqNum);
break;
}
}
-
- // Update the pointer to read the next instruction in the ROB.
- head_inst = rob->readHeadInst();
}
DPRINTF(CommitRate, "%i\n", num_committed);
- n_committed_dist.sample(num_committed);
+ numCommittedDist.sample(num_committed);
+
+ if (num_committed == commitWidth) {
+ commitEligibleSamples++;
+ }
}
template <class Impl>
bool
-SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
+DefaultCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
{
- // Make sure instruction is valid
assert(head_inst);
- // If the instruction is not executed yet, then it is a non-speculative
- // or store inst. Signal backwards that it should be executed.
+ int tid = head_inst->threadNumber;
+
+ // If the instruction is not executed yet, then it will need extra
+ // handling. Signal backwards that it should be executed.
if (!head_inst->isExecuted()) {
// Keep this number correct. We have not yet actually executed
// and committed this instruction.
- cpu->funcExeInst--;
-
- if (head_inst->isNonSpeculative()) {
- DPRINTF(Commit, "Commit: Encountered a store or non-speculative "
- "instruction at the head of the ROB, PC %#x.\n",
- head_inst->readPC());
+ thread[tid]->funcExeInst--;
+
+ head_inst->setAtCommit();
+
+ if (head_inst->isNonSpeculative() ||
+ head_inst->isStoreConditional() ||
+ head_inst->isMemBarrier() ||
+ head_inst->isWriteBarrier()) {
+
+ DPRINTF(Commit, "Encountered a barrier or non-speculative "
+ "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
+ head_inst->seqNum, head_inst->readPC());
+
+#if !FULL_SYSTEM
+ // Hack to make sure syscalls/memory barriers/quiesces
+ // aren't executed until all stores write back their data.
+ // This direct communication shouldn't be used for
+ // anything other than this.
+ if (inst_num > 0 || iewStage->hasStoresToWB())
+#else
+ if ((head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
+ head_inst->isQuiesce()) &&
+ iewStage->hasStoresToWB())
+#endif
+ {
+ DPRINTF(Commit, "Waiting for all stores to writeback.\n");
+ return false;
+ }
- toIEW->commitInfo.nonSpecSeqNum = head_inst->seqNum;
+ toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
// Change the instruction so it won't try to commit again until
// it is executed.
@@ -372,74 +949,110 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
++commitNonSpecStalls;
return false;
+ } else if (head_inst->isLoad()) {
+ DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
+ head_inst->seqNum, head_inst->readPC());
+
+ // Send back the non-speculative instruction's sequence
+ // number. Tell the lsq to re-execute the load.
+ toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
+ toIEW->commitInfo[tid].uncached = true;
+ toIEW->commitInfo[tid].uncachedLoad = head_inst;
+
+ head_inst->clearCanCommit();
+
+ return false;
} else {
- panic("Commit: Trying to commit un-executed instruction "
+ panic("Trying to commit un-executed instruction "
"of unknown type!\n");
}
}
- // Now check if it's one of the special trap or barrier or
- // serializing instructions.
- if (head_inst->isThreadSync() ||
- head_inst->isSerializing() ||
- head_inst->isMemBarrier() ||
- head_inst->isWriteBarrier() )
- {
- // Not handled for now. Mem barriers and write barriers are safe
- // to simply let commit as memory accesses only happen once they
- // reach the head of commit. Not sure about the other two.
- panic("Serializing or barrier instructions"
- " are not handled yet.\n");
+ if (head_inst->isThreadSync()) {
+ // Not handled for now.
+ panic("Thread sync instructions are not handled yet.\n");
}
+ // Stores mark themselves as completed.
+ if (!head_inst->isStore()) {
+ head_inst->setCompleted();
+ }
+
+#if USE_CHECKER
+ // Use checker prior to updating anything due to traps or PC
+ // based events.
+ if (cpu->checker) {
+ cpu->checker->verify(head_inst);
+ }
+#endif
+
// Check if the instruction caused a fault. If so, trap.
Fault inst_fault = head_inst->getFault();
if (inst_fault != NoFault) {
- if (!head_inst->isNop()) {
-#if FULL_SYSTEM
- cpu->trap(inst_fault);
-#else // !FULL_SYSTEM
- panic("fault (%d) detected @ PC %08p", inst_fault,
- head_inst->PC);
-#endif // FULL_SYSTEM
+ head_inst->setCompleted();
+ DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
+ head_inst->seqNum, head_inst->readPC());
+
+ if (iewStage->hasStoresToWB() || inst_num > 0) {
+ DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
+ return false;
}
- }
- // Check if we're really ready to commit. If not then return false.
- // I'm pretty sure all instructions should be able to commit if they've
- // reached this far. For now leave this in as a check.
- if (!rob->isHeadReady()) {
- panic("Commit: Unable to commit head instruction!\n");
- return false;
- }
+#if USE_CHECKER
+ if (cpu->checker && head_inst->isStore()) {
+ cpu->checker->verify(head_inst);
+ }
+#endif
- // If it's a branch, then send back branch prediction update info
- // to the fetch stage.
- // This should be handled in the iew stage if a mispredict happens...
+ assert(!thread[tid]->inSyscall);
- if (head_inst->isControl()) {
+ // Mark that we're in state update mode so that the trap's
+ // execution doesn't generate extra squashes.
+ thread[tid]->inSyscall = true;
-#if 0
- toIEW->nextPC = head_inst->readPC();
- //Maybe switch over to BTB incorrect.
- toIEW->btbMissed = head_inst->btbMiss();
- toIEW->target = head_inst->nextPC;
- //Maybe also include global history information.
- //This simple version will have no branch prediction however.
-#endif
+ // DTB will sometimes need the machine instruction for when
+ // faults happen. So we will set it here, prior to the DTB
+ // possibly needing it for its fault.
+ thread[tid]->setInst(
+ static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
+
+ // Execute the trap. Although it's slightly unrealistic in
+ // terms of timing (as it doesn't wait for the full timing of
+ // the trap event to complete before updating state), it's
+ // needed to update the state as soon as possible. This
+ // prevents external agents from changing any specific state
+ // that the trap need.
+ cpu->trap(inst_fault, tid);
+
+ // Exit state update mode to avoid accidental updating.
+ thread[tid]->inSyscall = false;
- ++commitCommittedBranches;
+ commitStatus[tid] = TrapPending;
+
+ // Generate trap squash event.
+ generateTrapEvent(tid);
+
+ return false;
}
- // Now that the instruction is going to be committed, finalize its
- // trace data.
+ updateComInstStats(head_inst);
+
if (head_inst->traceData) {
+ head_inst->traceData->setFetchSeq(head_inst->seqNum);
+ head_inst->traceData->setCPSeq(thread[tid]->numInst);
head_inst->traceData->finalize();
+ head_inst->traceData = NULL;
+ }
+
+ // Update the commit rename map
+ for (int i = 0; i < head_inst->numDestRegs(); i++) {
+ renameMap[tid]->setEntry(head_inst->destRegIdx(i),
+ head_inst->renamedDestRegIdx(i));
}
- //Finally clear the head ROB entry.
- rob->retireHead();
+ // Finally clear the head ROB entry.
+ rob->retireHead(tid);
// Return true to indicate that we have committed an instruction.
return true;
@@ -447,37 +1060,39 @@ SimpleCommit<Impl>::commitHead(DynInstPtr &head_inst, unsigned inst_num)
template <class Impl>
void
-SimpleCommit<Impl>::getInsts()
+DefaultCommit<Impl>::getInsts()
{
- //////////////////////////////////////
- // Handle ROB functions
- //////////////////////////////////////
-
- // Read any issued instructions and place them into the ROB. Do this
- // prior to squashing to avoid having instructions in the ROB that
- // don't get squashed properly.
+ // Read any renamed instructions and place them into the ROB.
int insts_to_process = min((int)renameWidth, fromRename->size);
- for (int inst_num = 0;
- inst_num < insts_to_process;
- ++inst_num)
+ for (int inst_num = 0; inst_num < insts_to_process; ++inst_num)
{
- if (!fromRename->insts[inst_num]->isSquashed()) {
- DPRINTF(Commit, "Commit: Inserting PC %#x into ROB.\n",
- fromRename->insts[inst_num]->readPC());
- rob->insertInst(fromRename->insts[inst_num]);
+ DynInstPtr inst = fromRename->insts[inst_num];
+ int tid = inst->threadNumber;
+
+ if (!inst->isSquashed() &&
+ commitStatus[tid] != ROBSquashing) {
+ changedROBNumEntries[tid] = true;
+
+ DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
+ inst->readPC(), inst->seqNum, tid);
+
+ rob->insertInst(inst);
+
+ assert(rob->getThreadEntries(tid) <= rob->getMaxEntries(tid));
+
+ youngestSeqNum[tid] = inst->seqNum;
} else {
- DPRINTF(Commit, "Commit: Instruction %i PC %#x was "
+ DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
"squashed, skipping.\n",
- fromRename->insts[inst_num]->seqNum,
- fromRename->insts[inst_num]->readPC());
+ inst->readPC(), inst->seqNum, tid);
}
}
}
template <class Impl>
void
-SimpleCommit<Impl>::markCompletedInsts()
+DefaultCommit<Impl>::markCompletedInsts()
{
// Grab completed insts out of the IEW instruction queue, and mark
// instructions completed within the ROB.
@@ -485,18 +1100,178 @@ SimpleCommit<Impl>::markCompletedInsts()
inst_num < fromIEW->size && fromIEW->insts[inst_num];
++inst_num)
{
- DPRINTF(Commit, "Commit: Marking PC %#x, SN %i ready within ROB.\n",
- fromIEW->insts[inst_num]->readPC(),
- fromIEW->insts[inst_num]->seqNum);
+ if (!fromIEW->insts[inst_num]->isSquashed()) {
+ DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
+ "within ROB.\n",
+ fromIEW->insts[inst_num]->threadNumber,
+ fromIEW->insts[inst_num]->readPC(),
+ fromIEW->insts[inst_num]->seqNum);
+
+ // Mark the instruction as ready to commit.
+ fromIEW->insts[inst_num]->setCanCommit();
+ }
+ }
+}
+
+template <class Impl>
+bool
+DefaultCommit<Impl>::robDoneSquashing()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (!rob->isDoneSquashing(tid))
+ return false;
+ }
+
+ return true;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
+{
+ unsigned thread = inst->threadNumber;
+
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch()) {
+ statComSwp[thread]++;
+ } else {
+ statComInst[thread]++;
+ }
+#else
+ statComInst[thread]++;
+#endif
+
+ //
+ // Control Instructions
+ //
+ if (inst->isControl())
+ statComBranches[thread]++;
+
+ //
+ // Memory references
+ //
+ if (inst->isMemRef()) {
+ statComRefs[thread]++;
+
+ if (inst->isLoad()) {
+ statComLoads[thread]++;
+ }
+ }
- // Mark the instruction as ready to commit.
- fromIEW->insts[inst_num]->setCanCommit();
+ if (inst->isMemBarrier()) {
+ statComMembars[thread]++;
}
}
+////////////////////////////////////////
+// //
+// SMT COMMIT POLICY MAINTAINED HERE //
+// //
+////////////////////////////////////////
template <class Impl>
-uint64_t
-SimpleCommit<Impl>::readCommitPC()
+int
+DefaultCommit<Impl>::getCommittingThread()
+{
+ if (numThreads > 1) {
+ switch (commitPolicy) {
+
+ case Aggressive:
+ //If Policy is Aggressive, commit will call
+ //this function multiple times per
+ //cycle
+ return oldestReady();
+
+ case RoundRobin:
+ return roundRobin();
+
+ case OldestReady:
+ return oldestReady();
+
+ default:
+ return -1;
+ }
+ } else {
+ int tid = (*activeThreads).front();
+
+ if (commitStatus[tid] == Running ||
+ commitStatus[tid] == Idle ||
+ commitStatus[tid] == FetchTrapPending) {
+ return tid;
+ } else {
+ return -1;
+ }
+ }
+}
+
+template<class Impl>
+int
+DefaultCommit<Impl>::roundRobin()
+{
+ list<unsigned>::iterator pri_iter = priority_list.begin();
+ list<unsigned>::iterator end = priority_list.end();
+
+ while (pri_iter != end) {
+ unsigned tid = *pri_iter;
+
+ if (commitStatus[tid] == Running ||
+ commitStatus[tid] == Idle ||
+ commitStatus[tid] == FetchTrapPending) {
+
+ if (rob->isHeadReady(tid)) {
+ priority_list.erase(pri_iter);
+ priority_list.push_back(tid);
+
+ return tid;
+ }
+ }
+
+ pri_iter++;
+ }
+
+ return -1;
+}
+
+template<class Impl>
+int
+DefaultCommit<Impl>::oldestReady()
{
- return rob->readHeadPC();
+ unsigned oldest = 0;
+ bool first = true;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (!rob->isEmpty(tid) &&
+ (commitStatus[tid] == Running ||
+ commitStatus[tid] == Idle ||
+ commitStatus[tid] == FetchTrapPending)) {
+
+ if (rob->isHeadReady(tid)) {
+
+ DynInstPtr head_inst = rob->readHeadInst(tid);
+
+ if (first) {
+ oldest = tid;
+ first = false;
+ } else if (head_inst->seqNum < oldest) {
+ oldest = tid;
+ }
+ }
+ }
+ }
+
+ if (!first) {
+ return oldest;
+ } else {
+ return -1;
+ }
}
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index a268dbc23..feca4cdf2 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,30 +24,47 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/full_system.hh"
+#include "config/use_checker.hh"
#if FULL_SYSTEM
#include "sim/system.hh"
#else
#include "sim/process.hh"
#endif
-#include "sim/root.hh"
-#include "cpu/cpu_exec_context.hh"
-#include "cpu/exec_context.hh"
-#include "cpu/o3/alpha_dyn_inst.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/activity.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/cpu.hh"
+#include "sim/root.hh"
+#include "sim/stat_control.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
using namespace std;
+using namespace TheISA;
-BaseFullCPU::BaseFullCPU(Params &params)
- : BaseCPU(&params), cpu_id(0)
+BaseO3CPU::BaseO3CPU(Params *params)
+ : BaseCPU(params), cpu_id(0)
{
}
+void
+BaseO3CPU::regStats()
+{
+ BaseCPU::regStats();
+}
+
template <class Impl>
FullO3CPU<Impl>::TickEvent::TickEvent(FullO3CPU<Impl> *c)
: Event(&mainEventQueue, CPU_Tick_Pri), cpu(c)
@@ -68,97 +85,115 @@ FullO3CPU<Impl>::TickEvent::description()
return "FullO3CPU tick event";
}
-//Call constructor to all the pipeline stages here
template <class Impl>
-FullO3CPU<Impl>::FullO3CPU(Params &params)
-#if FULL_SYSTEM
- : BaseFullCPU(params),
-#else
- : BaseFullCPU(params),
-#endif // FULL_SYSTEM
+FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
+ : Event(&mainEventQueue, CPU_Tick_Pri)
+{
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::ActivateThreadEvent::init(int thread_num,
+ FullO3CPU<Impl> *thread_cpu)
+{
+ tid = thread_num;
+ cpu = thread_cpu;
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::ActivateThreadEvent::process()
+{
+ cpu->activateThread(tid);
+}
+
+template <class Impl>
+const char *
+FullO3CPU<Impl>::ActivateThreadEvent::description()
+{
+ return "FullO3CPU \"Activate Thread\" event";
+}
+
+template <class Impl>
+FullO3CPU<Impl>::FullO3CPU(Params *params)
+ : BaseO3CPU(params),
tickEvent(this),
+ removeInstsThisCycle(false),
fetch(params),
decode(params),
rename(params),
iew(params),
commit(params),
- regFile(params.numPhysIntRegs, params.numPhysFloatRegs),
+ regFile(params->numPhysIntRegs, params->numPhysFloatRegs),
- freeList(TheISA::NumIntRegs, params.numPhysIntRegs,
- TheISA::NumFloatRegs, params.numPhysFloatRegs),
+ freeList(params->numberOfThreads,
+ TheISA::NumIntRegs, params->numPhysIntRegs,
+ TheISA::NumFloatRegs, params->numPhysFloatRegs),
- renameMap(TheISA::NumIntRegs, params.numPhysIntRegs,
- TheISA::NumFloatRegs, params.numPhysFloatRegs,
- TheISA::NumMiscRegs,
- TheISA::ZeroReg,
- TheISA::ZeroReg + TheISA::NumIntRegs),
+ rob(params->numROBEntries, params->squashWidth,
+ params->smtROBPolicy, params->smtROBThreshold,
+ params->numberOfThreads),
- rob(params.numROBEntries, params.squashWidth),
+ scoreboard(params->numberOfThreads,
+ TheISA::NumIntRegs, params->numPhysIntRegs,
+ TheISA::NumFloatRegs, params->numPhysFloatRegs,
+ TheISA::NumMiscRegs * number_of_threads,
+ TheISA::ZeroReg),
- // What to pass to these time buffers?
// For now just have these time buffers be pretty big.
+ // @todo: Make these time buffer sizes parameters or derived
+ // from latencies
timeBuffer(5, 5),
fetchQueue(5, 5),
decodeQueue(5, 5),
renameQueue(5, 5),
iewQueue(5, 5),
-
- cpuXC(NULL),
+ activityRec(NumStages, 10, params->activity),
globalSeqNum(1),
#if FULL_SYSTEM
- system(params.system),
- memCtrl(system->memctrl),
+ system(params->system),
physmem(system->physmem),
- itb(params.itb),
- dtb(params.dtb),
- mem(params.mem),
-#else
- // Hardcoded for a single thread!!
- mem(params.workload[0]->getMemory()),
#endif // FULL_SYSTEM
-
- icacheInterface(params.icacheInterface),
- dcacheInterface(params.dcacheInterface),
- deferRegistration(params.defReg),
- numInsts(0),
- funcExeInst(0)
+ mem(params->mem),
+ switchCount(0),
+ deferRegistration(params->deferRegistration),
+ numThreads(number_of_threads)
{
_status = Idle;
-#if !FULL_SYSTEM
- thread.resize(this->number_of_threads);
-#endif
+ checker = NULL;
- for (int i = 0; i < this->number_of_threads; ++i) {
+ if (params->checker) {
+#if USE_CHECKER
+ BaseCPU *temp_checker = params->checker;
+ checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
+ checker->setMemory(mem);
#if FULL_SYSTEM
- assert(i == 0);
- thread[i] = new CPUExecContext(this, 0, system, itb, dtb, mem);
- system->execContexts[i] = thread[i]->getProxy();
-
- execContexts.push_back(system->execContexts[i]);
+ checker->setSystem(params->system);
+#endif
#else
- if (i < params.workload.size()) {
- DPRINTF(FullCPU, "FullCPU: Workload[%i]'s starting PC is %#x, "
- "process is %#x",
- i, params.workload[i]->prog_entry, thread[i]);
- thread[i] = new CPUExecContext(this, i, params.workload[i], i);
- }
- assert(params.workload[i]->getMemory() != NULL);
- assert(mem != NULL);
- execContexts.push_back(thread[i]->getProxy());
-#endif // !FULL_SYSTEM
+ panic("Checker enabled but not compiled in!");
+#endif // USE_CHECKER
}
- // Note that this is a hack so that my code which still uses xc-> will
- // still work. I should remove this eventually
- cpuXC = thread[0];
+#if !FULL_SYSTEM
+ thread.resize(number_of_threads);
+ tids.resize(number_of_threads);
+#endif
+
+ // The stages also need their CPU pointer setup. However this
+ // must be done at the upper level CPU because they have pointers
+ // to the upper level CPU, and not this FullO3CPU.
- // The stages also need their CPU pointer setup. However this must be
- // done at the upper level CPU because they have pointers to the upper
- // level CPU, and not this FullO3CPU.
+ // Set up Pointers to the activeThreads list for each stage
+ fetch.setActiveThreads(&activeThreads);
+ decode.setActiveThreads(&activeThreads);
+ rename.setActiveThreads(&activeThreads);
+ iew.setActiveThreads(&activeThreads);
+ commit.setActiveThreads(&activeThreads);
// Give each of the stages the time buffer they will use.
fetch.setTimeBuffer(&timeBuffer);
@@ -170,6 +205,7 @@ FullO3CPU<Impl>::FullO3CPU(Params &params)
// Also setup each of the stages' queues.
fetch.setFetchQueue(&fetchQueue);
decode.setFetchQueue(&fetchQueue);
+ commit.setFetchQueue(&fetchQueue);
decode.setDecodeQueue(&decodeQueue);
rename.setDecodeQueue(&decodeQueue);
rename.setRenameQueue(&renameQueue);
@@ -178,16 +214,87 @@ FullO3CPU<Impl>::FullO3CPU(Params &params)
commit.setIEWQueue(&iewQueue);
commit.setRenameQueue(&renameQueue);
+ commit.setFetchStage(&fetch);
+ commit.setIEWStage(&iew);
+ rename.setIEWStage(&iew);
+ rename.setCommitStage(&commit);
+
+#if !FULL_SYSTEM
+ int active_threads = params->workload.size();
+
+ if (active_threads > Impl::MaxThreads) {
+ panic("Workload Size too large. Increase the 'MaxThreads'"
+ "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
+ "edit your workload size.");
+ }
+#else
+ int active_threads = 1;
+#endif
+
+ //Make Sure That this a Valid Architeture
+ assert(params->numPhysIntRegs >= numThreads * TheISA::NumIntRegs);
+ assert(params->numPhysFloatRegs >= numThreads * TheISA::NumFloatRegs);
+
+ rename.setScoreboard(&scoreboard);
+ iew.setScoreboard(&scoreboard);
+
// Setup the rename map for whichever stages need it.
- rename.setRenameMap(&renameMap);
- iew.setRenameMap(&renameMap);
+ PhysRegIndex lreg_idx = 0;
+ PhysRegIndex freg_idx = params->numPhysIntRegs; //Index to 1 after int regs
+
+ for (int tid=0; tid < numThreads; tid++) {
+ bool bindRegs = (tid <= active_threads - 1);
+
+ commitRenameMap[tid].init(TheISA::NumIntRegs,
+ params->numPhysIntRegs,
+ lreg_idx, //Index for Logical. Regs
+
+ TheISA::NumFloatRegs,
+ params->numPhysFloatRegs,
+ freg_idx, //Index for Float Regs
+
+ TheISA::NumMiscRegs,
+
+ TheISA::ZeroReg,
+ TheISA::ZeroReg,
+
+ tid,
+ false);
+
+ renameMap[tid].init(TheISA::NumIntRegs,
+ params->numPhysIntRegs,
+ lreg_idx, //Index for Logical. Regs
+
+ TheISA::NumFloatRegs,
+ params->numPhysFloatRegs,
+ freg_idx, //Index for Float Regs
+
+ TheISA::NumMiscRegs,
+
+ TheISA::ZeroReg,
+ TheISA::ZeroReg,
+
+ tid,
+ bindRegs);
+ }
- // Setup the free list for whichever stages need it.
+ rename.setRenameMap(renameMap);
+ commit.setRenameMap(commitRenameMap);
+
+ // Give renameMap & rename stage access to the freeList;
+ for (int i=0; i < numThreads; i++) {
+ renameMap[i].setFreeList(&freeList);
+ }
rename.setFreeList(&freeList);
- renameMap.setFreeList(&freeList);
// Setup the ROB for whichever stages need it.
commit.setROB(&rob);
+
+ lastRunningCycle = curTick;
+
+ lastActivatedCycle = -1;
+
+ contextSwitch = false;
}
template <class Impl>
@@ -199,18 +306,71 @@ template <class Impl>
void
FullO3CPU<Impl>::fullCPURegStats()
{
- // Register any of the FullCPU's stats here.
+ BaseO3CPU::regStats();
+
+ // Register any of the O3CPU's stats here.
+ timesIdled
+ .name(name() + ".timesIdled")
+ .desc("Number of times that the entire CPU went into an idle state and"
+ " unscheduled itself")
+ .prereq(timesIdled);
+
+ idleCycles
+ .name(name() + ".idleCycles")
+ .desc("Total number of cycles that the CPU has spent unscheduled due "
+ "to idling")
+ .prereq(idleCycles);
+
+ // Number of Instructions simulated
+ // --------------------------------
+ // Should probably be in Base CPU but need templated
+ // MaxThreads so put in here instead
+ committedInsts
+ .init(numThreads)
+ .name(name() + ".committedInsts")
+ .desc("Number of Instructions Simulated");
+
+ totalCommittedInsts
+ .name(name() + ".committedInsts_total")
+ .desc("Number of Instructions Simulated");
+
+ cpi
+ .name(name() + ".cpi")
+ .desc("CPI: Cycles Per Instruction")
+ .precision(6);
+ cpi = simTicks / committedInsts;
+
+ totalCpi
+ .name(name() + ".cpi_total")
+ .desc("CPI: Total CPI of All Threads")
+ .precision(6);
+ totalCpi = simTicks / totalCommittedInsts;
+
+ ipc
+ .name(name() + ".ipc")
+ .desc("IPC: Instructions Per Cycle")
+ .precision(6);
+ ipc = committedInsts / simTicks;
+
+ totalIpc
+ .name(name() + ".ipc_total")
+ .desc("IPC: Total IPC of All Threads")
+ .precision(6);
+ totalIpc = totalCommittedInsts / simTicks;
+
}
template <class Impl>
void
FullO3CPU<Impl>::tick()
{
- DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n");
+ DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
- //Tick each of the stages if they're actually running.
- //Will want to figure out a way to unschedule itself if they're all
- //going to be idle for a long time.
+ ++numCycles;
+
+// activity = false;
+
+ //Tick each of the stages
fetch.tick();
decode.tick();
@@ -221,7 +381,11 @@ FullO3CPU<Impl>::tick()
commit.tick();
- // Now advance the time buffers, unless the stage is stalled.
+#if !FULL_SYSTEM
+ doContextSwitch();
+#endif
+
+ // Now advance the time buffers
timeBuffer.advance();
fetchQueue.advance();
@@ -229,114 +393,421 @@ FullO3CPU<Impl>::tick()
renameQueue.advance();
iewQueue.advance();
- if (_status == Running && !tickEvent.scheduled())
- tickEvent.schedule(curTick + 1);
+ activityRec.advance();
+
+ if (removeInstsThisCycle) {
+ cleanUpRemovedInsts();
+ }
+
+ if (!tickEvent.scheduled()) {
+ if (_status == SwitchedOut) {
+ // increment stat
+ lastRunningCycle = curTick;
+ } else if (!activityRec.active()) {
+ lastRunningCycle = curTick;
+ timesIdled++;
+ } else {
+ tickEvent.schedule(curTick + cycles(1));
+ }
+ }
+
+#if !FULL_SYSTEM
+ updateThreadPriority();
+#endif
+
}
template <class Impl>
void
FullO3CPU<Impl>::init()
{
- if(!deferRegistration)
- {
- this->registerExecContexts();
+ 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;
- // Need to do a copy of the xc->regs into the CPU's regfile so
- // that it can start properly.
+ for (int tid=0; tid < number_of_threads; tid++) {
#if FULL_SYSTEM
- ExecContext *src_xc = system->execContexts[0];
- TheISA::initCPU(src_xc, src_xc->readCpuId());
+ ThreadContext *src_tc = threadContexts[tid];
#else
- ExecContext *src_xc = thread[0]->getProxy();
+ ThreadContext *src_tc = thread[tid]->getTC();
#endif
- // First loop through the integer registers.
- for (int i = 0; i < TheISA::NumIntRegs; ++i)
- {
- regFile.intRegFile[i] = src_xc->readIntReg(i);
+ // Threads start in the Suspended State
+ if (src_tc->status() != ThreadContext::Suspended) {
+ continue;
}
- // Then loop through the floating point registers.
- for (int i = 0; i < TheISA::NumFloatRegs; ++i)
- {
- regFile.floatRegFile.setRegBits(i, src_xc->readRegBits(i))
- }
-/*
- // Then loop through the misc registers.
- regFile.miscRegs.fpcr = src_xc->regs.miscRegs.fpcr;
- regFile.miscRegs.uniq = src_xc->regs.miscRegs.uniq;
- regFile.miscRegs.lock_flag = src_xc->regs.miscRegs.lock_flag;
- regFile.miscRegs.lock_addr = src_xc->regs.miscRegs.lock_addr;
-*/
- // Then finally set the PC and the next PC.
- regFile.pc = src_xc->readPC();
- regFile.npc = src_xc->readNextPC();
+#if FULL_SYSTEM
+ TheISA::initCPU(src_tc, src_tc->readCpuId());
+#endif
}
+
+ // Clear inSyscall.
+ for (int i = 0; i < number_of_threads; ++i)
+ thread[i]->inSyscall = false;
+
+ // Initialize stages.
+ fetch.initStage();
+ iew.initStage();
+ rename.initStage();
+ commit.initStage();
+
+ commit.setThreads(thread);
}
template <class Impl>
void
-FullO3CPU<Impl>::activateContext(int thread_num, int delay)
+FullO3CPU<Impl>::insertThread(unsigned tid)
+{
+ DPRINTF(O3CPU,"[tid:%i] Initializing thread data");
+ // Will change now that the PC and thread state is internal to the CPU
+ // and not in the ThreadContext.
+#if 0
+#if FULL_SYSTEM
+ ThreadContext *src_tc = system->threadContexts[tid];
+#else
+ ThreadContext *src_tc = thread[tid];
+#endif
+
+ //Bind Int Regs to Rename Map
+ for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
+ PhysRegIndex phys_reg = freeList.getIntReg();
+
+ renameMap[tid].setEntry(ireg,phys_reg);
+ scoreboard.setReg(phys_reg);
+ }
+
+ //Bind Float Regs to Rename Map
+ for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
+ PhysRegIndex phys_reg = freeList.getFloatReg();
+
+ renameMap[tid].setEntry(freg,phys_reg);
+ scoreboard.setReg(phys_reg);
+ }
+
+ //Copy Thread Data Into RegFile
+ this->copyFromTC(tid);
+
+ //Set PC/NPC
+ regFile.pc[tid] = src_tc->readPC();
+ regFile.npc[tid] = src_tc->readNextPC();
+
+ src_tc->setStatus(ThreadContext::Active);
+
+ activateContext(tid,1);
+
+ //Reset ROB/IQ/LSQ Entries
+ commit.rob->resetEntries();
+ iew.resetEntries();
+#endif
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::removeThread(unsigned tid)
+{
+ DPRINTF(O3CPU,"[tid:%i] Removing thread data");
+#if 0
+ //Unbind Int Regs from Rename Map
+ for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
+ PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);
+
+ scoreboard.unsetReg(phys_reg);
+ freeList.addReg(phys_reg);
+ }
+
+ //Unbind Float Regs from Rename Map
+ for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
+ PhysRegIndex phys_reg = renameMap[tid].lookup(freg);
+
+ scoreboard.unsetReg(phys_reg);
+ freeList.addReg(phys_reg);
+ }
+
+ //Copy Thread Data From RegFile
+ /* Fix Me:
+ * Do we really need to do this if we are removing a thread
+ * in the sense that it's finished (exiting)? If the thread is just
+ * being suspended we might...
+ */
+// this->copyToTC(tid);
+
+ //Squash Throughout Pipeline
+ fetch.squash(0,tid);
+ decode.squash(tid);
+ rename.squash(tid);
+
+ assert(iew.ldstQueue.getCount(tid) == 0);
+
+ //Reset ROB/IQ/LSQ Entries
+ if (activeThreads.size() >= 1) {
+ commit.rob->resetEntries();
+ iew.resetEntries();
+ }
+#endif
+}
+
+
+template <class Impl>
+void
+FullO3CPU<Impl>::activateWhenReady(int tid)
+{
+ DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming"
+ "(e.g. PhysRegs/ROB/IQ/LSQ) \n",
+ tid);
+
+ bool ready = true;
+
+ if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) {
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
+ "Phys. Int. Regs.\n",
+ tid);
+ ready = false;
+ } else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) {
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
+ "Phys. Float. Regs.\n",
+ tid);
+ ready = false;
+ } else if (commit.rob->numFreeEntries() >=
+ commit.rob->entryAmount(activeThreads.size() + 1)) {
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
+ "ROB entries.\n",
+ tid);
+ ready = false;
+ } else if (iew.instQueue.numFreeEntries() >=
+ iew.instQueue.entryAmount(activeThreads.size() + 1)) {
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
+ "IQ entries.\n",
+ tid);
+ ready = false;
+ } else if (iew.ldstQueue.numFreeEntries() >=
+ iew.ldstQueue.entryAmount(activeThreads.size() + 1)) {
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
+ "LSQ entries.\n",
+ tid);
+ ready = false;
+ }
+
+ if (ready) {
+ insertThread(tid);
+
+ contextSwitch = false;
+
+ cpuWaitList.remove(tid);
+ } else {
+ suspendContext(tid);
+
+ //blocks fetch
+ contextSwitch = true;
+
+ //do waitlist
+ cpuWaitList.push_back(tid);
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::activateThread(unsigned int tid)
+{
+ list<unsigned>::iterator isActive = find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ if (isActive == activeThreads.end()) {
+ DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
+ tid);
+
+ activeThreads.push_back(tid);
+ }
+}
+
+
+template <class Impl>
+void
+FullO3CPU<Impl>::activateContext(int tid, int delay)
{
// Needs to set each stage to running as well.
+ if (delay){
+ DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
+ "on cycle %d\n", tid, curTick + cycles(delay));
+ scheduleActivateThreadEvent(tid, delay);
+ } else {
+ activateThread(tid);
+ }
+
+ if(lastActivatedCycle < curTick) {
+ scheduleTickEvent(delay);
+
+ // Be sure to signal that there's some activity so the CPU doesn't
+ // deschedule itself.
+ activityRec.activity();
+ fetch.wakeFromQuiesce();
- scheduleTickEvent(delay);
+ lastActivatedCycle = curTick;
- _status = Running;
+ _status = Running;
+ }
}
template <class Impl>
void
-FullO3CPU<Impl>::suspendContext(int thread_num)
+FullO3CPU<Impl>::suspendContext(int tid)
{
- panic("suspendContext unimplemented!");
+ DPRINTF(O3CPU,"[tid: %i]: Suspended ...\n", tid);
+ unscheduleTickEvent();
+ _status = Idle;
+/*
+ //Remove From Active List, if Active
+ list<unsigned>::iterator isActive = find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ if (isActive != activeThreads.end()) {
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
+ tid);
+ activeThreads.erase(isActive);
+ }
+*/
}
template <class Impl>
void
-FullO3CPU<Impl>::deallocateContext(int thread_num)
+FullO3CPU<Impl>::deallocateContext(int tid)
{
- panic("deallocateContext unimplemented!");
+ DPRINTF(O3CPU,"[tid:%i]: Deallocating ...", tid);
+/*
+ //Remove From Active List, if Active
+ list<unsigned>::iterator isActive = find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ if (isActive != activeThreads.end()) {
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
+ tid);
+ activeThreads.erase(isActive);
+
+ removeThread(tid);
+ }
+*/
}
template <class Impl>
void
-FullO3CPU<Impl>::haltContext(int thread_num)
+FullO3CPU<Impl>::haltContext(int tid)
{
- panic("haltContext unimplemented!");
+ DPRINTF(O3CPU,"[tid:%i]: Halted ...", tid);
+/*
+ //Remove From Active List, if Active
+ list<unsigned>::iterator isActive = find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ if (isActive != activeThreads.end()) {
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
+ tid);
+ activeThreads.erase(isActive);
+
+ removeThread(tid);
+ }
+*/
}
template <class Impl>
void
-FullO3CPU<Impl>::switchOut()
+FullO3CPU<Impl>::switchOut(Sampler *_sampler)
{
- panic("FullO3CPU does not have a switch out function.\n");
+ sampler = _sampler;
+ switchCount = 0;
+ fetch.switchOut();
+ decode.switchOut();
+ rename.switchOut();
+ iew.switchOut();
+ commit.switchOut();
+
+ // Wake the CPU and record activity so everything can drain out if
+ // the CPU is currently idle.
+ wakeCPU();
+ activityRec.activity();
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::signalSwitched()
+{
+ if (++switchCount == NumStages) {
+ fetch.doSwitchOut();
+ rename.doSwitchOut();
+ commit.doSwitchOut();
+ instList.clear();
+ while (!removeList.empty()) {
+ removeList.pop();
+ }
+
+#if USE_CHECKER
+ if (checker)
+ checker->switchOut(sampler);
+#endif
+
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ sampler->signalSwitched();
+ _status = SwitchedOut;
+ }
+ assert(switchCount <= 5);
}
template <class Impl>
void
FullO3CPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
{
+ // Flush out any old data from the time buffers.
+ for (int i = 0; i < 10; ++i) {
+ timeBuffer.advance();
+ fetchQueue.advance();
+ decodeQueue.advance();
+ renameQueue.advance();
+ iewQueue.advance();
+ }
+
+ activityRec.reset();
+
BaseCPU::takeOverFrom(oldCPU);
+ fetch.takeOverFrom();
+ decode.takeOverFrom();
+ rename.takeOverFrom();
+ iew.takeOverFrom();
+ commit.takeOverFrom();
+
assert(!tickEvent.scheduled());
- // Set all status's to active, schedule the
- // CPU's tick event.
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
- if (xc->status() == ExecContext::Active && _status != Running) {
+ // @todo: Figure out how to properly select the tid to put onto
+ // the active threads list.
+ int tid = 0;
+
+ list<unsigned>::iterator isActive = find(
+ activeThreads.begin(), activeThreads.end(), tid);
+
+ if (isActive == activeThreads.end()) {
+ //May Need to Re-code this if the delay variable is the delay
+ //needed for thread to activate
+ DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",
+ tid);
+
+ activeThreads.push_back(tid);
+ }
+
+ // Set all statuses to active, schedule the CPU's tick event.
+ // @todo: Fix up statuses so this is handled properly
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
tickEvent.schedule(curTick);
}
}
-}
-
-template <class Impl>
-InstSeqNum
-FullO3CPU<Impl>::getAndIncrementInstSeq()
-{
- // Hopefully this works right.
- return globalSeqNum++;
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick);
}
template <class Impl>
@@ -411,156 +882,384 @@ FullO3CPU<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
template <class Impl>
uint64_t
-FullO3CPU<Impl>::readPC()
+FullO3CPU<Impl>::readArchIntReg(int reg_idx, unsigned tid)
{
- return regFile.readPC();
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
+
+ return regFile.readIntReg(phys_reg);
+}
+
+template <class Impl>
+float
+FullO3CPU<Impl>::readArchFloatRegSingle(int reg_idx, unsigned tid)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
+
+ return regFile.readFloatReg(phys_reg);
+}
+
+template <class Impl>
+double
+FullO3CPU<Impl>::readArchFloatRegDouble(int reg_idx, unsigned tid)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
+
+ return regFile.readFloatReg(phys_reg, 64);
+}
+
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readArchFloatRegInt(int reg_idx, unsigned tid)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(idx);
+
+ return regFile.readFloatRegBits(phys_reg);
}
template <class Impl>
void
-FullO3CPU<Impl>::setNextPC(uint64_t val)
+FullO3CPU<Impl>::setArchIntReg(int reg_idx, uint64_t val, unsigned tid)
{
- regFile.setNextPC(val);
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
+
+ regFile.setIntReg(phys_reg, val);
}
template <class Impl>
void
-FullO3CPU<Impl>::setPC(Addr new_PC)
+FullO3CPU<Impl>::setArchFloatRegSingle(int reg_idx, float val, unsigned tid)
{
- regFile.setPC(new_PC);
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
+
+ regFile.setFloatReg(phys_reg, val);
}
template <class Impl>
void
-FullO3CPU<Impl>::addInst(DynInstPtr &inst)
+FullO3CPU<Impl>::setArchFloatRegDouble(int reg_idx, double val, unsigned tid)
{
- instList.push_back(inst);
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
+
+ regFile.setFloatReg(phys_reg, val, 64);
}
template <class Impl>
void
-FullO3CPU<Impl>::instDone()
+FullO3CPU<Impl>::setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid)
{
- // Keep an instruction count.
- numInsts++;
+ PhysRegIndex phys_reg = commitRenameMap[tid].lookup(reg_idx);
- // Check for instruction-count-based events.
- comInstEventQueue[0]->serviceEvents(numInsts);
+ regFile.setFloatRegBits(phys_reg, val);
+}
+
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readPC(unsigned tid)
+{
+ return commit.readPC(tid);
}
template <class Impl>
void
-FullO3CPU<Impl>::removeBackInst(DynInstPtr &inst)
+FullO3CPU<Impl>::setPC(Addr new_PC,unsigned tid)
{
- DynInstPtr inst_to_delete;
+ commit.setPC(new_PC, tid);
+}
- // Walk through the instruction list, removing any instructions
- // that were inserted after the given instruction, inst.
- while (instList.back() != inst)
- {
- assert(!instList.empty());
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readNextPC(unsigned tid)
+{
+ return commit.readNextPC(tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setNextPC(uint64_t val,unsigned tid)
+{
+ commit.setNextPC(val, tid);
+}
- // Obtain the pointer to the instruction.
- inst_to_delete = instList.back();
+#if THE_ISA != ALPHA_ISA
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readNextNPC(unsigned tid)
+{
+ return commit.readNextNPC(tid);
+}
- DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
- inst_to_delete->seqNum, inst_to_delete->readPC());
+template <class Impl>
+void
+FullO3CPU<Impl>::setNextNNPC(uint64_t val,unsigned tid)
+{
+ commit.setNextNPC(val, tid);
+}
+#endif
- // Remove the instruction from the list.
- instList.pop_back();
+template <class Impl>
+typename FullO3CPU<Impl>::ListIt
+FullO3CPU<Impl>::addInst(DynInstPtr &inst)
+{
+ instList.push_back(inst);
- // Mark it as squashed.
- inst_to_delete->setSquashed();
- }
+ return --(instList.end());
}
template <class Impl>
void
-FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
+FullO3CPU<Impl>::instDone(unsigned tid)
{
- DynInstPtr inst_to_remove;
+ // Keep an instruction count.
+ thread[tid]->numInst++;
+ thread[tid]->numInsts++;
+ committedInsts[tid]++;
+ totalCommittedInsts++;
- // The front instruction should be the same one being asked to be removed.
- assert(instList.front() == inst);
+ // Check for instruction-count-based events.
+ comInstEventQueue[tid]->serviceEvents(thread[tid]->numInst);
+}
- // Remove the front instruction.
- inst_to_remove = inst;
- instList.pop_front();
+template <class Impl>
+void
+FullO3CPU<Impl>::addToRemoveList(DynInstPtr &inst)
+{
+ removeInstsThisCycle = true;
- DPRINTF(FullCPU, "FullCPU: Removing committed instruction %#x, PC %#x\n",
- inst_to_remove, inst_to_remove->readPC());
+ removeList.push(inst->getInstListIt());
}
template <class Impl>
void
-FullO3CPU<Impl>::removeInstsNotInROB()
+FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
{
- DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
- "list.\n");
+ DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x "
+ "[sn:%lli]\n",
+ inst->threadNumber, inst->readPC(), inst->seqNum);
- DynInstPtr rob_tail = rob.readTailInst();
+ removeInstsThisCycle = true;
- removeBackInst(rob_tail);
+ // Remove the front instruction.
+ removeList.push(inst->getInstListIt());
}
template <class Impl>
void
-FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num)
+FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid)
{
- DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
- "list.\n");
+ DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
+ " list.\n", tid);
+
+ ListIt end_it;
+
+ bool rob_empty = false;
+
+ if (instList.empty()) {
+ return;
+ } else if (rob.isEmpty(/*tid*/)) {
+ DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
+ end_it = instList.begin();
+ rob_empty = true;
+ } else {
+ end_it = (rob.readTailInst(tid))->getInstListIt();
+ DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
+ }
+
+ removeInstsThisCycle = true;
+
+ ListIt inst_it = instList.end();
- DynInstPtr inst_to_delete;
+ inst_it--;
- while (instList.back()->seqNum > seq_num) {
+ // Walk through the instruction list, removing any instructions
+ // that were inserted after the given instruction iterator, end_it.
+ while (inst_it != end_it) {
assert(!instList.empty());
- // Obtain the pointer to the instruction.
- inst_to_delete = instList.back();
+ squashInstIt(inst_it, tid);
- DPRINTF(FullCPU, "FullCPU: Removing instruction %i, PC %#x\n",
- inst_to_delete->seqNum, inst_to_delete->readPC());
+ inst_it--;
+ }
- // Remove the instruction from the list.
- instList.back() = NULL;
- instList.pop_back();
+ // If the ROB was empty, then we actually need to remove the first
+ // instruction as well.
+ if (rob_empty) {
+ squashInstIt(inst_it, tid);
+ }
+}
- // Mark it as squashed.
- inst_to_delete->setSquashed();
+template <class Impl>
+void
+FullO3CPU<Impl>::removeInstsUntil(const InstSeqNum &seq_num,
+ unsigned tid)
+{
+ assert(!instList.empty());
+
+ removeInstsThisCycle = true;
+
+ ListIt inst_iter = instList.end();
+
+ inst_iter--;
+
+ DPRINTF(O3CPU, "Deleting instructions from instruction "
+ "list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
+ tid, seq_num, (*inst_iter)->seqNum);
+
+ while ((*inst_iter)->seqNum > seq_num) {
+
+ bool break_loop = (inst_iter == instList.begin());
+
+ squashInstIt(inst_iter, tid);
+
+ inst_iter--;
+
+ if (break_loop)
+ break;
}
+}
+template <class Impl>
+inline void
+FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid)
+{
+ if ((*instIt)->threadNumber == tid) {
+ DPRINTF(O3CPU, "Squashing instruction, "
+ "[tid:%i] [sn:%lli] PC %#x\n",
+ (*instIt)->threadNumber,
+ (*instIt)->seqNum,
+ (*instIt)->readPC());
+
+ // Mark it as squashed.
+ (*instIt)->setSquashed();
+
+ // @todo: Formulate a consistent method for deleting
+ // instructions from the instruction list
+ // Remove the instruction from the list.
+ removeList.push(instIt);
+ }
}
template <class Impl>
void
+FullO3CPU<Impl>::cleanUpRemovedInsts()
+{
+ while (!removeList.empty()) {
+ DPRINTF(O3CPU, "Removing instruction, "
+ "[tid:%i] [sn:%lli] PC %#x\n",
+ (*removeList.front())->threadNumber,
+ (*removeList.front())->seqNum,
+ (*removeList.front())->readPC());
+
+ instList.erase(removeList.front());
+
+ removeList.pop();
+ }
+
+ removeInstsThisCycle = false;
+}
+/*
+template <class Impl>
+void
FullO3CPU<Impl>::removeAllInsts()
{
instList.clear();
}
-
+*/
template <class Impl>
void
FullO3CPU<Impl>::dumpInsts()
{
int num = 0;
- typename list<DynInstPtr>::iterator inst_list_it = instList.begin();
- while (inst_list_it != instList.end())
- {
- cprintf("Instruction:%i\nPC:%#x\nSN:%lli\nIssued:%i\nSquashed:%i\n\n",
- num, (*inst_list_it)->readPC(), (*inst_list_it)->seqNum,
- (*inst_list_it)->isIssued(), (*inst_list_it)->isSquashed());
+ ListIt inst_list_it = instList.begin();
+
+ cprintf("Dumping Instruction List\n");
+
+ while (inst_list_it != instList.end()) {
+ cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
+ "Squashed:%i\n\n",
+ num, (*inst_list_it)->readPC(), (*inst_list_it)->threadNumber,
+ (*inst_list_it)->seqNum, (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
inst_list_it++;
++num;
}
}
-
+/*
template <class Impl>
void
FullO3CPU<Impl>::wakeDependents(DynInstPtr &inst)
{
iew.wakeDependents(inst);
}
+*/
+template <class Impl>
+void
+FullO3CPU<Impl>::wakeCPU()
+{
+ if (activityRec.active() || tickEvent.scheduled()) {
+ DPRINTF(Activity, "CPU already running.\n");
+ return;
+ }
+
+ DPRINTF(Activity, "Waking up CPU\n");
+
+ idleCycles += (curTick - 1) - lastRunningCycle;
+
+ tickEvent.schedule(curTick);
+}
+
+template <class Impl>
+int
+FullO3CPU<Impl>::getFreeTid()
+{
+ for (int i=0; i < numThreads; i++) {
+ if (!tids[i]) {
+ tids[i] = true;
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::doContextSwitch()
+{
+ if (contextSwitch) {
+
+ //ADD CODE TO DEACTIVE THREAD HERE (???)
+
+ for (int tid=0; tid < cpuWaitList.size(); tid++) {
+ activateWhenReady(tid);
+ }
+
+ if (cpuWaitList.size() == 0)
+ contextSwitch = true;
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::updateThreadPriority()
+{
+ if (activeThreads.size() > 1)
+ {
+ //DEFAULT TO ROUND ROBIN SCHEME
+ //e.g. Move highest priority to end of thread list
+ list<unsigned>::iterator list_begin = activeThreads.begin();
+ list<unsigned>::iterator list_end = activeThreads.end();
+
+ unsigned high_thread = *list_begin;
+
+ activeThreads.erase(list_begin);
+
+ activeThreads.push_back(high_thread);
+ }
+}
// Forward declaration of FullO3CPU.
-template class FullO3CPU<AlphaSimpleImpl>;
+template class FullO3CPU<O3CPUImpl>;
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index f7c80e8a1..1cff6142d 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -24,120 +24,264 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-//Todo: Add in a lot of the functions that are ISA specific. Also define
-//the functions that currently exist within the base cpu class. Define
-//everything for the simobject stuff so it can be serialized and
-//instantiated, add in debugging statements everywhere. Have CPU schedule
-//itself properly. Threads!
-// Avoid running stages and advancing queues if idle/stalled.
-
-#ifndef __CPU_O3_CPU_FULL_CPU_HH__
-#define __CPU_O3_CPU_FULL_CPU_HH__
+#ifndef __CPU_O3_CPU_HH__
+#define __CPU_O3_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/cpu_exec_context.hh"
+#include "cpu/simple_thread.hh"
#include "cpu/o3/comm.hh"
#include "cpu/o3/cpu_policy.hh"
+#include "cpu/o3/scoreboard.hh"
+#include "cpu/o3/thread_state.hh"
+//#include "cpu/o3/thread_context.hh"
#include "sim/process.hh"
-class ExecContext;
-class FunctionalMemory;
+template <class>
+class Checker;
+class ThreadContext;
+template <class>
+class O3ThreadContext;
+class MemObject;
class Process;
-class BaseFullCPU : public BaseCPU
+class BaseO3CPU : public BaseCPU
{
//Stuff that's pretty ISA independent will go here.
public:
typedef BaseCPU::Params Params;
-#if FULL_SYSTEM
- BaseFullCPU(Params &params);
-#else
- BaseFullCPU(Params &params);
-#endif // FULL_SYSTEM
+ BaseO3CPU(Params *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;
};
+/**
+ * FullO3CPU class, has each of the stages (fetch through commit)
+ * within it, as well as all of the time buffers between stages. The
+ * tick() function for the CPU is defined here.
+ */
template <class Impl>
-class FullO3CPU : public BaseFullCPU
+class FullO3CPU : public BaseO3CPU
{
public:
- //Put typedefs from the Impl here.
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+
+ // Typedefs from the Impl here.
typedef typename Impl::CPUPol CPUPolicy;
typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef O3ThreadState<Impl> Thread;
+
+ typedef typename std::list<DynInstPtr>::iterator ListIt;
+
+ friend class O3ThreadContext<Impl>;
+
public:
enum Status {
Running,
Idle,
Halted,
- Blocked // ?
+ Blocked,
+ SwitchedOut
};
+ /** Overall CPU status. */
Status _status;
+ /** Per-thread status in CPU, used for SMT. */
+ Status _threadStatus[Impl::MaxThreads];
+
private:
class TickEvent : public Event
{
private:
+ /** Pointer to the CPU. */
FullO3CPU<Impl> *cpu;
public:
+ /** Constructs a tick event. */
TickEvent(FullO3CPU<Impl> *c);
+
+ /** Processes a tick event, calling tick() on the CPU. */
void process();
+ /** Returns the description of the tick event. */
const char *description();
};
+ /** The tick event used for scheduling CPU ticks. */
TickEvent tickEvent;
- /// Schedule tick event, regardless of its current state.
+ /** Schedule tick event, regardless of its current state. */
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
- tickEvent.reschedule(curTick + delay);
+ tickEvent.reschedule(curTick + cycles(delay));
else if (!tickEvent.scheduled())
- tickEvent.schedule(curTick + delay);
+ tickEvent.schedule(curTick + cycles(delay));
}
- /// Unschedule tick event, regardless of its current state.
+ /** Unschedule tick event, regardless of its current state. */
void unscheduleTickEvent()
{
if (tickEvent.scheduled())
tickEvent.squash();
}
+ class ActivateThreadEvent : public Event
+ {
+ private:
+ /** Number of Thread to Activate */
+ int tid;
+
+ /** Pointer to the CPU. */
+ FullO3CPU<Impl> *cpu;
+
+ public:
+ /** Constructs the event. */
+ ActivateThreadEvent();
+
+ /** Initialize Event */
+ void init(int thread_num, FullO3CPU<Impl> *thread_cpu);
+
+ /** Processes the event, calling activateThread() on the CPU. */
+ void process();
+
+ /** Returns the description of the event. */
+ const char *description();
+ };
+
+ /** Schedule thread to activate , regardless of its current state. */
+ void scheduleActivateThreadEvent(int tid, int delay)
+ {
+ // Schedule thread to activate, regardless of its current state.
+ if (activateThreadEvent[tid].squashed())
+ activateThreadEvent[tid].reschedule(curTick + cycles(delay));
+ else if (!activateThreadEvent[tid].scheduled())
+ activateThreadEvent[tid].schedule(curTick + cycles(delay));
+ }
+
+ /** Unschedule actiavte thread event, regardless of its current state. */
+ void unscheduleActivateThreadEvent(int tid)
+ {
+ if (activateThreadEvent[tid].scheduled())
+ activateThreadEvent[tid].squash();
+ }
+
+ /** The tick event used for scheduling CPU ticks. */
+ ActivateThreadEvent activateThreadEvent[Impl::MaxThreads];
+
public:
- FullO3CPU(Params &params);
+ /** Constructs a CPU with the given parameters. */
+ FullO3CPU(Params *params);
+ /** Destructor. */
~FullO3CPU();
+ /** Registers statistics. */
void fullCPURegStats();
+ /** Ticks CPU, calling tick() on each stage, and checking the overall
+ * activity to see if the CPU should deschedule itself.
+ */
void tick();
+ /** Initialize the CPU */
void init();
- void activateContext(int thread_num, int delay);
- void suspendContext(int thread_num);
- void deallocateContext(int thread_num);
- void haltContext(int thread_num);
+ /** Returns the Number of Active Threads in the CPU */
+ int numActiveThreads()
+ { return activeThreads.size(); }
+
+ /** Add Thread to Active Threads List */
+ void activateThread(unsigned int 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);
+
+ /** Count the Total Instructions Committed in the CPU. */
+ virtual Counter totalInstructions() const
+ {
+ Counter total(0);
+
+ for (int i=0; i < thread.size(); i++)
+ total += thread[i]->numInst;
+
+ return total;
+ }
+
+ /** Add Thread to Active Threads List. */
+ void activateContext(int tid, int delay);
+
+ /** Remove Thread from Active Threads List */
+ void suspendContext(int tid);
+
+ /** Remove Thread from Active Threads List &&
+ * Remove Thread Context from CPU.
+ */
+ void deallocateContext(int tid);
+
+ /** Remove Thread from Active Threads List &&
+ * Remove Thread Context from CPU.
+ */
+ void haltContext(int tid);
+
+ /** Activate a Thread When CPU Resources are Available. */
+ void activateWhenReady(int tid);
+
+ /** Add or Remove a Thread Context in the CPU. */
+ void doContextSwitch();
+
+ /** Update The Order In Which We Process Threads. */
+ void updateThreadPriority();
+
+ /** Executes a syscall on this cycle.
+ * ---------------------------------------
+ * Note: this is a virtual function. CPU-Specific
+ * functionality defined in derived classes
+ */
+ virtual void syscall(int tid) { panic("Unimplemented!"); }
+
+ /** Switches out this CPU. */
+ void switchOut(Sampler *sampler);
+
+ /** Signals to this CPU that a stage has completed switching out. */
+ void signalSwitched();
- void switchOut();
+ /** Takes over from another CPU. */
void takeOverFrom(BaseCPU *oldCPU);
/** Get the current instruction sequence number, and increment it. */
- InstSeqNum getAndIncrementInstSeq();
+ InstSeqNum getAndIncrementInstSeq()
+ { return globalSeqNum++; }
#if FULL_SYSTEM
/** Check if this address is a valid instruction address. */
@@ -147,27 +291,24 @@ class FullO3CPU : public BaseFullCPU
bool validDataAddr(Addr addr) { return true; }
/** Get instruction asid. */
- int getInstAsid()
- { return regFile.miscRegs.getInstAsid(); }
+ int getInstAsid(unsigned tid)
+ { return regFile.miscRegs[tid].getInstAsid(); }
/** Get data asid. */
- int getDataAsid()
- { return regFile.miscRegs.getDataAsid(); }
+ int getDataAsid(unsigned tid)
+ { return regFile.miscRegs[tid].getDataAsid(); }
#else
- bool validInstAddr(Addr addr)
- { return thread[0]->validInstAddr(addr); }
-
- bool validDataAddr(Addr addr)
- { return thread[0]->validDataAddr(addr); }
+ /** Get instruction asid. */
+ int getInstAsid(unsigned tid)
+ { return thread[tid]->getInstAsid(); }
- int getInstAsid() { return thread[0]->getInstAsid(); }
- int getDataAsid() { return thread[0]->getDataAsid(); }
+ /** Get data asid. */
+ int getDataAsid(unsigned tid)
+ { return thread[tid]->getDataAsid(); }
#endif
- //
- // New accessors for new decoder.
- //
+ /** Register accessors. Index refers to the physical register index. */
uint64_t readIntReg(int reg_idx);
FloatReg readFloatReg(int reg_idx);
@@ -180,103 +321,121 @@ class FullO3CPU : public BaseFullCPU
void setIntReg(int reg_idx, uint64_t val);
- void setFloatReg(int reg_idx, FloatReg val, int width);
+ void setFloatReg(int reg_idx, FloatReg val);
void setFloatReg(int reg_idx, FloatReg val, int width);
void setFloatRegBits(int reg_idx, FloatRegBits val);
- void setFloatRegBits(int reg_idx, FloatRegBits val);
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
+
+ uint64_t readArchIntReg(int reg_idx, unsigned tid);
+
+ float readArchFloatRegSingle(int reg_idx, unsigned tid);
+
+ double readArchFloatRegDouble(int reg_idx, unsigned tid);
+
+ uint64_t readArchFloatRegInt(int reg_idx, unsigned tid);
+
+ /** Architectural register accessors. Looks up in the commit
+ * rename table to obtain the true physical index of the
+ * architected register first, then accesses that physical
+ * register.
+ */
+ void setArchIntReg(int reg_idx, uint64_t val, unsigned tid);
+
+ void setArchFloatRegSingle(int reg_idx, float val, unsigned tid);
+
+ void setArchFloatRegDouble(int reg_idx, double val, unsigned tid);
+
+ void setArchFloatRegInt(int reg_idx, uint64_t val, unsigned tid);
- uint64_t readPC();
+ /** Reads the commit PC of a specific thread. */
+ uint64_t readPC(unsigned tid);
- void setNextPC(uint64_t val);
+ /** Sets the commit PC of a specific thread. */
+ void setPC(Addr new_PC, unsigned tid);
- void setPC(Addr new_PC);
+ /** 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.
*/
- void addInst(DynInstPtr &inst);
+ ListIt addInst(DynInstPtr &inst);
/** Function to tell the CPU that an instruction has completed. */
- void instDone();
-
- /** Remove all instructions in back of the given instruction, but leave
- * that instruction in the list. This is useful in a squash, when there
- * are instructions in this list that don't exist in structures such as
- * the ROB. The instruction doesn't have to be the last instruction in
- * the list, but will be once this function completes.
- * @todo: Remove only up until that inst? Squashed inst is most likely
- * valid.
- */
- void removeBackInst(DynInstPtr &inst);
-
- /** Remove an instruction from the front of the list. It is expected
- * that there are no instructions in front of it (that is, none are older
- * than the instruction being removed). Used when retiring instructions.
- * @todo: Remove the argument to this function, and just have it remove
- * last instruction once it's verified that commit has the same ordering
- * as the instruction list.
+ void instDone(unsigned tid);
+
+ /** Add Instructions to the CPU Remove List*/
+ void addToRemoveList(DynInstPtr &inst);
+
+ /** Remove an instruction from the front end of the list. There's
+ * no restriction on location of the instruction.
*/
void removeFrontInst(DynInstPtr &inst);
/** Remove all instructions that are not currently in the ROB. */
- void removeInstsNotInROB();
+ void removeInstsNotInROB(unsigned tid);
/** Remove all instructions younger than the given sequence number. */
- void removeInstsUntil(const InstSeqNum &seq_num);
+ void removeInstsUntil(const InstSeqNum &seq_num,unsigned tid);
- /** Remove all instructions from the list. */
- void removeAllInsts();
+ /** Removes the instruction pointed to by the iterator. */
+ inline void squashInstIt(const ListIt &instIt, const unsigned &tid);
- void dumpInsts();
+ /** Cleans up all instructions on the remove list. */
+ void cleanUpRemovedInsts();
- /** Basically a wrapper function so that instructions executed at
- * commit can tell the instruction queue that they have completed.
- * Eventually this hack should be removed.
- */
- void wakeDependents(DynInstPtr &inst);
+ /** Debug function to print all instructions on the list. */
+ void dumpInsts();
public:
/** List of all the instructions in flight. */
- list<DynInstPtr> instList;
+ std::list<DynInstPtr> instList;
+
+ /** List of all the instructions that will be removed at the end of this
+ * cycle.
+ */
+ std::queue<ListIt> removeList;
+
+#ifdef DEBUG
+ /** Debug structure to keep track of the sequence numbers still in
+ * flight.
+ */
+ std::set<InstSeqNum> snList;
+#endif
+
+ /** Records if instructions need to be removed this cycle due to
+ * being retired or squashed.
+ */
+ bool removeInstsThisCycle;
- //not sure these should be private.
protected:
/** The fetch stage. */
typename CPUPolicy::Fetch fetch;
- /** The fetch stage's status. */
- typename CPUPolicy::Fetch::Status fetchStatus;
-
/** The decode stage. */
typename CPUPolicy::Decode decode;
- /** The decode stage's status. */
- typename CPUPolicy::Decode::Status decodeStatus;
-
/** The dispatch stage. */
typename CPUPolicy::Rename rename;
- /** The dispatch stage's status. */
- typename CPUPolicy::Rename::Status renameStatus;
-
/** The issue/execute/writeback stages. */
typename CPUPolicy::IEW iew;
- /** The issue/execute/writeback stage's status. */
- typename CPUPolicy::IEW::Status iewStatus;
-
/** The commit stage. */
typename CPUPolicy::Commit commit;
- /** The fetch stage's status. */
- typename CPUPolicy::Commit::Status commitStatus;
-
- //Might want to just pass these objects in to the constructors of the
- //appropriate stage. regFile is in iew, freeList in dispatch, renameMap
- //in dispatch, and the rob in commit.
/** The register file. */
typename CPUPolicy::RegFile regFile;
@@ -284,12 +443,33 @@ class FullO3CPU : public BaseFullCPU
typename CPUPolicy::FreeList freeList;
/** The rename map. */
- typename CPUPolicy::RenameMap renameMap;
+ typename CPUPolicy::RenameMap renameMap[Impl::MaxThreads];
+
+ /** The commit rename map. */
+ typename CPUPolicy::RenameMap commitRenameMap[Impl::MaxThreads];
/** The re-order buffer. */
typename CPUPolicy::ROB rob;
+ /** Active Threads List */
+ std::list<unsigned> activeThreads;
+
+ /** Integer Register Scoreboard */
+ Scoreboard scoreboard;
+
public:
+ /** Enum to give each stage a specific index, so when calling
+ * activateStage() or deactivateStage(), they can specify which stage
+ * is being activated/deactivated.
+ */
+ enum StageIdx {
+ FetchIdx,
+ DecodeIdx,
+ RenameIdx,
+ IEWIdx,
+ CommitIdx,
+ NumStages };
+
/** Typedefs from the Impl to get the structs that each of the
* time buffers should use.
*/
@@ -318,46 +498,112 @@ class FullO3CPU : public BaseFullCPU
/** The IEW stage's instruction queue. */
TimeBuffer<IEWStruct> iewQueue;
+ 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:
- /** The temporary exec context to support older accessors. */
- CPUExecContext *cpuXC;
+ /** Records that there was time buffer activity this cycle. */
+ void activityThisCycle() { activityRec.activity(); }
- /** Temporary function to get pointer to exec context. */
- ExecContext *xcBase()
- {
- return thread[0]->getProxy();
- }
+ /** Changes a stage's status to active within the activity recorder. */
+ void activateStage(const StageIdx idx)
+ { activityRec.activateStage(idx); }
+
+ /** Changes a stage's status to inactive within the activity recorder. */
+ void deactivateStage(const StageIdx idx)
+ { activityRec.deactivateStage(idx); }
- CPUExecContext *cpuXCBase()
+ /** Wakes the CPU, rescheduling the CPU if it's not already active. */
+ void wakeCPU();
+
+ /** Gets a free thread id. Use if thread ids change across system. */
+ int getFreeTid();
+
+ public:
+ /** Returns a pointer to a thread context. */
+ ThreadContext *tcBase(unsigned tid)
{
- return thread[0];
+ return thread[tid]->getTC();
}
+ /** The global sequence number counter. */
InstSeqNum globalSeqNum;
+ /** Pointer to the checker, which can dynamically verify
+ * instruction results at run time. This can be set to NULL if it
+ * is not being used.
+ */
+ Checker<DynInstPtr> *checker;
+
#if FULL_SYSTEM
+ /** Pointer to the system. */
System *system;
- MemoryController *memCtrl;
+ /** Pointer to physical memory. */
PhysicalMemory *physmem;
+#endif
- AlphaITB *itb;
- AlphaDTB *dtb;
+ /** Pointer to memory. */
+ MemObject *mem;
-// SWContext *swCtx;
-#endif
- std::vector<CPUExecContext *> thread;
+ /** Pointer to the sampler */
+ Sampler *sampler;
- FunctionalMemory *mem;
+ /** 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;
- Counter numInsts;
-
- Counter funcExeInst;
+ /** 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;
+
+ /** The cycle that the CPU was last activated by a new thread*/
+ Tick lastActivatedCycle;
+
+ /** Number of Threads CPU can process */
+ unsigned numThreads;
+
+ /** Mapping for system thread id to cpu id */
+ std::map<unsigned,unsigned> threadMap;
+
+ /** Available thread ids in the cpu*/
+ std::vector<unsigned> tids;
+
+ /** Stat for total number of times the CPU is descheduled. */
+ Stats::Scalar<> timesIdled;
+ /** Stat for total number of cycles the CPU spends descheduled. */
+ Stats::Scalar<> idleCycles;
+ /** Stat for the number of committed instructions per thread. */
+ Stats::Vector<> committedInsts;
+ /** Stat for the total number of committed instructions. */
+ Stats::Scalar<> totalCommittedInsts;
+ /** Stat for the CPI per thread. */
+ Stats::Formula cpi;
+ /** Stat for the total CPI. */
+ Stats::Formula totalCpi;
+ /** Stat for the IPC per thread. */
+ Stats::Formula ipc;
+ /** Stat for the total IPC. */
+ Stats::Formula totalIpc;
};
-#endif
+#endif // __CPU_O3_CPU_HH__
diff --git a/src/cpu/o3/cpu_policy.hh b/src/cpu/o3/cpu_policy.hh
index 41f06f81b..32a0adcf1 100644
--- a/src/cpu/o3/cpu_policy.hh
+++ b/src/cpu/o3/cpu_policy.hh
@@ -24,15 +24,18 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_CPU_POLICY_HH__
-#define __CPU_O3_CPU_CPU_POLICY_HH__
+#ifndef __CPU_O3_CPU_POLICY_HH__
+#define __CPU_O3_CPU_POLICY_HH__
#include "cpu/o3/bpred_unit.hh"
#include "cpu/o3/free_list.hh"
#include "cpu/o3/inst_queue.hh"
-#include "cpu/o3/ldstq.hh"
+#include "cpu/o3/lsq.hh"
+#include "cpu/o3/lsq_unit.hh"
#include "cpu/o3/mem_dep_unit.hh"
#include "cpu/o3/regfile.hh"
#include "cpu/o3/rename_map.hh"
@@ -47,42 +50,70 @@
#include "cpu/o3/comm.hh"
+/**
+ * Struct that defines the key classes to be used by the CPU. All
+ * classes use the typedefs defined here to determine what are the
+ * classes of the other stages and communication buffers. In order to
+ * change a structure such as the IQ, simply change the typedef here
+ * to use the desired class instead, and recompile. In order to
+ * create a different CPU to be used simultaneously with this one, see
+ * the alpha_impl.hh file for instructions.
+ */
template<class Impl>
struct SimpleCPUPolicy
{
- typedef TwobitBPredUnit<Impl> BPredUnit;
+ /** Typedef for the branch prediction unit (which includes the BP,
+ * RAS, and BTB).
+ */
+ typedef BPredUnit<Impl> BPredUnit;
+ /** Typedef for the register file. Most classes assume a unified
+ * physical register file.
+ */
typedef PhysRegFile<Impl> RegFile;
+ /** Typedef for the freelist of registers. */
typedef SimpleFreeList FreeList;
+ /** Typedef for the rename map. */
typedef SimpleRenameMap RenameMap;
+ /** Typedef for the 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 LDSTQ<Impl> LDSTQ;
+ /** Typedef for the LSQ. */
+ typedef LSQ<Impl> LSQ;
+ /** Typedef for the thread-specific LSQ units. */
+ typedef LSQUnit<Impl> LSQUnit;
- typedef SimpleFetch<Impl> Fetch;
- typedef SimpleDecode<Impl> Decode;
- typedef SimpleRename<Impl> Rename;
- typedef SimpleIEW<Impl> IEW;
- typedef SimpleCommit<Impl> Commit;
+ /** Typedef for fetch. */
+ typedef DefaultFetch<Impl> Fetch;
+ /** Typedef for decode. */
+ typedef DefaultDecode<Impl> Decode;
+ /** Typedef for rename. */
+ typedef DefaultRename<Impl> Rename;
+ /** Typedef for Issue/Execute/Writeback. */
+ typedef DefaultIEW<Impl> IEW;
+ /** Typedef for commit. */
+ typedef DefaultCommit<Impl> Commit;
/** The struct for communication between fetch and decode. */
- typedef SimpleFetchSimpleDecode<Impl> FetchStruct;
+ typedef DefaultFetchDefaultDecode<Impl> FetchStruct;
/** The struct for communication between decode and rename. */
- typedef SimpleDecodeSimpleRename<Impl> DecodeStruct;
+ typedef DefaultDecodeDefaultRename<Impl> DecodeStruct;
/** The struct for communication between rename and IEW. */
- typedef SimpleRenameSimpleIEW<Impl> RenameStruct;
+ typedef DefaultRenameDefaultIEW<Impl> RenameStruct;
/** The struct for communication between IEW and commit. */
- typedef SimpleIEWSimpleCommit<Impl> IEWStruct;
+ typedef DefaultIEWDefaultCommit<Impl> IEWStruct;
/** The struct for communication within the IEW stage. */
typedef IssueStruct<Impl> IssueStruct;
/** The struct for all backwards communication. */
- typedef TimeBufStruct TimeStruct;
+ typedef TimeBufStruct<Impl> TimeStruct;
};
-#endif //__CPU_O3_CPU_CPU_POLICY_HH__
+#endif //__CPU_O3_CPU_POLICY_HH__
diff --git a/src/cpu/o3/decode.cc b/src/cpu/o3/decode.cc
index 290648318..896e38331 100644
--- a/src/cpu/o3/decode.cc
+++ b/src/cpu/o3/decode.cc
@@ -24,10 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/decode_impl.hh"
-template class SimpleDecode<AlphaSimpleImpl>;
+template class DefaultDecode<O3CPUImpl>;
diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh
index 5b9a0f822..1edf3335d 100644
--- a/src/cpu/o3/decode.hh
+++ b/src/cpu/o3/decode.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,22 +24,31 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_SIMPLE_DECODE_HH__
-#define __CPU_O3_CPU_SIMPLE_DECODE_HH__
+#ifndef __CPU_O3_DECODE_HH__
+#define __CPU_O3_DECODE_HH__
#include <queue>
#include "base/statistics.hh"
#include "base/timebuf.hh"
+/**
+ * DefaultDecode class handles both single threaded and SMT
+ * decode. Its width is specified by the parameters; each cycles it
+ * tries to decode that many instructions. Because instructions are
+ * actually decoded when the StaticInst is created, this stage does
+ * not do much other than check any PC-relative branches.
+ */
template<class Impl>
-class SimpleDecode
+class DefaultDecode
{
private:
// Typedefs from the Impl.
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
typedef typename Impl::Params Params;
typedef typename Impl::CPUPol CPUPol;
@@ -50,54 +59,137 @@ class SimpleDecode
typedef typename CPUPol::TimeStruct TimeStruct;
public:
- // The only time decode will become blocked is if dispatch becomes
- // blocked, which means IQ or ROB is probably full.
- enum Status {
+ /** Overall decode stage status. Used to determine if the CPU can
+ * deschedule itself due to a lack of activity.
+ */
+ enum DecodeStatus {
+ Active,
+ Inactive
+ };
+
+ /** Individual thread status. */
+ enum ThreadStatus {
Running,
Idle,
+ StartSquash,
Squashing,
Blocked,
Unblocking
};
private:
- // May eventually need statuses on a per thread basis.
- Status _status;
+ /** Decode status. */
+ DecodeStatus _status;
+
+ /** Per-thread status. */
+ ThreadStatus decodeStatus[Impl::MaxThreads];
public:
- SimpleDecode(Params &params);
+ /** DefaultDecode constructor. */
+ DefaultDecode(Params *params);
+
+ /** Returns the name of decode. */
+ std::string name() const;
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu_ptr);
+ /** Sets CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+ /** Sets the main backwards communication time buffer pointer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+ /** Sets pointer to time buffer used to communicate to the next stage. */
void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr);
+ /** Sets pointer to time buffer coming from fetch. */
void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr);
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Switches out the decode stage. */
+ void switchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Ticks decode, processing all input signals and decoding as many
+ * instructions as possible.
+ */
void tick();
- void decode();
+ /** Determines what to do based on decode's current status.
+ * @param status_change decode() sets this variable if there was a status
+ * change (ie switching from from blocking to unblocking).
+ * @param tid Thread id to decode instructions from.
+ */
+ void decode(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.
+ */
+ void decodeInsts(unsigned tid);
private:
+ /** Inserts a thread's instructions into the skid buffer, to be decoded
+ * once decode unblocks.
+ */
+ void skidInsert(unsigned tid);
+
+ /** Returns if all of the skid buffers are empty. */
+ bool skidsEmpty();
+
+ /** Updates overall decode status based on all of the threads' statuses. */
+ 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. */
+ void readStallSignals(unsigned tid);
+
+ /** Checks all input signals and updates decode's status appropriately. */
+ bool checkSignalsAndUpdate(unsigned tid);
+
+ /** Checks all stall signals, and returns if any are true. */
+ bool checkStall(unsigned tid) const;
+
+ /** Returns if there any instructions from fetch on this cycle. */
inline bool fetchInstsValid();
- void block();
+ /** Switches decode to blocking, and signals back that decode has
+ * become blocked.
+ * @return Returns true if there is a status change.
+ */
+ bool block(unsigned tid);
- inline void unblock();
+ /** Switches decode to unblocking if the skid buffer is empty, and
+ * signals back that decode has unblocked.
+ * @return Returns true if there is a status change.
+ */
+ bool unblock(unsigned tid);
- void squash(DynInstPtr &inst);
+ /** Squashes if there is a PC-relative branch that was predicted
+ * incorrectly. Sends squash information back to fetch.
+ */
+ void squash(DynInstPtr &inst, unsigned tid);
public:
- // Might want to make squash a friend function.
- void squash();
+ /** Squashes due to commit signalling a squash. Changes status to
+ * squashing and clears block/unblock signals as needed.
+ */
+ unsigned squash(unsigned tid);
private:
// Interfaces to objects outside of decode.
/** CPU interface. */
- FullCPU *cpu;
+ O3CPU *cpu;
/** Time buffer interface. */
TimeBuffer<TimeStruct> *timeBuffer;
@@ -127,10 +219,27 @@ class SimpleDecode
/** Wire to get fetch's output from fetch queue. */
typename TimeBuffer<FetchStruct>::wire fromFetch;
+ /** Queue of all instructions coming from fetch this cycle. */
+ std::queue<DynInstPtr> insts[Impl::MaxThreads];
+
/** Skid buffer between fetch and decode. */
- std::queue<FetchStruct> skidBuffer;
+ std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads];
+
+ /** Variable that tracks if decode has written to the time buffer this
+ * cycle. Used to tell CPU if there is activity this cycle.
+ */
+ bool wroteToTimeBuffer;
+
+ /** Source of possible stalls. */
+ struct Stalls {
+ bool rename;
+ bool iew;
+ bool commit;
+ };
+
+ /** Tracks which stages are telling decode to stall. */
+ Stalls stalls[Impl::MaxThreads];
- //Consider making these unsigned to avoid any confusion.
/** Rename to decode delay, in ticks. */
unsigned renameToDecodeDelay;
@@ -146,20 +255,43 @@ class SimpleDecode
/** The width of decode, in instructions. */
unsigned decodeWidth;
- /** The instruction that decode is currently on. It needs to have
- * persistent state so that when a stall occurs in the middle of a
- * group of instructions, it can restart at the proper instruction.
- */
- unsigned numInst;
+ /** Index of instructions being sent to rename. */
+ unsigned toRenameIndex;
+
+ /** number of Active Threads*/
+ unsigned numThreads;
+ /** List of active thread ids */
+ std::list<unsigned> *activeThreads;
+
+ /** Number of branches in flight. */
+ unsigned branchCount[Impl::MaxThreads];
+
+ /** Maximum size of the skid buffer. */
+ unsigned skidBufferMax;
+
+ /** Stat for total number of idle cycles. */
Stats::Scalar<> decodeIdleCycles;
+ /** Stat for total number of blocked cycles. */
Stats::Scalar<> decodeBlockedCycles;
+ /** Stat for total number of normal running cycles. */
+ Stats::Scalar<> decodeRunCycles;
+ /** Stat for total number of unblocking cycles. */
Stats::Scalar<> decodeUnblockCycles;
+ /** Stat for total number of squashing cycles. */
Stats::Scalar<> decodeSquashCycles;
+ /** Stat for number of times a branch is resolved at decode. */
+ Stats::Scalar<> decodeBranchResolved;
+ /** Stat for number of times a branch mispredict is detected. */
Stats::Scalar<> decodeBranchMispred;
+ /** Stat for number of times decode detected a non-control instruction
+ * incorrectly predicted as a branch.
+ */
Stats::Scalar<> decodeControlMispred;
+ /** Stat for total number of decoded instructions. */
Stats::Scalar<> decodeDecodedInsts;
+ /** Stat for total number of squashed instructions. */
Stats::Scalar<> decodeSquashedInsts;
};
-#endif // __CPU_O3_CPU_SIMPLE_DECODE_HH__
+#endif // __CPU_O3_DECODE_HH__
diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh
index 463f0ddac..16be01784 100644
--- a/src/cpu/o3/decode_impl.hh
+++ b/src/cpu/o3/decode_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,75 +24,105 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/decode.hh"
+using namespace std;
+
template<class Impl>
-SimpleDecode<Impl>::SimpleDecode(Params &params)
- : renameToDecodeDelay(params.renameToDecodeDelay),
- iewToDecodeDelay(params.iewToDecodeDelay),
- commitToDecodeDelay(params.commitToDecodeDelay),
- fetchToDecodeDelay(params.fetchToDecodeDelay),
- decodeWidth(params.decodeWidth),
- numInst(0)
+DefaultDecode<Impl>::DefaultDecode(Params *params)
+ : renameToDecodeDelay(params->renameToDecodeDelay),
+ iewToDecodeDelay(params->iewToDecodeDelay),
+ commitToDecodeDelay(params->commitToDecodeDelay),
+ fetchToDecodeDelay(params->fetchToDecodeDelay),
+ decodeWidth(params->decodeWidth),
+ numThreads(params->numberOfThreads)
{
- DPRINTF(Decode, "Decode: decodeWidth=%i.\n", decodeWidth);
- _status = Idle;
+ _status = Inactive;
+
+ // Setup status, make sure stall signals are clear.
+ for (int i = 0; i < numThreads; ++i) {
+ decodeStatus[i] = Idle;
+
+ stalls[i].rename = false;
+ stalls[i].iew = false;
+ stalls[i].commit = false;
+ }
+
+ // @todo: Make into a parameter
+ skidBufferMax = (fetchToDecodeDelay * params->fetchWidth) + decodeWidth;
+}
+
+template <class Impl>
+std::string
+DefaultDecode<Impl>::name() const
+{
+ return cpu->name() + ".decode";
}
template <class Impl>
void
-SimpleDecode<Impl>::regStats()
+DefaultDecode<Impl>::regStats()
{
decodeIdleCycles
- .name(name() + ".decodeIdleCycles")
+ .name(name() + ".DECODE:IdleCycles")
.desc("Number of cycles decode is idle")
.prereq(decodeIdleCycles);
decodeBlockedCycles
- .name(name() + ".decodeBlockedCycles")
+ .name(name() + ".DECODE:BlockedCycles")
.desc("Number of cycles decode is blocked")
.prereq(decodeBlockedCycles);
+ decodeRunCycles
+ .name(name() + ".DECODE:RunCycles")
+ .desc("Number of cycles decode is running")
+ .prereq(decodeRunCycles);
decodeUnblockCycles
- .name(name() + ".decodeUnblockCycles")
+ .name(name() + ".DECODE:UnblockCycles")
.desc("Number of cycles decode is unblocking")
.prereq(decodeUnblockCycles);
decodeSquashCycles
- .name(name() + ".decodeSquashCycles")
+ .name(name() + ".DECODE:SquashCycles")
.desc("Number of cycles decode is squashing")
.prereq(decodeSquashCycles);
+ decodeBranchResolved
+ .name(name() + ".DECODE:BranchResolved")
+ .desc("Number of times decode resolved a branch")
+ .prereq(decodeBranchResolved);
decodeBranchMispred
- .name(name() + ".decodeBranchMispred")
+ .name(name() + ".DECODE:BranchMispred")
.desc("Number of times decode detected a branch misprediction")
.prereq(decodeBranchMispred);
decodeControlMispred
- .name(name() + ".decodeControlMispred")
+ .name(name() + ".DECODE:ControlMispred")
.desc("Number of times decode detected an instruction incorrectly"
" predicted as a control")
.prereq(decodeControlMispred);
decodeDecodedInsts
- .name(name() + ".decodeDecodedInsts")
+ .name(name() + ".DECODE:DecodedInsts")
.desc("Number of instructions handled by decode")
.prereq(decodeDecodedInsts);
decodeSquashedInsts
- .name(name() + ".decodeSquashedInsts")
+ .name(name() + ".DECODE:SquashedInsts")
.desc("Number of squashed instructions handled by decode")
.prereq(decodeSquashedInsts);
}
template<class Impl>
void
-SimpleDecode<Impl>::setCPU(FullCPU *cpu_ptr)
+DefaultDecode<Impl>::setCPU(O3CPU *cpu_ptr)
{
- DPRINTF(Decode, "Decode: Setting CPU pointer.\n");
+ DPRINTF(Decode, "Setting CPU pointer.\n");
cpu = cpu_ptr;
}
template<class Impl>
void
-SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+DefaultDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
- DPRINTF(Decode, "Decode: Setting time buffer pointer.\n");
+ DPRINTF(Decode, "Setting time buffer pointer.\n");
timeBuffer = tb_ptr;
// Setup wire to write information back to fetch.
@@ -106,9 +136,9 @@ SimpleDecode<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
template<class Impl>
void
-SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
+DefaultDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
{
- DPRINTF(Decode, "Decode: Setting decode queue pointer.\n");
+ DPRINTF(Decode, "Setting decode queue pointer.\n");
decodeQueue = dq_ptr;
// Setup wire to write information to proper place in decode queue.
@@ -117,9 +147,9 @@ SimpleDecode<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
template<class Impl>
void
-SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
+DefaultDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
{
- DPRINTF(Decode, "Decode: Setting fetch queue pointer.\n");
+ DPRINTF(Decode, "Setting fetch queue pointer.\n");
fetchQueue = fq_ptr;
// Setup wire to read information from fetch queue.
@@ -127,250 +157,541 @@ SimpleDecode<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
}
template<class Impl>
+void
+DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(Decode, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+template <class Impl>
+void
+DefaultDecode<Impl>::switchOut()
+{
+ // Decode can immediately switch out.
+ cpu->signalSwitched();
+}
+
+template <class Impl>
+void
+DefaultDecode<Impl>::takeOverFrom()
+{
+ _status = Inactive;
+
+ // Be sure to reset state and clear out any old instructions.
+ for (int i = 0; i < numThreads; ++i) {
+ decodeStatus[i] = Idle;
+
+ stalls[i].rename = false;
+ stalls[i].iew = false;
+ stalls[i].commit = false;
+ while (!insts[i].empty())
+ insts[i].pop();
+ while (!skidBuffer[i].empty())
+ skidBuffer[i].pop();
+ branchCount[i] = 0;
+ }
+ wroteToTimeBuffer = false;
+}
+
+template<class Impl>
+bool
+DefaultDecode<Impl>::checkStall(unsigned tid) const
+{
+ bool ret_val = false;
+
+ if (stalls[tid].rename) {
+ DPRINTF(Decode,"[tid:%i]: Stall fom Rename stage detected.\n", tid);
+ ret_val = true;
+ } else if (stalls[tid].iew) {
+ DPRINTF(Decode,"[tid:%i]: Stall fom IEW stage detected.\n", tid);
+ ret_val = true;
+ } else if (stalls[tid].commit) {
+ DPRINTF(Decode,"[tid:%i]: Stall fom Commit stage detected.\n", tid);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+template<class Impl>
inline bool
-SimpleDecode<Impl>::fetchInstsValid()
+DefaultDecode<Impl>::fetchInstsValid()
{
return fromFetch->size > 0;
}
template<class Impl>
-void
-SimpleDecode<Impl>::block()
+bool
+DefaultDecode<Impl>::block(unsigned tid)
{
- DPRINTF(Decode, "Decode: Blocking.\n");
-
- // Set the status to Blocked.
- _status = Blocked;
+ DPRINTF(Decode, "[tid:%u]: Blocking.\n", tid);
// Add the current inputs to the skid buffer so they can be
// reprocessed when this stage unblocks.
- skidBuffer.push(*fromFetch);
+ skidInsert(tid);
+
+ // If the decode status is blocked or unblocking then decode has not yet
+ // signalled fetch to unblock. In that case, there is no need to tell
+ // fetch to block.
+ if (decodeStatus[tid] != Blocked) {
+ // Set the status to Blocked.
+ decodeStatus[tid] = Blocked;
+
+ if (decodeStatus[tid] != Unblocking) {
+ toFetch->decodeBlock[tid] = true;
+ wroteToTimeBuffer = true;
+ }
- // Note that this stage only signals previous stages to stall when
- // it is the cause of the stall originates at this stage. Otherwise
- // the previous stages are expected to check all possible stall signals.
+ return true;
+ }
+
+ return false;
}
template<class Impl>
-inline void
-SimpleDecode<Impl>::unblock()
+bool
+DefaultDecode<Impl>::unblock(unsigned tid)
{
- DPRINTF(Decode, "Decode: Unblocking, going to remove "
- "instructions from skid buffer.\n");
- // Remove the now processed instructions from the skid buffer.
- skidBuffer.pop();
-
- // If there's still information in the skid buffer, then
- // continue to tell previous stages to stall. They will be
- // able to restart once the skid buffer is empty.
- if (!skidBuffer.empty()) {
- toFetch->decodeInfo.stall = true;
- } else {
- DPRINTF(Decode, "Decode: Finished unblocking.\n");
- _status = Running;
+ // Decode is done unblocking only if the skid buffer is empty.
+ if (skidBuffer[tid].empty()) {
+ DPRINTF(Decode, "[tid:%u]: Done unblocking.\n", tid);
+ toFetch->decodeUnblock[tid] = true;
+ wroteToTimeBuffer = true;
+
+ decodeStatus[tid] = Running;
+ return true;
}
+
+ DPRINTF(Decode, "[tid:%u]: Currently unblocking.\n", tid);
+
+ return false;
}
-// This squash is specifically for when Decode detects a PC-relative branch
-// was predicted incorrectly.
template<class Impl>
void
-SimpleDecode<Impl>::squash(DynInstPtr &inst)
+DefaultDecode<Impl>::squash(DynInstPtr &inst, unsigned tid)
{
- DPRINTF(Decode, "Decode: Squashing due to incorrect branch prediction "
- "detected at decode.\n");
- Addr new_PC = inst->readNextPC();
-
- toFetch->decodeInfo.branchMispredict = true;
- toFetch->decodeInfo.doneSeqNum = inst->seqNum;
- toFetch->decodeInfo.predIncorrect = true;
- toFetch->decodeInfo.squash = true;
- toFetch->decodeInfo.nextPC = new_PC;
- toFetch->decodeInfo.branchTaken = true;
+ DPRINTF(Decode, "[tid:%i]: Squashing due to incorrect branch prediction "
+ "detected at decode.\n", tid);
+
+ // Send back mispredict information.
+ toFetch->decodeInfo[tid].branchMispredict = true;
+ toFetch->decodeInfo[tid].doneSeqNum = inst->seqNum;
+ toFetch->decodeInfo[tid].predIncorrect = true;
+ toFetch->decodeInfo[tid].squash = true;
+ toFetch->decodeInfo[tid].nextPC = inst->branchTarget();
+ toFetch->decodeInfo[tid].branchTaken =
+ inst->readNextPC() != (inst->readPC() + sizeof(TheISA::MachInst));
+
+ // Might have to tell fetch to unblock.
+ if (decodeStatus[tid] == Blocked ||
+ decodeStatus[tid] == Unblocking) {
+ toFetch->decodeUnblock[tid] = 1;
+ }
// Set status to squashing.
- _status = Squashing;
+ decodeStatus[tid] = Squashing;
+
+ for (int i=0; i<fromFetch->size; i++) {
+ if (fromFetch->insts[i]->threadNumber == tid &&
+ fromFetch->insts[i]->seqNum > inst->seqNum) {
+ fromFetch->insts[i]->setSquashed();
+ }
+ }
+
+ // Clear the instruction list and skid buffer in case they have any
+ // insts in them.
+ while (!insts[tid].empty()) {
+ insts[tid].pop();
+ }
- // Clear the skid buffer in case it has any data in it.
- while (!skidBuffer.empty()) {
- skidBuffer.pop();
+ while (!skidBuffer[tid].empty()) {
+ skidBuffer[tid].pop();
}
// Squash instructions up until this one
- // Slightly unrealistic!
- cpu->removeInstsUntil(inst->seqNum);
+ cpu->removeInstsUntil(inst->seqNum, tid);
}
template<class Impl>
-void
-SimpleDecode<Impl>::squash()
+unsigned
+DefaultDecode<Impl>::squash(unsigned tid)
{
- DPRINTF(Decode, "Decode: Squashing.\n");
+ DPRINTF(Decode, "[tid:%i]: Squashing.\n",tid);
+
+ if (decodeStatus[tid] == Blocked ||
+ decodeStatus[tid] == Unblocking) {
+#if !FULL_SYSTEM
+ // In syscall emulation, we can have both a block and a squash due
+ // to a syscall in the same cycle. This would cause both signals to
+ // be high. This shouldn't happen in full system.
+ // @todo: Determine if this still happens.
+ if (toFetch->decodeBlock[tid]) {
+ toFetch->decodeBlock[tid] = 0;
+ } else {
+ toFetch->decodeUnblock[tid] = 1;
+ }
+#else
+ toFetch->decodeUnblock[tid] = 1;
+#endif
+ }
+
// Set status to squashing.
- _status = Squashing;
+ decodeStatus[tid] = Squashing;
- // Maybe advance the time buffer? Not sure what to do in the normal
- // case.
+ // Go through incoming instructions from fetch and squash them.
+ unsigned squash_count = 0;
- // Clear the skid buffer in case it has any data in it.
- while (!skidBuffer.empty())
- {
- skidBuffer.pop();
+ for (int i=0; i<fromFetch->size; i++) {
+ if (fromFetch->insts[i]->threadNumber == tid) {
+ fromFetch->insts[i]->setSquashed();
+ squash_count++;
+ }
}
+
+ // Clear the instruction list and skid buffer in case they have any
+ // insts in them.
+ while (!insts[tid].empty()) {
+ insts[tid].pop();
+ }
+
+ while (!skidBuffer[tid].empty()) {
+ skidBuffer[tid].pop();
+ }
+
+ return squash_count;
}
template<class Impl>
void
-SimpleDecode<Impl>::tick()
+DefaultDecode<Impl>::skidInsert(unsigned tid)
{
- // Decode should try to execute as many instructions as its bandwidth
- // will allow, as long as it is not currently blocked.
- if (_status != Blocked && _status != Squashing) {
- DPRINTF(Decode, "Decode: Not blocked, so attempting to run "
- "stage.\n");
- // Make sure that the skid buffer has something in it if the
- // status is unblocking.
- assert(_status == Unblocking ? !skidBuffer.empty() : 1);
+ DynInstPtr inst = NULL;
- decode();
+ while (!insts[tid].empty()) {
+ inst = insts[tid].front();
- // If the status was unblocking, then instructions from the skid
- // buffer were used. Remove those instructions and handle
- // the rest of unblocking.
- if (_status == Unblocking) {
- ++decodeUnblockCycles;
+ insts[tid].pop();
- if (fetchInstsValid()) {
- // Add the current inputs to the skid buffer so they can be
- // reprocessed when this stage unblocks.
- skidBuffer.push(*fromFetch);
- }
+ assert(tid == inst->threadNumber);
- unblock();
- }
- } else if (_status == Blocked) {
- ++decodeBlockedCycles;
+ DPRINTF(Decode,"Inserting [sn:%lli] PC:%#x into decode skidBuffer %i\n",
+ inst->seqNum, inst->readPC(), inst->threadNumber);
- if (fetchInstsValid()) {
- block();
- }
+ skidBuffer[tid].push(inst);
+ }
- if (!fromRename->renameInfo.stall &&
- !fromIEW->iewInfo.stall &&
- !fromCommit->commitInfo.stall) {
- DPRINTF(Decode, "Decode: Stall signals cleared, going to "
- "unblock.\n");
- _status = Unblocking;
+ // @todo: Eventually need to enforce this by not letting a thread
+ // fetch past its skidbuffer
+ assert(skidBuffer[tid].size() <= skidBufferMax);
+}
- // Continue to tell previous stage to block until this
- // stage is done unblocking.
- toFetch->decodeInfo.stall = true;
- } else {
- DPRINTF(Decode, "Decode: Still blocked.\n");
- toFetch->decodeInfo.stall = true;
+template<class Impl>
+bool
+DefaultDecode<Impl>::skidsEmpty()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ if (!skidBuffer[*threads++].empty())
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+void
+DefaultDecode<Impl>::updateStatus()
+{
+ bool any_unblocking = false;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (decodeStatus[tid] == Unblocking) {
+ any_unblocking = true;
+ break;
}
+ }
+
+ // Decode will have activity if it's unblocking.
+ if (any_unblocking) {
+ if (_status == Inactive) {
+ _status = Active;
+
+ DPRINTF(Activity, "Activating stage.\n");
- if (fromCommit->commitInfo.squash ||
- fromCommit->commitInfo.robSquashing) {
- squash();
+ cpu->activateStage(O3CPU::DecodeIdx);
}
- } else if (_status == Squashing) {
- if (!fromCommit->commitInfo.squash &&
- !fromCommit->commitInfo.robSquashing) {
- _status = Running;
- } else if (fromCommit->commitInfo.squash) {
- ++decodeSquashCycles;
-
- squash();
+ } else {
+ // If it's not unblocking, then decode will not have any internal
+ // activity. Switch it to inactive.
+ if (_status == Active) {
+ _status = Inactive;
+ DPRINTF(Activity, "Deactivating stage.\n");
+
+ cpu->deactivateStage(O3CPU::DecodeIdx);
}
}
}
+template <class Impl>
+void
+DefaultDecode<Impl>::sortInsts()
+{
+ int insts_from_fetch = fromFetch->size;
+#ifdef DEBUG
+ for (int i=0; i < numThreads; i++)
+ assert(insts[i].empty());
+#endif
+ for (int i = 0; i < insts_from_fetch; ++i) {
+ insts[fromFetch->insts[i]->threadNumber].push(fromFetch->insts[i]);
+ }
+}
+
template<class Impl>
void
-SimpleDecode<Impl>::decode()
+DefaultDecode<Impl>::readStallSignals(unsigned tid)
{
- // Check time buffer if being told to squash.
- if (fromCommit->commitInfo.squash) {
- squash();
- return;
+ if (fromRename->renameBlock[tid]) {
+ stalls[tid].rename = true;
}
- // Check time buffer if being told to stall.
- if (fromRename->renameInfo.stall ||
- fromIEW->iewInfo.stall ||
- fromCommit->commitInfo.stall) {
- block();
- return;
+ if (fromRename->renameUnblock[tid]) {
+ assert(stalls[tid].rename);
+ stalls[tid].rename = false;
+ }
+
+ if (fromIEW->iewBlock[tid]) {
+ stalls[tid].iew = true;
+ }
+
+ if (fromIEW->iewUnblock[tid]) {
+ assert(stalls[tid].iew);
+ stalls[tid].iew = false;
+ }
+
+ if (fromCommit->commitBlock[tid]) {
+ stalls[tid].commit = true;
+ }
+
+ if (fromCommit->commitUnblock[tid]) {
+ assert(stalls[tid].commit);
+ stalls[tid].commit = false;
+ }
+}
+
+template <class Impl>
+bool
+DefaultDecode<Impl>::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 squash signals from commit.
+ if (fromCommit->commitInfo[tid].squash) {
+
+ DPRINTF(Decode, "[tid:%u]: Squashing instructions due to squash "
+ "from commit.\n", tid);
+
+ squash(tid);
+
+ return true;
+ }
+
+ // Check ROB squash signals from commit.
+ if (fromCommit->commitInfo[tid].robSquashing) {
+ DPRINTF(Decode, "[tid:%u]: ROB is still squashing.\n", tid);
+
+ // Continue to squash.
+ decodeStatus[tid] = Squashing;
+
+ return true;
+ }
+
+ if (checkStall(tid)) {
+ return block(tid);
}
- // Check fetch queue to see if instructions are available.
- // If no available instructions, do nothing, unless this stage is
- // currently unblocking.
- if (!fetchInstsValid() && _status != Unblocking) {
- DPRINTF(Decode, "Decode: Nothing to do, breaking out early.\n");
+ if (decodeStatus[tid] == Blocked) {
+ DPRINTF(Decode, "[tid:%u]: Done blocking, switching to unblocking.\n",
+ tid);
+
+ decodeStatus[tid] = Unblocking;
+
+ unblock(tid);
+
+ return true;
+ }
+
+ if (decodeStatus[tid] == Squashing) {
+ // Switch status to running if decode isn't being told to block or
+ // squash this cycle.
+ DPRINTF(Decode, "[tid:%u]: Done squashing, switching to running.\n",
+ tid);
+
+ decodeStatus[tid] = Running;
+
+ return false;
+ }
+
+ // If we've reached this point, we have not gotten any signals that
+ // cause decode to change its status. Decode remains the same as before.
+ return false;
+}
+
+template<class Impl>
+void
+DefaultDecode<Impl>::tick()
+{
+ wroteToTimeBuffer = false;
+
+ bool status_change = false;
+
+ toRenameIndex = 0;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ sortInsts();
+
+ //Check stall and squash signals.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ DPRINTF(Decode,"Processing [tid:%i]\n",tid);
+ status_change = checkSignalsAndUpdate(tid) || status_change;
+
+ decode(status_change, tid);
+ }
+
+ if (status_change) {
+ updateStatus();
+ }
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+
+ cpu->activityThisCycle();
+ }
+}
+
+template<class Impl>
+void
+DefaultDecode<Impl>::decode(bool &status_change, unsigned tid)
+{
+ // If status is Running or idle,
+ // call decodeInsts()
+ // If status is Unblocking,
+ // buffer any instructions coming from fetch
+ // continue trying to empty skid buffer
+ // check if stall conditions have passed
+
+ if (decodeStatus[tid] == Blocked) {
+ ++decodeBlockedCycles;
+ } else if (decodeStatus[tid] == Squashing) {
+ ++decodeSquashCycles;
+ }
+
+ // Decode should try to decode as many instructions as its bandwidth
+ // will allow, as long as it is not currently blocked.
+ if (decodeStatus[tid] == Running ||
+ decodeStatus[tid] == Idle) {
+ DPRINTF(Decode, "[tid:%u] Not blocked, so attempting to run "
+ "stage.\n",tid);
+
+ decodeInsts(tid);
+ } else if (decodeStatus[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.
+ decodeInsts(tid);
+
+ if (fetchInstsValid()) {
+ // 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;
+ }
+}
+
+template <class Impl>
+void
+DefaultDecode<Impl>::decodeInsts(unsigned tid)
+{
+ // Instructions can come either from the skid buffer or the list of
+ // instructions coming from fetch, depending on decode's status.
+ int insts_available = decodeStatus[tid] == Unblocking ?
+ skidBuffer[tid].size() : insts[tid].size();
+
+ if (insts_available == 0) {
+ DPRINTF(Decode, "[tid:%u] Nothing to do, breaking out"
+ " early.\n",tid);
// Should I change the status to idle?
++decodeIdleCycles;
return;
+ } else if (decodeStatus[tid] == Unblocking) {
+ DPRINTF(Decode, "[tid:%u] Unblocking, removing insts from skid "
+ "buffer.\n",tid);
+ ++decodeUnblockCycles;
+ } else if (decodeStatus[tid] == Running) {
+ ++decodeRunCycles;
}
- // Might be better to use a base DynInst * instead?
DynInstPtr inst;
- unsigned to_rename_index = 0;
+ std::queue<DynInstPtr>
+ &insts_to_decode = decodeStatus[tid] == Unblocking ?
+ skidBuffer[tid] : insts[tid];
- int insts_available = _status == Unblocking ?
- skidBuffer.front().size - numInst :
- fromFetch->size;
+ DPRINTF(Decode, "[tid:%u]: Sending instruction to rename.\n",tid);
- // Debug block...
-#if 0
- if (insts_available) {
- DPRINTF(Decode, "Decode: Instructions available.\n");
- } else {
- if (_status == Unblocking && skidBuffer.empty()) {
- DPRINTF(Decode, "Decode: No instructions available, skid buffer "
- "empty.\n");
- } else if (_status != Unblocking &&
- !fromFetch->insts[0]) {
- DPRINTF(Decode, "Decode: No instructions available, fetch queue "
- "empty.\n");
- } else {
- panic("Decode: No instructions available, unexpected condition!"
- "\n");
- }
- }
-#endif
+ while (insts_available > 0 && toRenameIndex < decodeWidth) {
+ assert(!insts_to_decode.empty());
- while (insts_available > 0)
- {
- DPRINTF(Decode, "Decode: Sending instruction to rename.\n");
+ inst = insts_to_decode.front();
- inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
- fromFetch->insts[numInst];
+ insts_to_decode.pop();
- DPRINTF(Decode, "Decode: Processing instruction %i with PC %#x\n",
- inst->seqNum, inst->readPC());
+ DPRINTF(Decode, "[tid:%u]: Processing instruction [sn:%lli] with "
+ "PC %#x\n",
+ tid, inst->seqNum, inst->readPC());
if (inst->isSquashed()) {
- DPRINTF(Decode, "Decode: Instruction %i with PC %#x is "
+ DPRINTF(Decode, "[tid:%u]: Instruction %i with PC %#x is "
"squashed, skipping.\n",
- inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->readPC());
++decodeSquashedInsts;
- ++numInst;
--insts_available;
continue;
}
-
// Also check if instructions have no source registers. Mark
// them as ready to issue at any time. Not sure if this check
// should exist here or at a later stage; however it doesn't matter
// too much for function correctness.
- // Isn't this handled by the inst queue?
if (inst->numSrcRegs() == 0) {
inst->setCanIssue();
}
@@ -378,9 +699,12 @@ SimpleDecode<Impl>::decode()
// This current instruction is valid, so add it into the decode
// queue. The next instruction may not be valid, so check to
// see if branches were predicted correctly.
- toRename->insts[to_rename_index] = inst;
+ toRename->insts[toRenameIndex] = inst;
++(toRename->size);
+ ++toRenameIndex;
+ ++decodeDecodedInsts;
+ --insts_available;
// Ensure that if it was predicted as a branch, it really is a
// branch.
@@ -388,38 +712,40 @@ SimpleDecode<Impl>::decode()
panic("Instruction predicted as a branch!");
++decodeControlMispred;
+
// Might want to set some sort of boolean and just do
// a check at the end
- squash(inst);
+ squash(inst, inst->threadNumber);
+
break;
}
// Go ahead and compute any PC-relative branches.
-
if (inst->isDirectCtrl() && inst->isUncondCtrl()) {
+ ++decodeBranchResolved;
- inst->setNextPC(inst->branchTarget());
-
- if (inst->mispredicted()) {
+ if (inst->branchTarget() != inst->readPredTarg()) {
++decodeBranchMispred;
+
// Might want to set some sort of boolean and just do
// a check at the end
- squash(inst);
+ squash(inst, inst->threadNumber);
+ inst->setPredTarg(inst->branchTarget());
+
break;
}
}
+ }
- // Normally can check if a direct branch has the right target
- // addr (either the immediate, or the branch PC + 4) and redirect
- // fetch if it's incorrect.
-
- // Increment which instruction we're looking at.
- ++numInst;
- ++to_rename_index;
- ++decodeDecodedInsts;
-
- --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_decode.empty()) {
+ block(tid);
}
- numInst = 0;
+ // Record that decode has written to the time buffer for activity
+ // tracking.
+ if (toRenameIndex) {
+ wroteToTimeBuffer = true;
+ }
}
diff --git a/src/cpu/o3/dep_graph.hh b/src/cpu/o3/dep_graph.hh
new file mode 100644
index 000000000..c19fd0abf
--- /dev/null
+++ b/src/cpu/o3/dep_graph.hh
@@ -0,0 +1,272 @@
+/*
+ * 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_O3_DEP_GRAPH_HH__
+#define __CPU_O3_DEP_GRAPH_HH__
+
+#include "cpu/o3/comm.hh"
+
+/** Node in a linked list. */
+template <class DynInstPtr>
+class DependencyEntry
+{
+ public:
+ DependencyEntry()
+ : inst(NULL), next(NULL)
+ { }
+
+ DynInstPtr inst;
+ //Might want to include data about what arch. register the
+ //dependence is waiting on.
+ DependencyEntry<DynInstPtr> *next;
+};
+
+/** Array of linked list that maintains the dependencies between
+ * producing instructions and consuming instructions. Each linked
+ * list represents a single physical register, having the future
+ * producer of the register's value, and all consumers waiting on that
+ * value on the list. The head node of each linked list represents
+ * the producing instruction of that register. Instructions are put
+ * on the list upon reaching the IQ, and are removed from the list
+ * either when the producer completes, or the instruction is squashed.
+*/
+template <class DynInstPtr>
+class DependencyGraph
+{
+ public:
+ typedef DependencyEntry<DynInstPtr> DepEntry;
+
+ /** Default construction. Must call resize() prior to use. */
+ DependencyGraph()
+ : numEntries(0), memAllocCounter(0), nodesTraversed(0), nodesRemoved(0)
+ { }
+
+ ~DependencyGraph();
+
+ /** Resize the dependency graph to have num_entries registers. */
+ void resize(int num_entries);
+
+ /** Clears all of the linked lists. */
+ void reset();
+
+ /** Inserts an instruction to be dependent on the given index. */
+ void insert(PhysRegIndex idx, DynInstPtr &new_inst);
+
+ /** Sets the producing instruction of a given register. */
+ void setInst(PhysRegIndex idx, DynInstPtr &new_inst)
+ { dependGraph[idx].inst = new_inst; }
+
+ /** Clears the producing instruction. */
+ void clearInst(PhysRegIndex idx)
+ { dependGraph[idx].inst = NULL; }
+
+ /** Removes an instruction from a single linked list. */
+ void remove(PhysRegIndex idx, DynInstPtr &inst_to_remove);
+
+ /** Removes and returns the newest dependent of a specific register. */
+ DynInstPtr pop(PhysRegIndex idx);
+
+ /** Checks if there are any dependents on a specific register. */
+ bool empty(PhysRegIndex idx) { return !dependGraph[idx].next; }
+
+ /** Debugging function to dump out the dependency graph.
+ */
+ void dump();
+
+ private:
+ /** Array of linked lists. Each linked list is a list of all the
+ * instructions that depend upon a given register. The actual
+ * register's index is used to index into the graph; ie all
+ * instructions in flight that are dependent upon r34 will be
+ * in the linked list of dependGraph[34].
+ */
+ DepEntry *dependGraph;
+
+ /** Number of linked lists; identical to the number of registers. */
+ int numEntries;
+
+ // Debug variable, remove when done testing.
+ unsigned memAllocCounter;
+
+ public:
+ // Debug variable, remove when done testing.
+ uint64_t nodesTraversed;
+ // Debug variable, remove when done testing.
+ uint64_t nodesRemoved;
+};
+
+template <class DynInstPtr>
+DependencyGraph<DynInstPtr>::~DependencyGraph()
+{
+ delete [] dependGraph;
+}
+
+template <class DynInstPtr>
+void
+DependencyGraph<DynInstPtr>::resize(int num_entries)
+{
+ numEntries = num_entries;
+ dependGraph = new DepEntry[numEntries];
+}
+
+template <class DynInstPtr>
+void
+DependencyGraph<DynInstPtr>::reset()
+{
+ // Clear the dependency graph
+ DepEntry *curr;
+ DepEntry *prev;
+
+ for (int i = 0; i < numEntries; ++i) {
+ curr = dependGraph[i].next;
+
+ while (curr) {
+ memAllocCounter--;
+
+ prev = curr;
+ curr = prev->next;
+ prev->inst = NULL;
+
+ delete prev;
+ }
+
+ if (dependGraph[i].inst) {
+ dependGraph[i].inst = NULL;
+ }
+
+ dependGraph[i].next = NULL;
+ }
+}
+
+template <class DynInstPtr>
+void
+DependencyGraph<DynInstPtr>::insert(PhysRegIndex idx, DynInstPtr &new_inst)
+{
+ //Add this new, dependent instruction at the head of the dependency
+ //chain.
+
+ // First create the entry that will be added to the head of the
+ // dependency chain.
+ DepEntry *new_entry = new DepEntry;
+ new_entry->next = dependGraph[idx].next;
+ new_entry->inst = new_inst;
+
+ // Then actually add it to the chain.
+ dependGraph[idx].next = new_entry;
+
+ ++memAllocCounter;
+}
+
+
+template <class DynInstPtr>
+void
+DependencyGraph<DynInstPtr>::remove(PhysRegIndex idx,
+ DynInstPtr &inst_to_remove)
+{
+ DepEntry *prev = &dependGraph[idx];
+ DepEntry *curr = dependGraph[idx].next;
+
+ // Make sure curr isn't NULL. Because this instruction is being
+ // removed from a dependency list, it must have been placed there at
+ // an earlier time. The dependency chain should not be empty,
+ // unless the instruction dependent upon it is already ready.
+ if (curr == NULL) {
+ return;
+ }
+
+ nodesRemoved++;
+
+ // Find the instruction to remove within the dependency linked list.
+ while (curr->inst != inst_to_remove) {
+ prev = curr;
+ curr = curr->next;
+ nodesTraversed++;
+
+ assert(curr != NULL);
+ }
+
+ // Now remove this instruction from the list.
+ prev->next = curr->next;
+
+ --memAllocCounter;
+
+ // Could push this off to the destructor of DependencyEntry
+ curr->inst = NULL;
+
+ delete curr;
+}
+
+template <class DynInstPtr>
+DynInstPtr
+DependencyGraph<DynInstPtr>::pop(PhysRegIndex idx)
+{
+ DepEntry *node;
+ node = dependGraph[idx].next;
+ DynInstPtr inst = NULL;
+ if (node) {
+ inst = node->inst;
+ dependGraph[idx].next = node->next;
+ node->inst = NULL;
+ memAllocCounter--;
+ delete node;
+ }
+ return inst;
+}
+
+template <class DynInstPtr>
+void
+DependencyGraph<DynInstPtr>::dump()
+{
+ DepEntry *curr;
+
+ for (int i = 0; i < numEntries; ++i)
+ {
+ curr = &dependGraph[i];
+
+ if (curr->inst) {
+ cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ",
+ i, curr->inst->readPC(), curr->inst->seqNum);
+ } else {
+ cprintf("dependGraph[%i]: No producer. consumer: ", i);
+ }
+
+ while (curr->next != NULL) {
+ curr = curr->next;
+
+ cprintf("%#x [sn:%lli] ",
+ curr->inst->readPC(), curr->inst->seqNum);
+ }
+
+ cprintf("\n");
+ }
+ cprintf("memAllocCounter: %i\n", memAllocCounter);
+}
+
+#endif // __CPU_O3_DEP_GRAPH_HH__
diff --git a/src/cpu/o3/fetch.cc b/src/cpu/o3/fetch.cc
index 8ad5e6565..d809b07e4 100644
--- a/src/cpu/o3/fetch.cc
+++ b/src/cpu/o3/fetch.cc
@@ -24,10 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/fetch_impl.hh"
-template class SimpleFetch<AlphaSimpleImpl>;
+template class DefaultFetch<O3CPUImpl>;
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
index cc64800d9..7fcd21b7d 100644
--- a/src/cpu/o3/fetch.hh
+++ b/src/cpu/o3/fetch.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,87 +24,190 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Todo: SMT fetch,
-// Add a way to get a stage's current status.
-
-#ifndef __CPU_O3_CPU_SIMPLE_FETCH_HH__
-#define __CPU_O3_CPU_SIMPLE_FETCH_HH__
+#ifndef __CPU_O3_FETCH_HH__
+#define __CPU_O3_FETCH_HH__
+#include "arch/utility.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/pc_event.hh"
-#include "mem/mem_interface.hh"
+#include "mem/packet_impl.hh"
+#include "mem/port.hh"
#include "sim/eventq.hh"
+class Sampler;
+
/**
- * SimpleFetch class to fetch a single instruction each cycle. SimpleFetch
- * will stall if there's an Icache miss, but otherwise assumes a one cycle
- * Icache hit.
+ * DefaultFetch class handles both single threaded and SMT fetch. Its
+ * width is specified by the parameters; each cycle it tries to fetch
+ * that many instructions. It supports using a branch predictor to
+ * predict direction and targets.
+ * It supports the idling functionality of the CPU by indicating to
+ * the CPU when it is active and inactive.
*/
-
template <class Impl>
-class SimpleFetch
+class DefaultFetch
{
public:
/** Typedefs from Impl. */
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInst DynInst;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::Params Params;
+ /** Typedefs from the CPU policy. */
typedef typename CPUPol::BPredUnit BPredUnit;
typedef typename CPUPol::FetchStruct FetchStruct;
typedef typename CPUPol::TimeStruct TimeStruct;
/** Typedefs from ISA. */
typedef TheISA::MachInst MachInst;
+ typedef TheISA::ExtMachInst ExtMachInst;
+
+ /** IcachePort class for DefaultFetch. Handles doing the
+ * communication with the cache/memory.
+ */
+ class IcachePort : public Port
+ {
+ protected:
+ /** Pointer to fetch. */
+ DefaultFetch<Impl> *fetch;
+
+ public:
+ /** Default constructor. */
+ IcachePort(DefaultFetch<Impl> *_fetch)
+ : Port(_fetch->name() + "-iport"), fetch(_fetch)
+ { }
+
+ 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();
+ };
public:
- enum Status {
+ /** Overall fetch status. Used to determine if the CPU can
+ * deschedule itsef due to a lack of activity.
+ */
+ enum FetchStatus {
+ Active,
+ Inactive
+ };
+
+ /** Individual thread status. */
+ enum ThreadStatus {
Running,
Idle,
Squashing,
Blocked,
- IcacheMissStall,
- IcacheMissComplete
+ Fetching,
+ TrapPending,
+ QuiescePending,
+ SwitchOut,
+ IcacheWaitResponse,
+ IcacheWaitRetry,
+ IcacheAccessComplete
};
- // May eventually need statuses on a per thread basis.
- Status _status;
+ /** Fetching Policy, Add new policies here.*/
+ enum FetchPriority {
+ SingleThread,
+ RoundRobin,
+ Branch,
+ IQ,
+ LSQ
+ };
- bool stalled;
+ private:
+ /** Fetch status. */
+ FetchStatus _status;
- public:
- class CacheCompletionEvent : public Event
- {
- private:
- SimpleFetch *fetch;
+ /** Per-thread status. */
+ ThreadStatus fetchStatus[Impl::MaxThreads];
- public:
- CacheCompletionEvent(SimpleFetch *_fetch);
+ /** Fetch policy. */
+ FetchPriority fetchPolicy;
- virtual void process();
- virtual const char *description();
- };
+ /** List that has the threads organized by priority. */
+ std::list<unsigned> priorityList;
public:
- /** SimpleFetch constructor. */
- SimpleFetch(Params &params);
+ /** DefaultFetch constructor. */
+ DefaultFetch(Params *params);
+
+ /** Returns the name of fetch. */
+ std::string name() const;
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu_ptr);
+ /** Sets CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+ /** Sets the main backwards communication time buffer pointer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer);
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Sets pointer to time buffer used to communicate to the next stage. */
void setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr);
- void processCacheCompletion();
+ /** Initialize stage. */
+ void initStage();
+
+ /** Processes cache completion event. */
+ void processCacheCompletion(PacketPtr pkt);
+
+ /** Begins the switch out of the fetch stage. */
+ void switchOut();
+
+ /** Completes the switch out of the fetch stage. */
+ void doSwitchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Checks if the fetch stage is switched out. */
+ bool isSwitchedOut() { return switchedOut; }
+
+ /** Tells fetch to wake up from a quiesce instruction. */
+ void wakeFromQuiesce();
private:
+ /** 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();
+
/**
* Looks up in the branch predictor to see if the next PC should be
* either next PC+=MachInst or a branch target.
@@ -120,24 +223,54 @@ class SimpleFetch
* fault that happened. Puts the data into the class variable
* cacheData.
* @param fetch_PC The PC address that is being fetched from.
+ * @param ret_fault The fault reference that will be set to the result of
+ * the icache access.
+ * @param tid Thread id.
* @return Any fault that occured.
*/
- Fault fetchCacheLine(Addr fetch_PC);
+ bool fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid);
+
+ /** Squashes a specific thread and resets the PC. */
+ inline void doSquash(const Addr &new_PC, unsigned tid);
+
+ /** Squashes a specific thread and resets the PC. Also tells the CPU to
+ * remove any instructions between fetch and decode that should be sqaushed.
+ */
+ void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num,
+ unsigned tid);
- inline void doSquash(const Addr &new_PC);
+ /** Checks if a thread is stalled. */
+ bool checkStall(unsigned tid) const;
- void squashFromDecode(const Addr &new_PC, const InstSeqNum &seq_num);
+ /** Updates overall fetch stage status; to be called at the end of each
+ * cycle. */
+ FetchStatus updateFetchStatus();
public:
- // Figure out PC vs next PC and how it should be updated
- void squash(const Addr &new_PC);
+ /** Squashes a specific thread and resets the PC. Also tells the CPU to
+ * remove any instructions that are not in the ROB. The source of this
+ * squash should be the commit stage.
+ */
+ void squash(const Addr &new_PC, unsigned tid);
+ /** Ticks the fetch stage, processing all inputs signals and fetching
+ * as many instructions as possible.
+ */
void tick();
- void fetch();
+ /** Checks all input signals and updates the status as necessary.
+ * @return: Returns if the status has changed due to input signals.
+ */
+ bool checkSignalsAndUpdate(unsigned tid);
+
+ /** Does the actual fetching of instructions and passing them on to the
+ * next stage.
+ * @param status_change fetch() sets this variable if there was a status
+ * change (ie switching to IcacheMissStall).
+ */
+ void fetch(bool &status_change);
- // Align an address (typically a PC) to the start of an I-cache block.
- // We fold in the PISA 64- to 32-bit conversion here as well.
+ /** Align a PC to the start of an I-cache block. */
Addr icacheBlockAlignPC(Addr addr)
{
addr = TheISA::realPCToFetchPC(addr);
@@ -145,8 +278,27 @@ class SimpleFetch
}
private:
- /** Pointer to the FullCPU. */
- FullCPU *cpu;
+ /** Handles retrying the fetch access. */
+ void recvRetry();
+
+ /** Returns the appropriate thread to fetch, given the fetch policy. */
+ int getFetchingThread(FetchPriority &fetch_priority);
+
+ /** Returns the appropriate thread to fetch using a round robin policy. */
+ int roundRobin();
+
+ /** Returns the appropriate thread to fetch using the IQ count policy. */
+ int iqCount();
+
+ /** Returns the appropriate thread to fetch using the LSQ count policy. */
+ int lsqCount();
+
+ /** Returns the appropriate thread to fetch using the branch count policy. */
+ int branchCount();
+
+ private:
+ /** Pointer to the O3CPU. */
+ O3CPU *cpu;
/** Time buffer interface. */
TimeBuffer<TimeStruct> *timeBuffer;
@@ -170,14 +322,50 @@ class SimpleFetch
/** Wire used to write any information heading to decode. */
typename TimeBuffer<FetchStruct>::wire toDecode;
+ MemObject *mem;
+
/** Icache interface. */
- MemInterface *icacheInterface;
+ IcachePort *icachePort;
/** BPredUnit. */
BPredUnit branchPred;
+ /** Per-thread fetch PC. */
+ Addr PC[Impl::MaxThreads];
+
+ /** Per-thread next PC. */
+ Addr nextPC[Impl::MaxThreads];
+
+#if THE_ISA != ALPHA_ISA
+ /** Per-thread next Next PC.
+ * This is not a real register but is used for
+ * architectures that use a branch-delay slot.
+ * (such as MIPS or Sparc)
+ */
+ Addr nextNPC[Impl::MaxThreads];
+#endif
+
/** Memory request used to access cache. */
- MemReqPtr memReq;
+ RequestPtr memReq[Impl::MaxThreads];
+
+ /** Variable that tracks if fetch has written to the time buffer this
+ * cycle. Used to tell CPU if there is activity this cycle.
+ */
+ bool wroteToTimeBuffer;
+
+ /** Tracks how many instructions has been fetched this cycle. */
+ int numInst;
+
+ /** Source of possible stalls. */
+ struct Stalls {
+ bool decode;
+ bool rename;
+ bool iew;
+ bool commit;
+ };
+
+ /** Tracks which stages are telling fetch to stall. */
+ Stalls stalls[Impl::MaxThreads];
/** Decode to fetch delay, in ticks. */
unsigned decodeToFetchDelay;
@@ -194,6 +382,15 @@ class SimpleFetch
/** The width of fetch in instructions. */
unsigned fetchWidth;
+ /** Is the cache blocked? If so no threads can access it. */
+ bool cacheBlocked;
+
+ /** The packet that is waiting to be retried. */
+ PacketPtr retryPkt;
+
+ /** The thread that is waiting on the cache to tell fetch to retry. */
+ int retryTid;
+
/** Cache block size. */
int cacheBlkSize;
@@ -201,23 +398,69 @@ class SimpleFetch
Addr cacheBlkMask;
/** The cache line being fetched. */
- uint8_t *cacheData;
+ uint8_t *cacheData[Impl::MaxThreads];
/** Size of instructions. */
int instSize;
/** Icache stall statistics. */
- Counter lastIcacheStall;
+ Counter lastIcacheStall[Impl::MaxThreads];
+
+ /** List of Active Threads */
+ std::list<unsigned> *activeThreads;
+ /** Number of threads. */
+ unsigned numThreads;
+
+ /** Number of threads that are actively fetching. */
+ unsigned numFetchingThreads;
+
+ /** Thread ID being fetched. */
+ int threadFetched;
+
+ /** Checks if there is an interrupt pending. If there is, fetch
+ * must stop once it is not fetching PAL instructions.
+ */
+ bool interruptPending;
+
+ /** Records if fetch is switched out. */
+ bool switchedOut;
+
+ // @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;
+ /** Stat for total number of fetched instructions. */
Stats::Scalar<> fetchedInsts;
+ /** Total number of fetched branches. */
+ Stats::Scalar<> fetchedBranches;
+ /** Stat for total number of predicted branches. */
Stats::Scalar<> predictedBranches;
+ /** Stat for total number of cycles spent fetching. */
Stats::Scalar<> fetchCycles;
+ /** Stat for total number of cycles spent squashing. */
Stats::Scalar<> fetchSquashCycles;
+ /** Stat for total number of cycles spent blocked due to other stages in
+ * the pipeline.
+ */
+ Stats::Scalar<> fetchIdleCycles;
+ /** Total number of cycles spent blocked. */
Stats::Scalar<> fetchBlockedCycles;
+ /** Total number of cycles spent in any other state. */
+ Stats::Scalar<> fetchMiscStallCycles;
+ /** Stat for total number of fetched cache lines. */
Stats::Scalar<> fetchedCacheLines;
-
- Stats::Distribution<> fetch_nisn_dist;
+ /** Total number of outstanding icache accesses that were dropped
+ * due to a squash.
+ */
+ Stats::Scalar<> fetchIcacheSquashes;
+ /** Distribution of number of instructions fetched each cycle. */
+ Stats::Distribution<> fetchNisnDist;
+ /** Rate of how often fetch was idle. */
+ Stats::Formula idleRate;
+ /** Number of branch fetches per cycle. */
+ Stats::Formula branchRate;
+ /** Number of instruction fetched per cycle. */
+ Stats::Formula fetchRate;
};
-#endif //__CPU_O3_CPU_SIMPLE_FETCH_HH__
+#endif //__CPU_O3_FETCH_HH__
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index 8029fc732..60eb76d17 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,85 +24,164 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Remove this later; used only for debugging.
-#define OPCODE(X) (X >> 26) & 0x3f
+#include "config/use_checker.hh"
#include "arch/isa_traits.hh"
-#include "sim/byteswap.hh"
+#include "arch/utility.hh"
+#include "cpu/checker/cpu.hh"
#include "cpu/exetrace.hh"
-#include "mem/base_mem.hh"
-#include "mem/mem_interface.hh"
-#include "mem/mem_req.hh"
#include "cpu/o3/fetch.hh"
-
+#include "mem/packet.hh"
+#include "mem/request.hh"
+#include "sim/byteswap.hh"
+#include "sim/host.hh"
#include "sim/root.hh"
+#if FULL_SYSTEM
+#include "arch/tlb.hh"
+#include "arch/vtophys.hh"
+#include "base/remote_gdb.hh"
+#include "sim/system.hh"
+#endif // FULL_SYSTEM
+
+#include <algorithm>
+
+using namespace std;
+using namespace TheISA;
+
+template<class Impl>
+Tick
+DefaultFetch<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("DefaultFetch doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
template<class Impl>
-SimpleFetch<Impl>::CacheCompletionEvent
-::CacheCompletionEvent(SimpleFetch *_fetch)
- : Event(&mainEventQueue),
- fetch(_fetch)
+void
+DefaultFetch<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
{
+ panic("DefaultFetch doesn't expect recvFunctional callback!");
}
template<class Impl>
void
-SimpleFetch<Impl>::CacheCompletionEvent::process()
+DefaultFetch<Impl>::IcachePort::recvStatusChange(Status status)
{
- fetch->processCacheCompletion();
+ if (status == RangeChange)
+ return;
+
+ panic("DefaultFetch doesn't expect recvStatusChange callback!");
}
template<class Impl>
-const char *
-SimpleFetch<Impl>::CacheCompletionEvent::description()
+bool
+DefaultFetch<Impl>::IcachePort::recvTiming(Packet *pkt)
{
- return "SimpleFetch cache completion event";
+ fetch->processCacheCompletion(pkt);
+ return true;
}
template<class Impl>
-SimpleFetch<Impl>::SimpleFetch(Params &params)
- : icacheInterface(params.icacheInterface),
+void
+DefaultFetch<Impl>::IcachePort::recvRetry()
+{
+ fetch->recvRetry();
+}
+
+template<class Impl>
+DefaultFetch<Impl>::DefaultFetch(Params *params)
+ : mem(params->mem),
branchPred(params),
- decodeToFetchDelay(params.decodeToFetchDelay),
- renameToFetchDelay(params.renameToFetchDelay),
- iewToFetchDelay(params.iewToFetchDelay),
- commitToFetchDelay(params.commitToFetchDelay),
- fetchWidth(params.fetchWidth)
-{
- DPRINTF(Fetch, "Fetch: Fetch constructor called\n");
-
- // Set status to idle.
- _status = Idle;
-
- // Create a new memory request.
- memReq = new MemReq();
- // Not sure of this parameter. I think it should be based on the
- // thread number.
-#if !FULL_SYSTEM
- memReq->asid = 0;
-#else
- memReq->asid = 0;
-#endif // FULL_SYSTEM
- memReq->data = new uint8_t[64];
+ decodeToFetchDelay(params->decodeToFetchDelay),
+ renameToFetchDelay(params->renameToFetchDelay),
+ iewToFetchDelay(params->iewToFetchDelay),
+ commitToFetchDelay(params->commitToFetchDelay),
+ fetchWidth(params->fetchWidth),
+ cacheBlocked(false),
+ retryPkt(NULL),
+ retryTid(-1),
+ numThreads(params->numberOfThreads),
+ numFetchingThreads(params->smtNumFetchingThreads),
+ interruptPending(false),
+ switchedOut(false)
+{
+ if (numThreads > Impl::MaxThreads)
+ fatal("numThreads is not a valid value\n");
+
+ // Set fetch stage's status to inactive.
+ _status = Inactive;
+
+ string policy = params->smtFetchPolicy;
+
+ // Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ // Figure out fetch policy
+ if (policy == "singlethread") {
+ fetchPolicy = SingleThread;
+ if (numThreads > 1)
+ panic("Invalid Fetch Policy for a SMT workload.");
+ } else if (policy == "roundrobin") {
+ fetchPolicy = RoundRobin;
+ DPRINTF(Fetch, "Fetch policy set to Round Robin\n");
+ } else if (policy == "branch") {
+ fetchPolicy = Branch;
+ DPRINTF(Fetch, "Fetch policy set to Branch Count\n");
+ } else if (policy == "iqcount") {
+ fetchPolicy = IQ;
+ DPRINTF(Fetch, "Fetch policy set to IQ count\n");
+ } else if (policy == "lsqcount") {
+ fetchPolicy = LSQ;
+ DPRINTF(Fetch, "Fetch policy set to LSQ count\n");
+ } else {
+ fatal("Invalid Fetch Policy. Options Are: {SingleThread,"
+ " RoundRobin,LSQcount,IQcount}\n");
+ }
// Size of cache block.
- cacheBlkSize = icacheInterface ? icacheInterface->getBlockSize() : 64;
+ cacheBlkSize = 64;
// Create mask to get rid of offset bits.
cacheBlkMask = (cacheBlkSize - 1);
+ for (int tid=0; tid < numThreads; tid++) {
+
+ fetchStatus[tid] = Running;
+
+ priorityList.push_back(tid);
+
+ memReq[tid] = NULL;
+
+ // Create space to store a cache line.
+ cacheData[tid] = new uint8_t[cacheBlkSize];
+
+ stalls[tid].decode = 0;
+ stalls[tid].rename = 0;
+ stalls[tid].iew = 0;
+ stalls[tid].commit = 0;
+ }
+
// Get the size of an instruction.
instSize = sizeof(MachInst);
+}
- // Create space to store a cache line.
- cacheData = new uint8_t[cacheBlkSize];
+template <class Impl>
+std::string
+DefaultFetch<Impl>::name() const
+{
+ return cpu->name() + ".fetch";
}
template <class Impl>
void
-SimpleFetch<Impl>::regStats()
+DefaultFetch<Impl>::regStats()
{
icacheStallCycles
.name(name() + ".icacheStallCycles")
@@ -110,58 +189,116 @@ SimpleFetch<Impl>::regStats()
.prereq(icacheStallCycles);
fetchedInsts
- .name(name() + ".fetchedInsts")
+ .name(name() + ".Insts")
.desc("Number of instructions fetch has processed")
.prereq(fetchedInsts);
+
+ fetchedBranches
+ .name(name() + ".Branches")
+ .desc("Number of branches that fetch encountered")
+ .prereq(fetchedBranches);
+
predictedBranches
.name(name() + ".predictedBranches")
.desc("Number of branches that fetch has predicted taken")
.prereq(predictedBranches);
+
fetchCycles
- .name(name() + ".fetchCycles")
+ .name(name() + ".Cycles")
.desc("Number of cycles fetch has run and was not squashing or"
" blocked")
.prereq(fetchCycles);
+
fetchSquashCycles
- .name(name() + ".fetchSquashCycles")
+ .name(name() + ".SquashCycles")
.desc("Number of cycles fetch has spent squashing")
.prereq(fetchSquashCycles);
+
+ fetchIdleCycles
+ .name(name() + ".IdleCycles")
+ .desc("Number of cycles fetch was idle")
+ .prereq(fetchIdleCycles);
+
fetchBlockedCycles
- .name(name() + ".fetchBlockedCycles")
+ .name(name() + ".BlockedCycles")
.desc("Number of cycles fetch has spent blocked")
.prereq(fetchBlockedCycles);
+
fetchedCacheLines
- .name(name() + ".fetchedCacheLines")
+ .name(name() + ".CacheLines")
.desc("Number of cache lines fetched")
.prereq(fetchedCacheLines);
- fetch_nisn_dist
+ fetchMiscStallCycles
+ .name(name() + ".MiscStallCycles")
+ .desc("Number of cycles fetch has spent waiting on interrupts, or "
+ "bad addresses, or out of MSHRs")
+ .prereq(fetchMiscStallCycles);
+
+ fetchIcacheSquashes
+ .name(name() + ".IcacheSquashes")
+ .desc("Number of outstanding Icache misses that were squashed")
+ .prereq(fetchIcacheSquashes);
+
+ fetchNisnDist
.init(/* base value */ 0,
/* last value */ fetchWidth,
/* bucket size */ 1)
- .name(name() + ".FETCH:rate_dist")
+ .name(name() + ".rateDist")
.desc("Number of instructions fetched each cycle (Total)")
- .flags(Stats::pdf)
- ;
+ .flags(Stats::pdf);
+
+ idleRate
+ .name(name() + ".idleRate")
+ .desc("Percent of cycles fetch was idle")
+ .prereq(idleRate);
+ idleRate = fetchIdleCycles * 100 / cpu->numCycles;
+
+ branchRate
+ .name(name() + ".branchRate")
+ .desc("Number of branch fetches per cycle")
+ .flags(Stats::total);
+ branchRate = fetchedBranches / cpu->numCycles;
+
+ fetchRate
+ .name(name() + ".rate")
+ .desc("Number of inst fetches per cycle")
+ .flags(Stats::total);
+ fetchRate = fetchedInsts / cpu->numCycles;
branchPred.regStats();
}
template<class Impl>
void
-SimpleFetch<Impl>::setCPU(FullCPU *cpu_ptr)
+DefaultFetch<Impl>::setCPU(O3CPU *cpu_ptr)
{
- DPRINTF(Fetch, "Fetch: Setting the CPU pointer.\n");
+ DPRINTF(Fetch, "Setting the CPU pointer.\n");
cpu = cpu_ptr;
- // This line will be removed eventually.
- memReq->xc = cpu->xcBase();
+
+ // Name is finally available, so create the port.
+ icachePort = new IcachePort(this);
+
+ Port *mem_dport = mem->getPort("");
+ icachePort->setPeer(mem_dport);
+ mem_dport->setPeer(icachePort);
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setIcachePort(icachePort);
+ }
+#endif
+
+ // Fetch needs to start fetching instructions at the very beginning,
+ // so it must start up in active state.
+ switchToActive();
}
template<class Impl>
void
-SimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
+DefaultFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
{
- DPRINTF(Fetch, "Fetch: Setting the time buffer pointer.\n");
+ DPRINTF(Fetch, "Setting the time buffer pointer.\n");
timeBuffer = time_buffer;
// Create wires to get information from proper places in time buffer.
@@ -173,9 +310,17 @@ SimpleFetch<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *time_buffer)
template<class Impl>
void
-SimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
+DefaultFetch<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(Fetch, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+template<class Impl>
+void
+DefaultFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
{
- DPRINTF(Fetch, "Fetch: Setting the fetch queue pointer.\n");
+ DPRINTF(Fetch, "Setting the fetch queue pointer.\n");
fetchQueue = fq_ptr;
// Create wire to write information to proper place in fetch queue.
@@ -184,21 +329,139 @@ SimpleFetch<Impl>::setFetchQueue(TimeBuffer<FetchStruct> *fq_ptr)
template<class Impl>
void
-SimpleFetch<Impl>::processCacheCompletion()
+DefaultFetch<Impl>::initStage()
{
- DPRINTF(Fetch, "Fetch: Waking up from cache miss.\n");
+ // Setup PC and nextPC with initial state.
+ for (int tid = 0; tid < numThreads; tid++) {
+ PC[tid] = cpu->readPC(tid);
+ nextPC[tid] = cpu->readNextPC(tid);
+#if THE_ISA != ALPHA_ISA
+ nextNPC[tid] = cpu->readNextNPC(tid);
+#endif
+ }
+}
+
+template<class Impl>
+void
+DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
+{
+ unsigned tid = pkt->req->getThreadNum();
+
+ DPRINTF(Fetch, "[tid:%u] Waking up from cache miss.\n",tid);
// Only change the status if it's still waiting on the icache access
// to return.
- // Can keep track of how many cache accesses go unused due to
- // misspeculation here.
- if (_status == IcacheMissStall)
- _status = IcacheMissComplete;
+ if (fetchStatus[tid] != IcacheWaitResponse ||
+ pkt->req != memReq[tid] ||
+ isSwitchedOut()) {
+ ++fetchIcacheSquashes;
+ delete pkt->req;
+ delete pkt;
+ return;
+ }
+
+ // Wake up the CPU (if it went to sleep and was waiting on this completion
+ // event).
+ cpu->wakeCPU();
+
+ DPRINTF(Activity, "[tid:%u] Activating fetch due to cache completion\n",
+ tid);
+
+ switchToActive();
+
+ // Only switch to IcacheAccessComplete if we're not stalled as well.
+ if (checkStall(tid)) {
+ fetchStatus[tid] = Blocked;
+ } else {
+ fetchStatus[tid] = IcacheAccessComplete;
+ }
+
+ // Reset the mem req to NULL.
+ delete pkt->req;
+ delete pkt;
+ memReq[tid] = NULL;
+}
+
+template <class Impl>
+void
+DefaultFetch<Impl>::switchOut()
+{
+ // Fetch is ready to switch out at any time.
+ switchedOut = true;
+ cpu->signalSwitched();
+}
+
+template <class Impl>
+void
+DefaultFetch<Impl>::doSwitchOut()
+{
+ // Branch predictor needs to have its state cleared.
+ branchPred.switchOut();
+}
+
+template <class Impl>
+void
+DefaultFetch<Impl>::takeOverFrom()
+{
+ // Reset all state
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ stalls[i].decode = 0;
+ stalls[i].rename = 0;
+ stalls[i].iew = 0;
+ stalls[i].commit = 0;
+ PC[i] = cpu->readPC(i);
+ nextPC[i] = cpu->readNextPC(i);
+#if THE_ISA != ALPHA_ISA
+ nextNPC[i] = cpu->readNextNPC(i);
+#endif
+ fetchStatus[i] = Running;
+ }
+ numInst = 0;
+ wroteToTimeBuffer = false;
+ _status = Inactive;
+ switchedOut = false;
+ branchPred.takeOverFrom();
+}
+
+template <class Impl>
+void
+DefaultFetch<Impl>::wakeFromQuiesce()
+{
+ DPRINTF(Fetch, "Waking up from quiesce\n");
+ // Hopefully this is safe
+ // @todo: Allow other threads to wake from quiesce.
+ fetchStatus[0] = Running;
+}
+
+template <class Impl>
+inline void
+DefaultFetch<Impl>::switchToActive()
+{
+ if (_status == Inactive) {
+ DPRINTF(Activity, "Activating stage.\n");
+
+ cpu->activateStage(O3CPU::FetchIdx);
+
+ _status = Active;
+ }
+}
+
+template <class Impl>
+inline void
+DefaultFetch<Impl>::switchToInactive()
+{
+ if (_status == Active) {
+ DPRINTF(Activity, "Deactivating stage.\n");
+
+ cpu->deactivateStage(O3CPU::FetchIdx);
+
+ _status = Inactive;
+ }
}
template <class Impl>
bool
-SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
+DefaultFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
{
// Do branch prediction check here.
// A bit of a misnomer...next_PC is actually the current PC until
@@ -211,7 +474,9 @@ SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
return false;
}
- predict_taken = branchPred.predict(inst, next_PC);
+ predict_taken = branchPred.predict(inst, next_PC, inst->threadNumber);
+
+ ++fetchedBranches;
if (predict_taken) {
++predictedBranches;
@@ -221,251 +486,430 @@ SimpleFetch<Impl>::lookupAndUpdateNextPC(DynInstPtr &inst, Addr &next_PC)
}
template <class Impl>
-Fault
-SimpleFetch<Impl>::fetchCacheLine(Addr fetch_PC)
+bool
+DefaultFetch<Impl>::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid)
{
- // Check if the instruction exists within the cache.
- // If it does, then proceed on to read the instruction and the rest
- // of the instructions in the cache line until either the end of the
- // cache line or a predicted taken branch is encountered.
+ Fault fault = NoFault;
#if FULL_SYSTEM
// Flag to say whether or not address is physical addr.
- unsigned flags = cpu->inPalMode() ? PHYSICAL : 0;
+ unsigned flags = cpu->inPalMode(fetch_PC) ? PHYSICAL : 0;
#else
unsigned flags = 0;
#endif // FULL_SYSTEM
- Fault fault = NoFault;
+ if (cacheBlocked || (interruptPending && flags == 0) || switchedOut) {
+ // Hold off fetch from getting new instructions when:
+ // Cache is blocked, or
+ // while an interrupt is pending and we're not in PAL mode, or
+ // fetch is switched out.
+ return false;
+ }
// Align the fetch PC so it's at the start of a cache block.
fetch_PC = icacheBlockAlignPC(fetch_PC);
- // Setup the memReq to do a read of the first isntruction's address.
+ // Setup the memReq to do a read of the first instruction's address.
// Set the appropriate read size and flags as well.
- memReq->cmd = Read;
- memReq->reset(fetch_PC, cacheBlkSize, flags);
+ // Build request here.
+ RequestPtr mem_req = new Request(tid, fetch_PC, cacheBlkSize, flags,
+ fetch_PC, cpu->readCpuId(), tid);
- // Translate the instruction request.
- // Should this function be
- // in the CPU class ? Probably...ITB/DTB should exist within the
- // CPU.
+ memReq[tid] = mem_req;
- fault = cpu->translateInstReq(memReq);
+ // Translate the instruction request.
+ fault = cpu->translateInstReq(mem_req, cpu->thread[tid]);
// In the case of faults, the fetch stage may need to stall and wait
- // on what caused the fetch (ITB or Icache miss).
+ // for the ITB miss to be handled.
// If translation was successful, attempt to read the first
// instruction.
if (fault == NoFault) {
+#if 0
+ if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) ||
+ memReq[tid]->flags & UNCACHEABLE) {
+ DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a "
+ "misspeculating path)!",
+ memReq[tid]->paddr);
+ ret_fault = TheISA::genMachineCheckFault();
+ return false;
+ }
+#endif
+
+ // Build packet here.
+ PacketPtr data_pkt = new Packet(mem_req,
+ Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(cacheData[tid]);
+
DPRINTF(Fetch, "Fetch: Doing instruction read.\n");
- fault = cpu->mem->read(memReq, cacheData);
- // This read may change when the mem interface changes.
fetchedCacheLines++;
- }
-
- // Now do the timing access to see whether or not the instruction
- // exists within the cache.
- if (icacheInterface && fault == NoFault) {
- DPRINTF(Fetch, "Fetch: Doing timing memory access.\n");
- memReq->completionEvent = NULL;
- memReq->time = curTick;
+ // Now do the timing access to see whether or not the instruction
+ // exists within the cache.
+ if (!icachePort->sendTiming(data_pkt)) {
+ assert(retryPkt == NULL);
+ assert(retryTid == -1);
+ DPRINTF(Fetch, "[tid:%i] Out of MSHRs!\n", tid);
+ fetchStatus[tid] = IcacheWaitRetry;
+ retryPkt = data_pkt;
+ retryTid = tid;
+ cacheBlocked = true;
+ return false;
+ }
- MemAccessResult result = icacheInterface->access(memReq);
+ DPRINTF(Fetch, "[tid:%i]: Doing cache access.\n", tid);
- // If the cache missed (in this model functional and timing
- // memories are different), then schedule an event to wake
- // up this stage once the cache miss completes.
- if (result != MA_HIT && icacheInterface->doEvents()) {
- memReq->completionEvent = new CacheCompletionEvent(this);
+ lastIcacheStall[tid] = curTick;
- // How does current model work as far as individual
- // stages scheduling/unscheduling?
- // Perhaps have only the main CPU scheduled/unscheduled,
- // and have it choose what stages to run appropriately.
+ DPRINTF(Activity, "[tid:%i]: Activity: Waiting on I-cache "
+ "response.\n", tid);
- DPRINTF(Fetch, "Fetch: Stalling due to icache miss.\n");
- _status = IcacheMissStall;
- }
+ fetchStatus[tid] = IcacheWaitResponse;
+ } else {
+ delete mem_req;
+ memReq[tid] = NULL;
}
- return fault;
+ ret_fault = fault;
+ return true;
}
template <class Impl>
inline void
-SimpleFetch<Impl>::doSquash(const Addr &new_PC)
+DefaultFetch<Impl>::doSquash(const Addr &new_PC, unsigned tid)
{
- DPRINTF(Fetch, "Fetch: Squashing, setting PC to: %#x.\n", new_PC);
+ DPRINTF(Fetch, "[tid:%i]: Squashing, setting PC to: %#x.\n",
+ tid, new_PC);
- cpu->setNextPC(new_PC + instSize);
- cpu->setPC(new_PC);
+ PC[tid] = new_PC;
+ nextPC[tid] = new_PC + instSize;
// Clear the icache miss if it's outstanding.
- if (_status == IcacheMissStall && icacheInterface) {
- DPRINTF(Fetch, "Fetch: Squashing outstanding Icache miss.\n");
- // @todo: Use an actual thread number here.
- icacheInterface->squash(0);
+ if (fetchStatus[tid] == IcacheWaitResponse) {
+ DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n",
+ tid);
+ memReq[tid] = NULL;
+ }
+
+ // Get rid of the retrying packet if it was from this thread.
+ if (retryTid == tid) {
+ assert(cacheBlocked);
+ cacheBlocked = false;
+ retryTid = -1;
+ retryPkt = NULL;
+ delete retryPkt->req;
+ delete retryPkt;
}
- _status = Squashing;
+ fetchStatus[tid] = Squashing;
++fetchSquashCycles;
}
template<class Impl>
void
-SimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,
- const InstSeqNum &seq_num)
+DefaultFetch<Impl>::squashFromDecode(const Addr &new_PC,
+ const InstSeqNum &seq_num,
+ unsigned tid)
{
- DPRINTF(Fetch, "Fetch: Squashing from decode.\n");
+ DPRINTF(Fetch, "[tid:%i]: Squashing from decode.\n",tid);
- doSquash(new_PC);
+ doSquash(new_PC, tid);
// Tell the CPU to remove any instructions that are in flight between
// fetch and decode.
- cpu->removeInstsUntil(seq_num);
+ cpu->removeInstsUntil(seq_num, tid);
+}
+
+template<class Impl>
+bool
+DefaultFetch<Impl>::checkStall(unsigned tid) const
+{
+ bool ret_val = false;
+
+ if (cpu->contextSwitch) {
+ DPRINTF(Fetch,"[tid:%i]: Stalling for a context switch.\n",tid);
+ ret_val = true;
+ } else if (stalls[tid].decode) {
+ DPRINTF(Fetch,"[tid:%i]: Stall from Decode stage detected.\n",tid);
+ ret_val = true;
+ } else if (stalls[tid].rename) {
+ DPRINTF(Fetch,"[tid:%i]: Stall from Rename stage detected.\n",tid);
+ ret_val = true;
+ } else if (stalls[tid].iew) {
+ DPRINTF(Fetch,"[tid:%i]: Stall from IEW stage detected.\n",tid);
+ ret_val = true;
+ } else if (stalls[tid].commit) {
+ DPRINTF(Fetch,"[tid:%i]: Stall from Commit stage detected.\n",tid);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+template<class Impl>
+typename DefaultFetch<Impl>::FetchStatus
+DefaultFetch<Impl>::updateFetchStatus()
+{
+ //Check Running
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+
+ unsigned tid = *threads++;
+
+ if (fetchStatus[tid] == Running ||
+ fetchStatus[tid] == Squashing ||
+ fetchStatus[tid] == IcacheAccessComplete) {
+
+ if (_status == Inactive) {
+ DPRINTF(Activity, "[tid:%i]: Activating stage.\n",tid);
+
+ if (fetchStatus[tid] == IcacheAccessComplete) {
+ DPRINTF(Activity, "[tid:%i]: Activating fetch due to cache"
+ "completion\n",tid);
+ }
+
+ cpu->activateStage(O3CPU::FetchIdx);
+ }
+
+ return Active;
+ }
+ }
+
+ // Stage is switching from active to inactive, notify CPU of it.
+ if (_status == Active) {
+ DPRINTF(Activity, "Deactivating stage.\n");
+
+ cpu->deactivateStage(O3CPU::FetchIdx);
+ }
+
+ return Inactive;
}
template <class Impl>
void
-SimpleFetch<Impl>::squash(const Addr &new_PC)
+DefaultFetch<Impl>::squash(const Addr &new_PC, unsigned tid)
{
- DPRINTF(Fetch, "Fetch: Squash from commit.\n");
+ DPRINTF(Fetch, "[tid:%u]: Squash from commit.\n",tid);
- doSquash(new_PC);
+ doSquash(new_PC, tid);
// Tell the CPU to remove any instructions that are not in the ROB.
- cpu->removeInstsNotInROB();
+ cpu->removeInstsNotInROB(tid);
}
-template<class Impl>
+template <class Impl>
void
-SimpleFetch<Impl>::tick()
+DefaultFetch<Impl>::tick()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ bool status_change = false;
+
+ wroteToTimeBuffer = false;
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ // Check the signals for each thread to determine the proper status
+ // for each thread.
+ bool updated_status = checkSignalsAndUpdate(tid);
+ status_change = status_change || updated_status;
+ }
+
+ DPRINTF(Fetch, "Running stage.\n");
+
+ // Reset the number of the instruction we're fetching.
+ numInst = 0;
+
+#if FULL_SYSTEM
+ if (fromCommit->commitInfo[0].interruptPending) {
+ interruptPending = true;
+ }
+
+ if (fromCommit->commitInfo[0].clearInterrupt) {
+ interruptPending = false;
+ }
+#endif
+
+ for (threadFetched = 0; threadFetched < numFetchingThreads;
+ threadFetched++) {
+ // Fetch each of the actively fetching threads.
+ fetch(status_change);
+ }
+
+ // Record number of instructions fetched this cycle for distribution.
+ fetchNisnDist.sample(numInst);
+
+ if (status_change) {
+ // Change the fetch stage status if there was a status change.
+ _status = updateFetchStatus();
+ }
+
+ // If there was activity this cycle, inform the CPU of it.
+ if (wroteToTimeBuffer || cpu->contextSwitch) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+
+ cpu->activityThisCycle();
+ }
+}
+
+template <class Impl>
+bool
+DefaultFetch<Impl>::checkSignalsAndUpdate(unsigned tid)
{
+ // Update the per thread stall statuses.
+ if (fromDecode->decodeBlock[tid]) {
+ stalls[tid].decode = true;
+ }
+
+ if (fromDecode->decodeUnblock[tid]) {
+ assert(stalls[tid].decode);
+ assert(!fromDecode->decodeBlock[tid]);
+ stalls[tid].decode = false;
+ }
+
+ if (fromRename->renameBlock[tid]) {
+ stalls[tid].rename = true;
+ }
+
+ if (fromRename->renameUnblock[tid]) {
+ assert(stalls[tid].rename);
+ assert(!fromRename->renameBlock[tid]);
+ stalls[tid].rename = false;
+ }
+
+ if (fromIEW->iewBlock[tid]) {
+ stalls[tid].iew = true;
+ }
+
+ if (fromIEW->iewUnblock[tid]) {
+ assert(stalls[tid].iew);
+ assert(!fromIEW->iewBlock[tid]);
+ stalls[tid].iew = false;
+ }
+
+ if (fromCommit->commitBlock[tid]) {
+ stalls[tid].commit = true;
+ }
+
+ if (fromCommit->commitUnblock[tid]) {
+ assert(stalls[tid].commit);
+ assert(!fromCommit->commitBlock[tid]);
+ stalls[tid].commit = false;
+ }
+
// Check squash signals from commit.
- if (fromCommit->commitInfo.squash) {
- DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
- "from commit.\n");
+ if (fromCommit->commitInfo[tid].squash) {
+
+ DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
+ "from commit.\n",tid);
// In any case, squash.
- squash(fromCommit->commitInfo.nextPC);
+ squash(fromCommit->commitInfo[tid].nextPC,tid);
// Also check if there's a mispredict that happened.
- if (fromCommit->commitInfo.branchMispredict) {
- branchPred.squash(fromCommit->commitInfo.doneSeqNum,
- fromCommit->commitInfo.nextPC,
- fromCommit->commitInfo.branchTaken);
+ if (fromCommit->commitInfo[tid].branchMispredict) {
+ branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
+ fromCommit->commitInfo[tid].nextPC,
+ fromCommit->commitInfo[tid].branchTaken,
+ tid);
} else {
- branchPred.squash(fromCommit->commitInfo.doneSeqNum);
+ branchPred.squash(fromCommit->commitInfo[tid].doneSeqNum,
+ tid);
}
- return;
- } else if (fromCommit->commitInfo.doneSeqNum) {
+ return true;
+ } else if (fromCommit->commitInfo[tid].doneSeqNum) {
// Update the branch predictor if it wasn't a squashed instruction
- // that was braodcasted.
- branchPred.update(fromCommit->commitInfo.doneSeqNum);
+ // that was broadcasted.
+ branchPred.update(fromCommit->commitInfo[tid].doneSeqNum, tid);
}
// Check ROB squash signals from commit.
- if (fromCommit->commitInfo.robSquashing) {
- DPRINTF(Fetch, "Fetch: ROB is still squashing.\n");
+ if (fromCommit->commitInfo[tid].robSquashing) {
+ DPRINTF(Fetch, "[tid:%u]: ROB is still squashing.\n", tid);
// Continue to squash.
- _status = Squashing;
+ fetchStatus[tid] = Squashing;
- ++fetchSquashCycles;
- return;
+ return true;
}
// Check squash signals from decode.
- if (fromDecode->decodeInfo.squash) {
- DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "
- "from decode.\n");
+ if (fromDecode->decodeInfo[tid].squash) {
+ DPRINTF(Fetch, "[tid:%u]: Squashing instructions due to squash "
+ "from decode.\n",tid);
// Update the branch predictor.
- if (fromDecode->decodeInfo.branchMispredict) {
- branchPred.squash(fromDecode->decodeInfo.doneSeqNum,
- fromDecode->decodeInfo.nextPC,
- fromDecode->decodeInfo.branchTaken);
+ if (fromDecode->decodeInfo[tid].branchMispredict) {
+ branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
+ fromDecode->decodeInfo[tid].nextPC,
+ fromDecode->decodeInfo[tid].branchTaken,
+ tid);
} else {
- branchPred.squash(fromDecode->decodeInfo.doneSeqNum);
+ branchPred.squash(fromDecode->decodeInfo[tid].doneSeqNum,
+ tid);
}
- if (_status != Squashing) {
- // Squash unless we're already squashing?
- squashFromDecode(fromDecode->decodeInfo.nextPC,
- fromDecode->decodeInfo.doneSeqNum);
- return;
+ if (fetchStatus[tid] != Squashing) {
+ // Squash unless we're already squashing
+ squashFromDecode(fromDecode->decodeInfo[tid].nextPC,
+ fromDecode->decodeInfo[tid].doneSeqNum,
+ tid);
+
+ return true;
}
}
- // Check if any of the stall signals are high.
- if (fromDecode->decodeInfo.stall ||
- fromRename->renameInfo.stall ||
- fromIEW->iewInfo.stall ||
- fromCommit->commitInfo.stall)
- {
- // Block stage, regardless of current status.
-
- DPRINTF(Fetch, "Fetch: Stalling stage.\n");
- DPRINTF(Fetch, "Fetch: Statuses: Decode: %i Rename: %i IEW: %i "
- "Commit: %i\n",
- fromDecode->decodeInfo.stall,
- fromRename->renameInfo.stall,
- fromIEW->iewInfo.stall,
- fromCommit->commitInfo.stall);
-
- _status = Blocked;
+ if (checkStall(tid) && fetchStatus[tid] != IcacheWaitResponse) {
+ DPRINTF(Fetch, "[tid:%i]: Setting to blocked\n",tid);
- ++fetchBlockedCycles;
- return;
- } else if (_status == Blocked) {
- // Unblock stage if status is currently blocked and none of the
- // stall signals are being held high.
- _status = Running;
+ fetchStatus[tid] = Blocked;
- ++fetchBlockedCycles;
- return;
+ return true;
}
- // If fetch has reached this point, then there are no squash signals
- // still being held high. Check if fetch is in the squashing state;
- // if so, fetch can switch to running.
- // Similarly, there are no blocked signals still being held high.
- // Check if fetch is in the blocked state; if so, fetch can switch to
- // running.
- if (_status == Squashing) {
- DPRINTF(Fetch, "Fetch: Done squashing, switching to running.\n");
-
- // Switch status to running
- _status = Running;
-
- ++fetchCycles;
-
- fetch();
- } else if (_status != IcacheMissStall) {
- DPRINTF(Fetch, "Fetch: Running stage.\n");
+ if (fetchStatus[tid] == Blocked ||
+ fetchStatus[tid] == Squashing) {
+ // Switch status to running if fetch isn't being told to block or
+ // squash this cycle.
+ DPRINTF(Fetch, "[tid:%i]: Done squashing, switching to running.\n",
+ tid);
- ++fetchCycles;
+ fetchStatus[tid] = Running;
- fetch();
+ return true;
}
+
+ // If we've reached this point, we have not gotten any signals that
+ // cause fetch to change its status. Fetch remains the same as before.
+ return false;
}
template<class Impl>
void
-SimpleFetch<Impl>::fetch()
+DefaultFetch<Impl>::fetch(bool &status_change)
{
//////////////////////////////////////////
// Start actual fetch
//////////////////////////////////////////
+ int tid = getFetchingThread(fetchPolicy);
+
+ if (tid == -1) {
+ DPRINTF(Fetch,"There are no more threads available to fetch from.\n");
+
+ // Breaks looping condition in tick()
+ threadFetched = numFetchingThreads;
+ return;
+ }
+
+ DPRINTF(Fetch, "Attempting to fetch from [tid:%i]\n", tid);
// The current PC.
- Addr fetch_PC = cpu->readPC();
+ Addr &fetch_PC = PC[tid];
// Fault code for memory access.
Fault fault = NoFault;
@@ -473,60 +917,75 @@ SimpleFetch<Impl>::fetch()
// If returning from the delay of a cache miss, then update the status
// to running, otherwise do the cache access. Possibly move this up
// to tick() function.
- if (_status == IcacheMissComplete) {
- DPRINTF(Fetch, "Fetch: Icache miss is complete.\n");
-
- // Reset the completion event to NULL.
- memReq->completionEvent = NULL;
-
- _status = Running;
+ if (fetchStatus[tid] == IcacheAccessComplete) {
+ DPRINTF(Fetch, "[tid:%i]: Icache miss is complete.\n",
+ tid);
+
+ fetchStatus[tid] = Running;
+ status_change = true;
+ } else if (fetchStatus[tid] == Running) {
+ DPRINTF(Fetch, "[tid:%i]: Attempting to translate and read "
+ "instruction, starting at PC %08p.\n",
+ tid, fetch_PC);
+
+ bool fetch_success = fetchCacheLine(fetch_PC, fault, tid);
+ if (!fetch_success) {
+ if (cacheBlocked) {
+ ++icacheStallCycles;
+ } else {
+ ++fetchMiscStallCycles;
+ }
+ return;
+ }
} else {
- DPRINTF(Fetch, "Fetch: Attempting to translate and read "
- "instruction, starting at PC %08p.\n",
- fetch_PC);
+ if (fetchStatus[tid] == Idle) {
+ ++fetchIdleCycles;
+ } else if (fetchStatus[tid] == Blocked) {
+ ++fetchBlockedCycles;
+ } else if (fetchStatus[tid] == Squashing) {
+ ++fetchSquashCycles;
+ } else if (fetchStatus[tid] == IcacheWaitResponse) {
+ ++icacheStallCycles;
+ }
- fault = fetchCacheLine(fetch_PC);
+ // Status is Idle, Squashing, Blocked, or IcacheWaitResponse, so
+ // fetch should do nothing.
+ return;
}
- // If we had a stall due to an icache miss, then return. It'd
- // be nicer if this were handled through the kind of fault that
- // is returned by the function.
- if (_status == IcacheMissStall) {
+ ++fetchCycles;
+
+ // If we had a stall due to an icache miss, then return.
+ if (fetchStatus[tid] == IcacheWaitResponse) {
+ ++icacheStallCycles;
+ status_change = true;
return;
}
- // As far as timing goes, the CPU will need to send an event through
- // the MemReq in order to be woken up once the memory access completes.
- // Probably have a status on a per thread basis so each thread can
- // block independently and be woken up independently.
-
Addr next_PC = fetch_PC;
InstSeqNum inst_seq;
MachInst inst;
- unsigned offset = fetch_PC & cacheBlkMask;
- unsigned fetched;
+ ExtMachInst ext_inst;
+ // @todo: Fix this hack.
+ unsigned offset = (fetch_PC & cacheBlkMask) & ~3;
if (fault == NoFault) {
// If the read of the first instruction was successful, then grab the
// instructions from the rest of the cache line and put them into the
// queue heading to decode.
- DPRINTF(Fetch, "Fetch: Adding instructions to queue to decode.\n");
-
- //////////////////////////
- // Fetch first instruction
- //////////////////////////
+ DPRINTF(Fetch, "[tid:%i]: Adding instructions to queue to "
+ "decode.\n",tid);
// Need to keep track of whether or not a predicted branch
// ended this fetch block.
bool predicted_branch = false;
- for (fetched = 0;
+ for (;
offset < cacheBlkSize &&
- fetched < fetchWidth &&
+ numInst < fetchWidth &&
!predicted_branch;
- ++fetched)
- {
+ ++numInst) {
// Get a sequence number.
inst_seq = cpu->getAndIncrementInstSeq();
@@ -536,31 +995,40 @@ SimpleFetch<Impl>::fetch()
// Get the instruction from the array of the cache line.
inst = gtoh(*reinterpret_cast<MachInst *>
- (&cacheData[offset]));
+ (&cacheData[tid][offset]));
+
+ ext_inst = TheISA::makeExtMI(inst, fetch_PC);
// Create a new DynInst from the instruction fetched.
- DynInstPtr instruction = new DynInst(inst, fetch_PC, next_PC,
+ DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
+ next_PC,
inst_seq, cpu);
+ instruction->setTid(tid);
+
+ instruction->setASID(tid);
+
+ instruction->setThreadState(cpu->thread[tid]);
- DPRINTF(Fetch, "Fetch: Instruction %i created, with PC %#x\n",
- inst_seq, instruction->readPC());
+ DPRINTF(Fetch, "[tid:%i]: Instruction PC %#x created "
+ "[sn:%lli]\n",
+ tid, instruction->readPC(), inst_seq);
- DPRINTF(Fetch, "Fetch: Instruction opcode is: %03p\n",
- OPCODE(inst));
+ DPRINTF(Fetch, "[tid:%i]: Instruction is: %s\n",
+ tid, instruction->staticInst->disassemble(fetch_PC));
instruction->traceData =
- Trace::getInstRecord(curTick, cpu->xcBase(), cpu,
+ Trace::getInstRecord(curTick, cpu->tcBase(tid), cpu,
instruction->staticInst,
- instruction->readPC(), 0);
+ instruction->readPC(),tid);
predicted_branch = lookupAndUpdateNextPC(instruction, next_PC);
// Add instruction to the CPU's list of instructions.
- cpu->addInst(instruction);
+ instruction->setInstListIt(cpu->addInst(instruction));
// Write the instruction to the first slot in the queue
// that heads to decode.
- toDecode->insts[fetched] = instruction;
+ toDecode->insts[numInst] = instruction;
toDecode->size++;
@@ -570,48 +1038,252 @@ SimpleFetch<Impl>::fetch()
// Move to the next instruction, unless we have a branch.
fetch_PC = next_PC;
+ if (instruction->isQuiesce()) {
+ warn("cycle %lli: Quiesce instruction encountered, halting fetch!",
+ curTick);
+ fetchStatus[tid] = QuiescePending;
+ ++numInst;
+ status_change = true;
+ break;
+ }
+
offset+= instSize;
}
+ }
- fetch_nisn_dist.sample(fetched);
+ if (numInst > 0) {
+ wroteToTimeBuffer = true;
}
// Now that fetching is completed, update the PC to signify what the next
- // cycle will be. Might want to move this to the beginning of this
- // function so that the PC updates at the beginning of everything.
- // Or might want to leave setting the PC to the main CPU, with fetch
- // only changing the nextPC (will require correct determination of
- // next PC).
+ // cycle will be.
if (fault == NoFault) {
- DPRINTF(Fetch, "Fetch: Setting PC to %08p.\n", next_PC);
- cpu->setPC(next_PC);
- cpu->setNextPC(next_PC + instSize);
+ DPRINTF(Fetch, "[tid:%i]: Setting PC to %08p.\n",tid, next_PC);
+
+#if THE_ISA == ALPHA_ISA
+ PC[tid] = next_PC;
+ nextPC[tid] = next_PC + instSize;
+#else
+ PC[tid] = next_PC;
+ nextPC[tid] = next_PC + instSize;
+ nextPC[tid] = next_PC + instSize;
+
+ thread->setNextPC(thread->readNextNPC());
+ thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
+#endif
} else {
- // If the issue was an icache miss, then we can just return and
- // wait until it is handled.
- if (_status == IcacheMissStall) {
- return;
+ // We shouldn't be in an icache miss and also have a fault (an ITB
+ // miss)
+ if (fetchStatus[tid] == IcacheWaitResponse) {
+ panic("Fetch should have exited prior to this!");
}
- // Handle the fault.
- // This stage will not be able to continue until all the ROB
- // slots are empty, at which point the fault can be handled.
- // The only other way it can wake up is if a squash comes along
- // and changes the PC. Not sure how to handle that case...perhaps
- // have it handled by the upper level CPU class which peeks into the
- // time buffer and sees if a squash comes along, in which case it
- // changes the status.
+ // Send the fault to commit. This thread will not do anything
+ // until commit handles the fault. The only other way it can
+ // wake up is if a squash comes along and changes the PC.
+#if FULL_SYSTEM
+ assert(numInst != fetchWidth);
+ // Get a sequence number.
+ inst_seq = cpu->getAndIncrementInstSeq();
+ // We will use a nop in order to carry the fault.
+ ext_inst = TheISA::NoopMachInst;
- DPRINTF(Fetch, "Fetch: Blocked, need to handle the trap.\n");
+ // Create a new DynInst from the dummy nop.
+ DynInstPtr instruction = new DynInst(ext_inst, fetch_PC,
+ next_PC,
+ inst_seq, cpu);
+ instruction->setPredTarg(next_PC + instSize);
+ instruction->setTid(tid);
- _status = Blocked;
-#if FULL_SYSTEM
-// cpu->trap(fault);
- // Send a signal to the ROB indicating that there's a trap from the
- // fetch stage that needs to be handled. Need to indicate that
- // there's a fault, and the fault type.
+ instruction->setASID(tid);
+
+ instruction->setThreadState(cpu->thread[tid]);
+
+ instruction->traceData = NULL;
+
+ instruction->setInstListIt(cpu->addInst(instruction));
+
+ instruction->fault = fault;
+
+ toDecode->insts[numInst] = instruction;
+ toDecode->size++;
+
+ DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid);
+
+ fetchStatus[tid] = TrapPending;
+ status_change = true;
+
+ warn("cycle %lli: fault (%d) detected @ PC %08p", curTick, fault, PC[tid]);
#else // !FULL_SYSTEM
- fatal("fault (%d) detected @ PC %08p", fault, cpu->readPC());
+ warn("cycle %lli: fault (%d) detected @ PC %08p", curTick, fault, PC[tid]);
#endif // FULL_SYSTEM
}
}
+
+template<class Impl>
+void
+DefaultFetch<Impl>::recvRetry()
+{
+ assert(cacheBlocked);
+ if (retryPkt != NULL) {
+ assert(retryTid != -1);
+ assert(fetchStatus[retryTid] == IcacheWaitRetry);
+
+ if (icachePort->sendTiming(retryPkt)) {
+ fetchStatus[retryTid] = IcacheWaitResponse;
+ retryPkt = NULL;
+ retryTid = -1;
+ cacheBlocked = false;
+ }
+ } else {
+ assert(retryTid == -1);
+ // Access has been squashed since it was sent out. Just clear
+ // the cache being blocked.
+ cacheBlocked = false;
+ }
+}
+
+///////////////////////////////////////
+// //
+// SMT FETCH POLICY MAINTAINED HERE //
+// //
+///////////////////////////////////////
+template<class Impl>
+int
+DefaultFetch<Impl>::getFetchingThread(FetchPriority &fetch_priority)
+{
+ if (numThreads > 1) {
+ switch (fetch_priority) {
+
+ case SingleThread:
+ return 0;
+
+ case RoundRobin:
+ return roundRobin();
+
+ case IQ:
+ return iqCount();
+
+ case LSQ:
+ return lsqCount();
+
+ case Branch:
+ return branchCount();
+
+ default:
+ return -1;
+ }
+ } else {
+ int tid = *((*activeThreads).begin());
+
+ if (fetchStatus[tid] == Running ||
+ fetchStatus[tid] == IcacheAccessComplete ||
+ fetchStatus[tid] == Idle) {
+ return tid;
+ } else {
+ return -1;
+ }
+ }
+
+}
+
+
+template<class Impl>
+int
+DefaultFetch<Impl>::roundRobin()
+{
+ list<unsigned>::iterator pri_iter = priorityList.begin();
+ list<unsigned>::iterator end = priorityList.end();
+
+ int high_pri;
+
+ while (pri_iter != end) {
+ high_pri = *pri_iter;
+
+ assert(high_pri <= numThreads);
+
+ if (fetchStatus[high_pri] == Running ||
+ fetchStatus[high_pri] == IcacheAccessComplete ||
+ fetchStatus[high_pri] == Idle) {
+
+ priorityList.erase(pri_iter);
+ priorityList.push_back(high_pri);
+
+ return high_pri;
+ }
+
+ pri_iter++;
+ }
+
+ return -1;
+}
+
+template<class Impl>
+int
+DefaultFetch<Impl>::iqCount()
+{
+ priority_queue<unsigned> PQ;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ PQ.push(fromIEW->iewInfo[tid].iqCount);
+ }
+
+ while (!PQ.empty()) {
+
+ unsigned high_pri = PQ.top();
+
+ if (fetchStatus[high_pri] == Running ||
+ fetchStatus[high_pri] == IcacheAccessComplete ||
+ fetchStatus[high_pri] == Idle)
+ return high_pri;
+ else
+ PQ.pop();
+
+ }
+
+ return -1;
+}
+
+template<class Impl>
+int
+DefaultFetch<Impl>::lsqCount()
+{
+ priority_queue<unsigned> PQ;
+
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ PQ.push(fromIEW->iewInfo[tid].ldstqCount);
+ }
+
+ while (!PQ.empty()) {
+
+ unsigned high_pri = PQ.top();
+
+ if (fetchStatus[high_pri] == Running ||
+ fetchStatus[high_pri] == IcacheAccessComplete ||
+ fetchStatus[high_pri] == Idle)
+ return high_pri;
+ else
+ PQ.pop();
+
+ }
+
+ return -1;
+}
+
+template<class Impl>
+int
+DefaultFetch<Impl>::branchCount()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ panic("Branch Count Fetch policy unimplemented\n");
+ return *threads;
+}
diff --git a/src/cpu/o3/free_list.cc b/src/cpu/o3/free_list.cc
index 6f0b4be1e..ae651398b 100644
--- a/src/cpu/o3/free_list.cc
+++ b/src/cpu/o3/free_list.cc
@@ -24,13 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/trace.hh"
#include "cpu/o3/free_list.hh"
-SimpleFreeList::SimpleFreeList(unsigned _numLogicalIntRegs,
+SimpleFreeList::SimpleFreeList(unsigned activeThreads,
+ unsigned _numLogicalIntRegs,
unsigned _numPhysicalIntRegs,
unsigned _numLogicalFloatRegs,
unsigned _numPhysicalFloatRegs)
@@ -40,43 +43,30 @@ SimpleFreeList::SimpleFreeList(unsigned _numLogicalIntRegs,
numPhysicalFloatRegs(_numPhysicalFloatRegs),
numPhysicalRegs(numPhysicalIntRegs + numPhysicalFloatRegs)
{
- DPRINTF(FreeList, "FreeList: Creating new free list object.\n");
-
- // DEBUG stuff.
- freeIntRegsScoreboard.resize(numPhysicalIntRegs);
-
- freeFloatRegsScoreboard.resize(numPhysicalRegs);
-
- for (PhysRegIndex i = 0; i < numLogicalIntRegs; ++i) {
- freeIntRegsScoreboard[i] = 0;
- }
+ DPRINTF(FreeList, "Creating new free list object.\n");
// Put all of the extra physical registers onto the free list. This
// means excluding all of the base logical registers.
- for (PhysRegIndex i = numLogicalIntRegs;
+ for (PhysRegIndex i = numLogicalIntRegs * activeThreads;
i < numPhysicalIntRegs; ++i)
{
freeIntRegs.push(i);
-
- freeIntRegsScoreboard[i] = 1;
- }
-
- for (PhysRegIndex i = 0; i < numPhysicalIntRegs + numLogicalFloatRegs;
- ++i)
- {
- freeFloatRegsScoreboard[i] = 0;
}
// Put all of the extra physical registers onto the free list. This
// means excluding all of the base logical registers. Because the
// float registers' indices start where the physical registers end,
// some math must be done to determine where the free registers start.
- for (PhysRegIndex i = numPhysicalIntRegs + numLogicalFloatRegs;
- i < numPhysicalRegs; ++i)
+ PhysRegIndex i = numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads);
+
+ for ( ; i < numPhysicalRegs; ++i)
{
freeFloatRegs.push(i);
-
- freeFloatRegsScoreboard[i] = 1;
}
}
+std::string
+SimpleFreeList::name() const
+{
+ return "cpu.freelist";
+}
diff --git a/src/cpu/o3/free_list.hh b/src/cpu/o3/free_list.hh
index 0b85dba1e..c669b0b34 100644
--- a/src/cpu/o3/free_list.hh
+++ b/src/cpu/o3/free_list.hh
@@ -24,15 +24,18 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_FREE_LIST_HH__
-#define __CPU_O3_CPU_FREE_LIST_HH__
+#ifndef __CPU_O3_FREE_LIST_HH__
+#define __CPU_O3_FREE_LIST_HH__
#include <iostream>
#include <queue>
#include "arch/isa_traits.hh"
+#include "base/misc.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "cpu/o3/comm.hh"
@@ -45,10 +48,9 @@
* other classes, it assumes that the indices for the floating point
* registers starts after the integer registers end. Hence the variable
* numPhysicalIntRegs is logically equivalent to the baseFP dependency.
- * Note that
- * while this most likely should be called FreeList, the name "FreeList"
- * is used in a typedef within the CPU Policy, and therefore no class
- * can be named simply "FreeList".
+ * Note that while this most likely should be called FreeList, the name
+ * "FreeList" is used in a typedef within the CPU Policy, and therefore no
+ * class can be named simply "FreeList".
* @todo: Give a better name to the base FP dependency.
*/
class SimpleFreeList
@@ -75,36 +77,51 @@ class SimpleFreeList
/** Total number of physical registers. */
int numPhysicalRegs;
- /** DEBUG stuff below. */
- std::vector<int> freeIntRegsScoreboard;
-
- std::vector<bool> freeFloatRegsScoreboard;
-
public:
- SimpleFreeList(unsigned _numLogicalIntRegs,
+ /** Constructs a free list.
+ * @param activeThreads Number of active threads.
+ * @param _numLogicalIntRegs Number of logical integer registers.
+ * @param _numPhysicalIntRegs Number of physical integer registers.
+ * @param _numLogicalFloatRegs Number of logical fp registers.
+ * @param _numPhysicalFloatRegs Number of physical fp registers.
+ */
+ SimpleFreeList(unsigned activeThreads,
+ unsigned _numLogicalIntRegs,
unsigned _numPhysicalIntRegs,
unsigned _numLogicalFloatRegs,
unsigned _numPhysicalFloatRegs);
+ /** Gives the name of the freelist. */
+ std::string name() const;
+
+ /** Gets a free integer register. */
inline PhysRegIndex getIntReg();
+ /** Gets a free fp register. */
inline PhysRegIndex getFloatReg();
+ /** Adds a register back to the free list. */
inline void addReg(PhysRegIndex freed_reg);
+ /** Adds an integer register back to the free list. */
inline void addIntReg(PhysRegIndex freed_reg);
+ /** Adds a fp register back to the free list. */
inline void addFloatReg(PhysRegIndex freed_reg);
+ /** Checks if there are any free integer registers. */
bool hasFreeIntRegs()
{ return !freeIntRegs.empty(); }
+ /** Checks if there are any free fp registers. */
bool hasFreeFloatRegs()
{ return !freeFloatRegs.empty(); }
+ /** Returns the number of free integer registers. */
int numFreeIntRegs()
{ return freeIntRegs.size(); }
+ /** Returns the number of free fp registers. */
int numFreeFloatRegs()
{ return freeFloatRegs.size(); }
};
@@ -112,7 +129,8 @@ class SimpleFreeList
inline PhysRegIndex
SimpleFreeList::getIntReg()
{
- DPRINTF(Rename, "FreeList: Trying to get free integer register.\n");
+ DPRINTF(FreeList, "Trying to get free integer register.\n");
+
if (freeIntRegs.empty()) {
panic("No free integer registers!");
}
@@ -121,17 +139,14 @@ SimpleFreeList::getIntReg()
freeIntRegs.pop();
- // DEBUG
- assert(freeIntRegsScoreboard[free_reg]);
- freeIntRegsScoreboard[free_reg] = 0;
-
return(free_reg);
}
inline PhysRegIndex
SimpleFreeList::getFloatReg()
{
- DPRINTF(Rename, "FreeList: Trying to get free float register.\n");
+ DPRINTF(FreeList, "Trying to get free float register.\n");
+
if (freeFloatRegs.empty()) {
panic("No free integer registers!");
}
@@ -140,42 +155,28 @@ SimpleFreeList::getFloatReg()
freeFloatRegs.pop();
- // DEBUG
- assert(freeFloatRegsScoreboard[free_reg]);
- freeFloatRegsScoreboard[free_reg] = 0;
-
return(free_reg);
}
inline void
SimpleFreeList::addReg(PhysRegIndex freed_reg)
{
- DPRINTF(Rename, "Freelist: Freeing register %i.\n", freed_reg);
+ DPRINTF(FreeList,"Freeing register %i.\n", freed_reg);
//Might want to add in a check for whether or not this register is
//already in there. A bit vector or something similar would be useful.
if (freed_reg < numPhysicalIntRegs) {
- freeIntRegs.push(freed_reg);
-
- // DEBUG
- assert(freeIntRegsScoreboard[freed_reg] == false);
- freeIntRegsScoreboard[freed_reg] = 1;
+ if (freed_reg != TheISA::ZeroReg)
+ freeIntRegs.push(freed_reg);
} else if (freed_reg < numPhysicalRegs) {
- freeFloatRegs.push(freed_reg);
-
- // DEBUG
- assert(freeFloatRegsScoreboard[freed_reg] == false);
- freeFloatRegsScoreboard[freed_reg] = 1;
+ if (freed_reg != (TheISA::ZeroReg + numPhysicalIntRegs))
+ freeFloatRegs.push(freed_reg);
}
}
inline void
SimpleFreeList::addIntReg(PhysRegIndex freed_reg)
{
- DPRINTF(Rename, "Freelist: Freeing int register %i.\n", freed_reg);
-
- // DEBUG
- assert(!freeIntRegsScoreboard[freed_reg]);
- freeIntRegsScoreboard[freed_reg] = 1;
+ DPRINTF(FreeList,"Freeing int register %i.\n", freed_reg);
freeIntRegs.push(freed_reg);
}
@@ -183,13 +184,9 @@ SimpleFreeList::addIntReg(PhysRegIndex freed_reg)
inline void
SimpleFreeList::addFloatReg(PhysRegIndex freed_reg)
{
- DPRINTF(Rename, "Freelist: Freeing float register %i.\n", freed_reg);
-
- // DEBUG
- assert(!freeFloatRegsScoreboard[freed_reg]);
- freeFloatRegsScoreboard[freed_reg] = 1;
+ DPRINTF(FreeList,"Freeing float register %i.\n", freed_reg);
freeFloatRegs.push(freed_reg);
}
-#endif // __CPU_O3_CPU_FREE_LIST_HH__
+#endif // __CPU_O3_FREE_LIST_HH__
diff --git a/src/cpu/o3/fu_pool.cc b/src/cpu/o3/fu_pool.cc
new file mode 100644
index 000000000..42e329aca
--- /dev/null
+++ b/src/cpu/o3/fu_pool.cc
@@ -0,0 +1,299 @@
+/*
+ * 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
+ */
+
+#include <sstream>
+
+#include "cpu/o3/fu_pool.hh"
+#include "cpu/func_unit.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+////////////////////////////////////////////////////////////////////////////
+//
+// A pool of function units
+//
+
+inline void
+FUPool::FUIdxQueue::addFU(int fu_idx)
+{
+ funcUnitsIdx.push_back(fu_idx);
+ ++size;
+}
+
+inline int
+FUPool::FUIdxQueue::getFU()
+{
+ int retval = funcUnitsIdx[idx++];
+
+ if (idx == size)
+ idx = 0;
+
+ return retval;
+}
+
+FUPool::~FUPool()
+{
+ fuListIterator i = funcUnits.begin();
+ fuListIterator end = funcUnits.end();
+ for (; i != end; ++i)
+ delete *i;
+}
+
+
+// Constructor
+FUPool::FUPool(string name, vector<FUDesc *> paramList)
+ : SimObject(name)
+{
+ numFU = 0;
+
+ funcUnits.clear();
+
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ maxOpLatencies[i] = 0;
+ maxIssueLatencies[i] = 0;
+ }
+
+ //
+ // Iterate through the list of FUDescData structures
+ //
+ for (FUDDiterator i = paramList.begin(); i != paramList.end(); ++i) {
+
+ //
+ // Don't bother with this if we're not going to create any FU's
+ //
+ if ((*i)->number) {
+ //
+ // Create the FuncUnit object from this structure
+ // - add the capabilities listed in the FU's operation
+ // description
+ //
+ // We create the first unit, then duplicate it as needed
+ //
+ FuncUnit *fu = new FuncUnit;
+
+ OPDDiterator j = (*i)->opDescList.begin();
+ OPDDiterator end = (*i)->opDescList.end();
+ for (; j != end; ++j) {
+ // indicate that this pool has this capability
+ capabilityList.set((*j)->opClass);
+
+ // Add each of the FU's that will have this capability to the
+ // appropriate queue.
+ for (int k = 0; k < (*i)->number; ++k)
+ fuPerCapList[(*j)->opClass].addFU(numFU + k);
+
+ // indicate that this FU has the capability
+ fu->addCapability((*j)->opClass, (*j)->opLat, (*j)->issueLat);
+
+ if ((*j)->opLat > maxOpLatencies[(*j)->opClass])
+ maxOpLatencies[(*j)->opClass] = (*j)->opLat;
+
+ if ((*j)->issueLat > maxIssueLatencies[(*j)->opClass])
+ maxIssueLatencies[(*j)->opClass] = (*j)->issueLat;
+ }
+
+ numFU++;
+
+ // Add the appropriate number of copies of this FU to the list
+ ostringstream s;
+
+ s << (*i)->name() << "(0)";
+ fu->name = s.str();
+ funcUnits.push_back(fu);
+
+ for (int c = 1; c < (*i)->number; ++c) {
+ ostringstream s;
+ numFU++;
+ FuncUnit *fu2 = new FuncUnit(*fu);
+
+ s << (*i)->name() << "(" << c << ")";
+ fu2->name = s.str();
+ funcUnits.push_back(fu2);
+ }
+ }
+ }
+
+ unitBusy.resize(numFU);
+
+ for (int i = 0; i < numFU; i++) {
+ unitBusy[i] = false;
+ }
+}
+
+void
+FUPool::annotateMemoryUnits(unsigned hit_latency)
+{
+ maxOpLatencies[MemReadOp] = hit_latency;
+
+ fuListIterator i = funcUnits.begin();
+ fuListIterator iend = funcUnits.end();
+ for (; i != iend; ++i) {
+ if ((*i)->provides(MemReadOp))
+ (*i)->opLatency(MemReadOp) = hit_latency;
+
+ if ((*i)->provides(MemWriteOp))
+ (*i)->opLatency(MemWriteOp) = hit_latency;
+ }
+}
+
+int
+FUPool::getUnit(OpClass capability)
+{
+ // If this pool doesn't have the specified capability,
+ // return this information to the caller
+ if (!capabilityList[capability])
+ return -2;
+
+ int fu_idx = fuPerCapList[capability].getFU();
+ int start_idx = fu_idx;
+
+ // Iterate through the circular queue if needed, stopping if we've reached
+ // the first element again.
+ while (unitBusy[fu_idx]) {
+ fu_idx = fuPerCapList[capability].getFU();
+ if (fu_idx == start_idx) {
+ // No FU available
+ return -1;
+ }
+ }
+
+ assert(fu_idx < numFU);
+
+ unitBusy[fu_idx] = true;
+
+ return fu_idx;
+}
+
+void
+FUPool::freeUnitNextCycle(int fu_idx)
+{
+ assert(unitBusy[fu_idx]);
+ unitsToBeFreed.push_back(fu_idx);
+}
+
+void
+FUPool::processFreeUnits()
+{
+ while (!unitsToBeFreed.empty()) {
+ int fu_idx = unitsToBeFreed.back();
+ unitsToBeFreed.pop_back();
+
+ assert(unitBusy[fu_idx]);
+
+ unitBusy[fu_idx] = false;
+ }
+}
+
+void
+FUPool::dump()
+{
+ cout << "Function Unit Pool (" << name() << ")\n";
+ cout << "======================================\n";
+ cout << "Free List:\n";
+
+ for (int i = 0; i < numFU; ++i) {
+ if (unitBusy[i]) {
+ continue;
+ }
+
+ cout << " [" << i << "] : ";
+
+ cout << funcUnits[i]->name << " ";
+
+ cout << "\n";
+ }
+
+ cout << "======================================\n";
+ cout << "Busy List:\n";
+ for (int i = 0; i < numFU; ++i) {
+ if (!unitBusy[i]) {
+ continue;
+ }
+
+ cout << " [" << i << "] : ";
+
+ cout << funcUnits[i]->name << " ";
+
+ cout << "\n";
+ }
+}
+
+void
+FUPool::switchOut()
+{
+}
+
+void
+FUPool::takeOverFrom()
+{
+ for (int i = 0; i < numFU; i++) {
+ unitBusy[i] = false;
+ }
+ unitsToBeFreed.clear();
+}
+
+//
+
+////////////////////////////////////////////////////////////////////////////
+//
+// The SimObjects we use to get the FU information into the simulator
+//
+////////////////////////////////////////////////////////////////////////////
+
+//
+// FUPool - Contails a list of FUDesc objects to make available
+//
+
+//
+// The FuPool object
+//
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(FUPool)
+
+ SimObjectVectorParam<FUDesc *> FUList;
+
+END_DECLARE_SIM_OBJECT_PARAMS(FUPool)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(FUPool)
+
+ INIT_PARAM(FUList, "list of FU's for this pool")
+
+END_INIT_SIM_OBJECT_PARAMS(FUPool)
+
+
+CREATE_SIM_OBJECT(FUPool)
+{
+ return new FUPool(getInstanceName(), FUList);
+}
+
+REGISTER_SIM_OBJECT("FUPool", FUPool)
+
diff --git a/src/cpu/o3/fu_pool.hh b/src/cpu/o3/fu_pool.hh
new file mode 100644
index 000000000..52d83f056
--- /dev/null
+++ b/src/cpu/o3/fu_pool.hh
@@ -0,0 +1,167 @@
+/*
+ * 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_O3_FU_POOL_HH__
+#define __CPU_O3_FU_POOL_HH__
+
+#include <bitset>
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/sched_list.hh"
+#include "cpu/op_class.hh"
+#include "sim/sim_object.hh"
+
+class FUDesc;
+class FuncUnit;
+
+/**
+ * Pool of FU's, specific to the new CPU model. The old FU pool had lists of
+ * free units and busy units, and whenever a FU was needed it would iterate
+ * through the free units to find a FU that provided the capability. This pool
+ * has lists of units specific to each of the capabilities, and whenever a FU
+ * is needed, it iterates through that list to find a free unit. The previous
+ * FU pool would have to be ticked each cycle to update which units became
+ * free. This FU pool lets the IEW stage handle freeing units, which frees
+ * them as their scheduled execution events complete. This limits units in this
+ * model to either have identical issue and op latencies, or 1 cycle issue
+ * latencies.
+ */
+class FUPool : public SimObject
+{
+ private:
+ /** Maximum op execution latencies, per op class. */
+ unsigned maxOpLatencies[Num_OpClasses];
+ /** Maximum issue latencies, per op class. */
+ unsigned maxIssueLatencies[Num_OpClasses];
+
+ /** Bitvector listing capabilities of this FU pool. */
+ std::bitset<Num_OpClasses> capabilityList;
+
+ /** Bitvector listing which FUs are busy. */
+ std::vector<bool> unitBusy;
+
+ /** List of units to be freed at the end of this cycle. */
+ std::vector<int> unitsToBeFreed;
+
+ /**
+ * Class that implements a circular queue to hold FU indices. The hope is
+ * that FUs that have been just used will be moved to the end of the queue
+ * by iterating through it, thus leaving free units at the head of the
+ * queue.
+ */
+ class FUIdxQueue {
+ public:
+ /** Constructs a circular queue of FU indices. */
+ FUIdxQueue()
+ : idx(0), size(0)
+ { }
+
+ /** Adds a FU to the queue. */
+ inline void addFU(int fu_idx);
+
+ /** Returns the index of the FU at the head of the queue, and changes
+ * the index to the next element.
+ */
+ inline int getFU();
+
+ private:
+ /** Circular queue index. */
+ int idx;
+
+ /** Size of the queue. */
+ int size;
+
+ /** Queue of FU indices. */
+ std::vector<int> funcUnitsIdx;
+ };
+
+ /** Per op class queues of FUs that provide that capability. */
+ FUIdxQueue fuPerCapList[Num_OpClasses];
+
+ /** Number of FUs. */
+ int numFU;
+
+ /** Functional units. */
+ std::vector<FuncUnit *> funcUnits;
+
+ typedef std::vector<FuncUnit *>::iterator fuListIterator;
+
+ public:
+
+ /** Constructs a FU pool. */
+ FUPool(std::string name, std::vector<FUDesc *> l);
+ ~FUPool();
+
+ /** Annotates units that provide memory operations. Included only because
+ * old FU pool provided this function.
+ */
+ void annotateMemoryUnits(unsigned hit_latency);
+
+ /**
+ * Gets a FU providing the requested capability. Will mark the unit as busy,
+ * but leaves the freeing of the unit up to the IEW stage.
+ * @param capability The capability requested.
+ * @return Returns -2 if the FU pool does not have the capability, -1 if
+ * there is no free FU, and the FU's index otherwise.
+ */
+ int getUnit(OpClass capability);
+
+ /** Frees a FU at the end of this cycle. */
+ void freeUnitNextCycle(int fu_idx);
+
+ /** Frees all FUs on the list. */
+ void processFreeUnits();
+
+ /** Returns the total number of FUs. */
+ int size() { return numFU; }
+
+ /** Debugging function used to dump FU information. */
+ void dump();
+
+ /** Returns the operation execution latency of the given capability. */
+ unsigned getOpLatency(OpClass capability) {
+ return maxOpLatencies[capability];
+ }
+
+ /** Returns the issue latency of the given capability. */
+ unsigned getIssueLatency(OpClass capability) {
+ return maxIssueLatencies[capability];
+ }
+
+ /** Switches out functional unit pool. */
+ void switchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+};
+
+#endif // __CPU_O3_FU_POOL_HH__
diff --git a/src/cpu/o3/iew.cc b/src/cpu/o3/iew.cc
index 45b5610e7..f99be7fe0 100644
--- a/src/cpu/o3/iew.cc
+++ b/src/cpu/o3/iew.cc
@@ -24,11 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/iew_impl.hh"
#include "cpu/o3/inst_queue.hh"
-template class SimpleIEW<AlphaSimpleImpl>;
+template class DefaultIEW<O3CPUImpl>;
diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh
index 1e370d4e6..2af68d8fc 100644
--- a/src/cpu/o3/iew.hh
+++ b/src/cpu/o3/iew.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,113 +24,265 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-//Todo: Update with statuses.
-//Need to handle delaying writes to the writeback bus if it's full at the
-//given time.
-
-#ifndef __CPU_O3_CPU_SIMPLE_IEW_HH__
-#define __CPU_O3_CPU_SIMPLE_IEW_HH__
+#ifndef __CPU_O3_IEW_HH__
+#define __CPU_O3_IEW_HH__
#include <queue>
-#include "config/full_system.hh"
#include "base/statistics.hh"
#include "base/timebuf.hh"
+#include "config/full_system.hh"
#include "cpu/o3/comm.hh"
-
+#include "cpu/o3/scoreboard.hh"
+#include "cpu/o3/lsq.hh"
+
+class FUPool;
+
+/**
+ * DefaultIEW handles both single threaded and SMT IEW
+ * (issue/execute/writeback). It handles the dispatching of
+ * instructions to the LSQ/IQ as part of the issue stage, and has the
+ * IQ try to issue instructions each cycle. The execute latency is
+ * actually tied into the issue latency to allow the IQ to be able to
+ * do back-to-back scheduling without having to speculatively schedule
+ * instructions. This happens by having the IQ have access to the
+ * functional units, and the IQ gets the execution latencies from the
+ * FUs when it issues instructions. Instructions reach the execute
+ * stage on the last cycle of their execution, which is when the IQ
+ * knows to wake up any dependent instructions, allowing back to back
+ * scheduling. The execute portion of IEW separates memory
+ * instructions from non-memory instructions, either telling the LSQ
+ * to execute the instruction, or executing the instruction directly.
+ * The writeback portion of IEW completes the instructions by waking
+ * up any dependents, and marking the register ready on the
+ * scoreboard.
+ */
template<class Impl>
-class SimpleIEW
+class DefaultIEW
{
private:
//Typedefs from Impl
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::Params Params;
typedef typename CPUPol::IQ IQ;
typedef typename CPUPol::RenameMap RenameMap;
- typedef typename CPUPol::LDSTQ LDSTQ;
+ typedef typename CPUPol::LSQ LSQ;
typedef typename CPUPol::TimeStruct TimeStruct;
typedef typename CPUPol::IEWStruct IEWStruct;
typedef typename CPUPol::RenameStruct RenameStruct;
typedef typename CPUPol::IssueStruct IssueStruct;
- friend class Impl::FullCPU;
+ friend class Impl::O3CPU;
+ friend class CPUPol::IQ;
+
public:
+ /** Overall IEW stage status. Used to determine if the CPU can
+ * deschedule itself due to a lack of activity.
+ */
enum Status {
+ Active,
+ Inactive
+ };
+
+ /** Status for Issue, Execute, and Writeback stages. */
+ enum StageStatus {
Running,
Blocked,
Idle,
+ StartSquash,
Squashing,
Unblocking
};
private:
+ /** Overall stage status. */
Status _status;
- Status _issueStatus;
- Status _exeStatus;
- Status _wbStatus;
+ /** Dispatch status. */
+ StageStatus dispatchStatus[Impl::MaxThreads];
+ /** Execute status. */
+ StageStatus exeStatus;
+ /** Writeback status. */
+ StageStatus wbStatus;
public:
- class WritebackEvent : public Event {
- private:
- DynInstPtr inst;
- SimpleIEW<Impl> *iewStage;
+ /** Constructs a DefaultIEW with the given parameters. */
+ DefaultIEW(Params *params);
- public:
- WritebackEvent(DynInstPtr &_inst, SimpleIEW<Impl> *_iew);
-
- virtual void process();
- virtual const char *description();
- };
-
- public:
- SimpleIEW(Params &params);
+ /** Returns the name of the DefaultIEW stage. */
+ std::string name() const;
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu_ptr);
+ /** Initializes stage; sends back the number of free IQ and LSQ entries. */
+ void initStage();
+ /** Sets CPU pointer for IEW, IQ, and LSQ. */
+ void setCPU(O3CPU *cpu_ptr);
+
+ /** Sets main time buffer used for backwards communication. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+ /** Sets time buffer for getting instructions coming from rename. */
void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+ /** Sets time buffer to pass on instructions to commit. */
void setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr);
- void setRenameMap(RenameMap *rm_ptr);
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Sets pointer to the scoreboard. */
+ void setScoreboard(Scoreboard *sb_ptr);
- void squash();
+ /** Starts switch out of IEW stage. */
+ void switchOut();
- void squashDueToBranch(DynInstPtr &inst);
+ /** Completes switch out of IEW stage. */
+ void doSwitchOut();
- void squashDueToMem(DynInstPtr &inst);
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
- void block();
+ /** Returns if IEW is switched out. */
+ bool isSwitchedOut() { return switchedOut; }
- inline void unblock();
+ /** Squashes instructions in IEW for a specific thread. */
+ void squash(unsigned tid);
+ /** Wakes all dependents of a completed instruction. */
void wakeDependents(DynInstPtr &inst);
+ /** Tells memory dependence unit that a memory instruction needs to be
+ * rescheduled. It will re-execute once replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &inst);
+
+ /** Re-executes all rescheduled memory instructions. */
+ void replayMemInst(DynInstPtr &inst);
+
+ /** Sends an instruction to commit through the time buffer. */
void instToCommit(DynInstPtr &inst);
+ /** Inserts unused instructions of a thread into the skid buffer. */
+ void skidInsert(unsigned tid);
+
+ /** Returns the max of the number of entries in all of the skid buffers. */
+ int skidCount();
+
+ /** Returns if all of the skid buffers are empty. */
+ bool skidsEmpty();
+
+ /** Updates overall IEW status based on all of the stages' statuses. */
+ void updateStatus();
+
+ /** Resets entries of the IQ and the LSQ. */
+ void resetEntries();
+
+ /** Tells the CPU to wakeup if it has descheduled itself due to no
+ * activity. Used mainly by the LdWritebackEvent.
+ */
+ void wakeCPU();
+
+ /** Reports to the CPU that there is activity this cycle. */
+ void activityThisCycle();
+
+ /** Tells CPU that the IEW stage is active and running. */
+ inline void activateStage();
+
+ /** Tells CPU that the IEW stage is inactive and idle. */
+ inline void deactivateStage();
+
+ /** Returns if the LSQ has any stores to writeback. */
+ bool hasStoresToWB() { return ldstQueue.hasStoresToWB(); }
+
private:
- void dispatchInsts();
+ /** Sends commit proper information for a squash due to a branch
+ * mispredict.
+ */
+ void squashDueToBranch(DynInstPtr &inst, unsigned thread_id);
+ /** Sends commit proper information for a squash due to a memory order
+ * violation.
+ */
+ void squashDueToMemOrder(DynInstPtr &inst, unsigned thread_id);
+
+ /** Sends commit proper information for a squash due to memory becoming
+ * blocked (younger issued instructions must be retried).
+ */
+ void squashDueToMemBlocked(DynInstPtr &inst, unsigned thread_id);
+
+ /** Sets Dispatch to blocked, and signals back to other stages to block. */
+ void block(unsigned thread_id);
+
+ /** Unblocks Dispatch if the skid buffer is empty, and signals back to
+ * other stages to unblock.
+ */
+ void unblock(unsigned thread_id);
+
+ /** Determines proper actions to take given Dispatch's status. */
+ void dispatch(unsigned tid);
+
+ /** Dispatches instructions to IQ and LSQ. */
+ void dispatchInsts(unsigned tid);
+
+ /** Executes instructions. In the case of memory operations, it informs the
+ * LSQ to execute the instructions. Also handles any redirects that occur
+ * due to the executed instructions.
+ */
void executeInsts();
+ /** Writebacks instructions. In our model, the instruction's execute()
+ * function atomically reads registers, executes, and writes registers.
+ * Thus this writeback only wakes up dependent instructions, and informs
+ * the scoreboard of registers becoming ready.
+ */
+ void writebackInsts();
+
+ /** Returns the number of valid, non-squashed instructions coming from
+ * rename to dispatch.
+ */
+ unsigned validInstsFromRename();
+
+ /** Reads the stall signals. */
+ void readStallSignals(unsigned tid);
+
+ /** Checks if any of the stall conditions are currently true. */
+ bool checkStall(unsigned tid);
+
+ /** Processes inputs and changes state accordingly. */
+ void checkSignalsAndUpdate(unsigned tid);
+
+ /** Removes instructions from rename from a thread's instruction list. */
+ void emptyRenameInsts(unsigned tid);
+
+ /** Sorts instructions coming from rename into lists separated by thread. */
+ void sortInsts();
+
public:
+ /** Ticks IEW stage, causing Dispatch, the IQ, the LSQ, Execute, and
+ * Writeback to run for one cycle.
+ */
void tick();
- void iew();
+ private:
+ /** Updates execution stats based on the instruction. */
+ void updateExeInstStats(DynInstPtr &inst);
- //Interfaces to objects inside and outside of IEW.
- /** Time buffer interface. */
+ /** Pointer to main time buffer used for backwards communication. */
TimeBuffer<TimeStruct> *timeBuffer;
+ /** Wire to write information heading to previous stages. */
+ typename TimeBuffer<TimeStruct>::wire toFetch;
+
/** Wire to get commit's output from backwards time buffer. */
typename TimeBuffer<TimeStruct>::wire fromCommit;
@@ -158,32 +310,67 @@ class SimpleIEW
/** Wire to write infromation heading to commit. */
typename TimeBuffer<IEWStruct>::wire toCommit;
- //Will need internal queue to hold onto instructions coming from
- //the rename stage in case of a stall.
+ /** Queue of all instructions coming from rename this cycle. */
+ std::queue<DynInstPtr> insts[Impl::MaxThreads];
+
/** Skid buffer between rename and IEW. */
- std::queue<RenameStruct> skidBuffer;
+ std::queue<DynInstPtr> skidBuffer[Impl::MaxThreads];
+
+ /** Scoreboard pointer. */
+ Scoreboard* scoreboard;
- protected:
+ public:
/** Instruction queue. */
IQ instQueue;
- LDSTQ ldstQueue;
+ /** Load / store queue. */
+ LSQ ldstQueue;
-#if !FULL_SYSTEM
- public:
- void lsqWriteback();
-#endif
+ /** Pointer to the functional unit pool. */
+ FUPool *fuPool;
private:
- /** Pointer to rename map. Might not want this stage to directly
- * access this though...
+ /** CPU pointer. */
+ O3CPU *cpu;
+
+ /** Records if IEW has written to the time buffer this cycle, so that the
+ * CPU can deschedule itself if there is no activity.
*/
- RenameMap *renameMap;
+ bool wroteToTimeBuffer;
+
+ /** Source of possible stalls. */
+ struct Stalls {
+ bool commit;
+ };
- /** CPU interface. */
- FullCPU *cpu;
+ /** Stages that are telling IEW to stall. */
+ Stalls stalls[Impl::MaxThreads];
+
+ /** Debug function to print instructions that are issued this cycle. */
+ void printAvailableInsts();
+
+ public:
+ /** Records if the LSQ needs to be updated on the next cycle, so that
+ * IEW knows if there will be activity on the next cycle.
+ */
+ bool updateLSQNextCycle;
private:
+ /** Records if there is a fetch redirect on this cycle for each thread. */
+ bool fetchRedirect[Impl::MaxThreads];
+
+ /** Used to track if all instructions have been dispatched this cycle.
+ * If they have not, then blocking must have occurred, and the instructions
+ * would already be added to the skid buffer.
+ * @todo: Fix this hack.
+ */
+ bool dispatchedAllInsts;
+
+ /** Records if the queues have been changed (inserted or issued insts),
+ * so that IEW knows to broadcast the updated amount of free entries.
+ */
+ bool updatedQueues;
+
/** Commit to IEW delay, in ticks. */
unsigned commitToIEWDelay;
@@ -206,34 +393,96 @@ class SimpleIEW
/** Width of issue, in instructions. */
unsigned issueWidth;
- /** Width of execute, in instructions. Might make more sense to break
- * down into FP vs int.
- */
- unsigned executeWidth;
+ /** Index into queue of instructions being written back. */
+ unsigned wbNumInst;
- /** Number of cycles stage has been squashing. Used so that the stage
- * knows when it can start unblocking, which is when the previous stage
- * has received the stall signal and clears up its outputs.
+ /** Cycle number within the queue of instructions being written back.
+ * Used in case there are too many instructions writing back at the current
+ * cycle and writesbacks need to be scheduled for the future. See comments
+ * in instToCommit().
*/
- unsigned cyclesSquashing;
+ unsigned wbCycle;
+ /** Number of active threads. */
+ unsigned numThreads;
+
+ /** Pointer to list of active threads. */
+ std::list<unsigned> *activeThreads;
+
+ /** Maximum size of the skid buffer. */
+ unsigned skidBufferMax;
+
+ /** Is this stage switched out. */
+ bool switchedOut;
+
+ /** Stat for total number of idle cycles. */
Stats::Scalar<> iewIdleCycles;
+ /** Stat for total number of squashing cycles. */
Stats::Scalar<> iewSquashCycles;
+ /** Stat for total number of blocking cycles. */
Stats::Scalar<> iewBlockCycles;
+ /** Stat for total number of unblocking cycles. */
Stats::Scalar<> iewUnblockCycles;
-// Stats::Scalar<> iewWBInsts;
+ /** Stat for total number of instructions dispatched. */
Stats::Scalar<> iewDispatchedInsts;
+ /** Stat for total number of squashed instructions dispatch skips. */
Stats::Scalar<> iewDispSquashedInsts;
+ /** Stat for total number of dispatched load instructions. */
Stats::Scalar<> iewDispLoadInsts;
+ /** Stat for total number of dispatched store instructions. */
Stats::Scalar<> iewDispStoreInsts;
+ /** Stat for total number of dispatched non speculative instructions. */
Stats::Scalar<> iewDispNonSpecInsts;
+ /** Stat for number of times the IQ becomes full. */
Stats::Scalar<> iewIQFullEvents;
- Stats::Scalar<> iewExecutedInsts;
- Stats::Scalar<> iewExecLoadInsts;
- Stats::Scalar<> iewExecStoreInsts;
- Stats::Scalar<> iewExecSquashedInsts;
+ /** Stat for number of times the LSQ becomes full. */
+ Stats::Scalar<> iewLSQFullEvents;
+ /** Stat for total number of memory ordering violation events. */
Stats::Scalar<> memOrderViolationEvents;
+ /** Stat for total number of incorrect predicted taken branches. */
Stats::Scalar<> predictedTakenIncorrect;
+ /** Stat for total number of incorrect predicted not taken branches. */
+ 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;
+ /** Stat for total number of executed load instructions. */
+ Stats::Vector<> iewExecLoadInsts;
+ /** Stat for total number of squashed instructions skipped at execute. */
+ Stats::Scalar<> iewExecSquashedInsts;
+ /** Number of executed software prefetches. */
+ Stats::Vector<> iewExecutedSwp;
+ /** Number of executed nops. */
+ Stats::Vector<> iewExecutedNop;
+ /** Number of executed meomory references. */
+ Stats::Vector<> iewExecutedRefs;
+ /** Number of executed branches. */
+ 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;
+ /** Number of instructions that writeback. */
+ Stats::Vector<> writebackCount;
+ /** Number of instructions that wake consumers. */
+ Stats::Vector<> producerInst;
+ /** Number of instructions that wake up from producers. */
+ Stats::Vector<> consumerInst;
+ /** Number of instructions that were delayed in writing back due
+ * to resource contention.
+ */
+ Stats::Vector<> wbPenalized;
+ /** Number of instructions per cycle written back. */
+ Stats::Formula wbRate;
+ /** Average number of woken instructions per writeback. */
+ Stats::Formula wbFanout;
+ /** Number of instructions per cycle delayed in writing back . */
+ Stats::Formula wbPenalizedRate;
};
-#endif // __CPU_O3_CPU_IEW_HH__
+#endif // __CPU_O3_IEW_HH__
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
index 85217dd10..8e6fd46a1 100644
--- a/src/cpu/o3/iew_impl.hh
+++ b/src/cpu/o3/iew_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,64 +24,40 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
// @todo: Fix the instantaneous communication among all the stages within
// iew. There's a clear delay between issue and execute, yet backwards
// communication happens simultaneously.
-// Update the statuses for each stage.
#include <queue>
#include "base/timebuf.hh"
+#include "cpu/o3/fu_pool.hh"
#include "cpu/o3/iew.hh"
-template<class Impl>
-SimpleIEW<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst,
- SimpleIEW<Impl> *_iew)
- : Event(&mainEventQueue, CPU_Tick_Pri), inst(_inst), iewStage(_iew)
-{
- this->setFlags(Event::AutoDelete);
-}
-
-template<class Impl>
-void
-SimpleIEW<Impl>::WritebackEvent::process()
-{
- DPRINTF(IEW, "IEW: WRITEBACK EVENT!!!!\n");
-
- // Need to insert instruction into queue to commit
- iewStage->instToCommit(inst);
- // Need to execute second half of the instruction, do actual writing to
- // registers and such
- inst->execute();
-}
-
-template<class Impl>
-const char *
-SimpleIEW<Impl>::WritebackEvent::description()
-{
- return "LSQ writeback event";
-}
+using namespace std;
template<class Impl>
-SimpleIEW<Impl>::SimpleIEW(Params &params)
- : // Just make this time buffer really big for now
+DefaultIEW<Impl>::DefaultIEW(Params *params)
+ : // @todo: Make this into a parameter.
issueToExecQueue(5, 5),
instQueue(params),
ldstQueue(params),
- commitToIEWDelay(params.commitToIEWDelay),
- renameToIEWDelay(params.renameToIEWDelay),
- issueToExecuteDelay(params.issueToExecuteDelay),
- issueReadWidth(params.issueWidth),
- issueWidth(params.issueWidth),
- executeWidth(params.executeWidth)
-{
- DPRINTF(IEW, "IEW: executeIntWidth: %i.\n", params.executeIntWidth);
- _status = Idle;
- _issueStatus = Idle;
- _exeStatus = Idle;
- _wbStatus = Idle;
+ fuPool(params->fuPool),
+ commitToIEWDelay(params->commitToIEWDelay),
+ renameToIEWDelay(params->renameToIEWDelay),
+ issueToExecuteDelay(params->issueToExecuteDelay),
+ issueReadWidth(params->issueWidth),
+ issueWidth(params->issueWidth),
+ numThreads(params->numberOfThreads),
+ switchedOut(false)
+{
+ _status = Active;
+ exeStatus = Running;
+ wbStatus = Idle;
// Setup wire to read instructions coming from issue.
fromIssue = issueToExecQueue.getWire(-issueToExecuteDelay);
@@ -89,14 +65,35 @@ SimpleIEW<Impl>::SimpleIEW(Params &params)
// Instruction queue needs the queue between issue and execute.
instQueue.setIssueToExecuteQueue(&issueToExecQueue);
+ instQueue.setIEW(this);
ldstQueue.setIEW(this);
+
+ for (int i=0; i < numThreads; i++) {
+ dispatchStatus[i] = Running;
+ stalls[i].commit = false;
+ fetchRedirect[i] = false;
+ }
+
+ updateLSQNextCycle = false;
+
+ skidBufferMax = (3 * (renameToIEWDelay * params->renameWidth)) + issueWidth;
+}
+
+template <class Impl>
+std::string
+DefaultIEW<Impl>::name() const
+{
+ return cpu->name() + ".iew";
}
template <class Impl>
void
-SimpleIEW<Impl>::regStats()
+DefaultIEW<Impl>::regStats()
{
+ using namespace Stats;
+
instQueue.regStats();
+ ldstQueue.regStats();
iewIdleCycles
.name(name() + ".iewIdleCycles")
@@ -114,8 +111,6 @@ SimpleIEW<Impl>::regStats()
.name(name() + ".iewUnblockCycles")
.desc("Number of cycles IEW is unblocking");
-// iewWBInsts;
-
iewDispatchedInsts
.name(name() + ".iewDispatchedInsts")
.desc("Number of instructions dispatched to IQ");
@@ -140,47 +135,163 @@ SimpleIEW<Impl>::regStats()
.name(name() + ".iewIQFullEvents")
.desc("Number of times the IQ has become full, causing a stall");
+ iewLSQFullEvents
+ .name(name() + ".iewLSQFullEvents")
+ .desc("Number of times the LSQ has become full, causing a stall");
+
+ memOrderViolationEvents
+ .name(name() + ".memOrderViolationEvents")
+ .desc("Number of memory order violations");
+
+ predictedTakenIncorrect
+ .name(name() + ".predictedTakenIncorrect")
+ .desc("Number of branches that were predicted taken incorrectly");
+
+ predictedNotTakenIncorrect
+ .name(name() + ".predictedNotTakenIncorrect")
+ .desc("Number of branches that were predicted not taken incorrectly");
+
+ branchMispredicts
+ .name(name() + ".branchMispredicts")
+ .desc("Number of branch mispredicts detected at execute");
+
+ branchMispredicts = predictedTakenIncorrect + predictedNotTakenIncorrect;
+
iewExecutedInsts
- .name(name() + ".iewExecutedInsts")
+ .name(name() + ".EXEC:insts")
.desc("Number of executed instructions");
iewExecLoadInsts
- .name(name() + ".iewExecLoadInsts")
- .desc("Number of load instructions executed");
-
- iewExecStoreInsts
- .name(name() + ".iewExecStoreInsts")
- .desc("Number of store instructions executed");
+ .init(cpu->number_of_threads)
+ .name(name() + ".EXEC:loads")
+ .desc("Number of load instructions executed")
+ .flags(total);
iewExecSquashedInsts
- .name(name() + ".iewExecSquashedInsts")
+ .name(name() + ".EXEC:squashedInsts")
.desc("Number of squashed instructions skipped in execute");
- memOrderViolationEvents
- .name(name() + ".memOrderViolationEvents")
- .desc("Number of memory order violations");
+ iewExecutedSwp
+ .init(cpu->number_of_threads)
+ .name(name() + ".EXEC:swp")
+ .desc("number of swp insts executed")
+ .flags(total);
+
+ iewExecutedNop
+ .init(cpu->number_of_threads)
+ .name(name() + ".EXEC:nop")
+ .desc("number of nop insts executed")
+ .flags(total);
+
+ iewExecutedRefs
+ .init(cpu->number_of_threads)
+ .name(name() + ".EXEC:refs")
+ .desc("number of memory reference insts executed")
+ .flags(total);
+
+ iewExecutedBranches
+ .init(cpu->number_of_threads)
+ .name(name() + ".EXEC:branches")
+ .desc("Number of branches executed")
+ .flags(total);
- predictedTakenIncorrect
- .name(name() + ".predictedTakenIncorrect")
- .desc("Number of branches that were predicted taken incorrectly");
+ iewExecStoreInsts
+ .name(name() + ".EXEC:stores")
+ .desc("Number of stores executed")
+ .flags(total);
+ iewExecStoreInsts = iewExecutedRefs - iewExecLoadInsts;
+
+ iewExecRate
+ .name(name() + ".EXEC:rate")
+ .desc("Inst execution rate")
+ .flags(total);
+
+ iewExecRate = iewExecutedInsts / cpu->numCycles;
+
+ iewInstsToCommit
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:sent")
+ .desc("cumulative count of insts sent to commit")
+ .flags(total);
+
+ writebackCount
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:count")
+ .desc("cumulative count of insts written-back")
+ .flags(total);
+
+ producerInst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:producers")
+ .desc("num instructions producing a value")
+ .flags(total);
+
+ consumerInst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:consumers")
+ .desc("num instructions consuming a value")
+ .flags(total);
+
+ wbPenalized
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:penalized")
+ .desc("number of instrctions required to write to 'other' IQ")
+ .flags(total);
+
+ wbPenalizedRate
+ .name(name() + ".WB:penalized_rate")
+ .desc ("fraction of instructions written-back that wrote to 'other' IQ")
+ .flags(total);
+
+ wbPenalizedRate = wbPenalized / writebackCount;
+
+ wbFanout
+ .name(name() + ".WB:fanout")
+ .desc("average fanout of values written-back")
+ .flags(total);
+
+ wbFanout = producerInst / consumerInst;
+
+ wbRate
+ .name(name() + ".WB:rate")
+ .desc("insts written-back per cycle")
+ .flags(total);
+ wbRate = writebackCount / cpu->numCycles;
}
template<class Impl>
void
-SimpleIEW<Impl>::setCPU(FullCPU *cpu_ptr)
+DefaultIEW<Impl>::initStage()
{
- DPRINTF(IEW, "IEW: Setting CPU pointer.\n");
+ for (int tid=0; tid < numThreads; tid++) {
+ toRename->iewInfo[tid].usedIQ = true;
+ toRename->iewInfo[tid].freeIQEntries =
+ instQueue.numFreeEntries(tid);
+
+ toRename->iewInfo[tid].usedLSQ = true;
+ toRename->iewInfo[tid].freeLSQEntries =
+ ldstQueue.numFreeEntries(tid);
+ }
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::setCPU(O3CPU *cpu_ptr)
+{
+ DPRINTF(IEW, "Setting CPU pointer.\n");
cpu = cpu_ptr;
instQueue.setCPU(cpu_ptr);
ldstQueue.setCPU(cpu_ptr);
+
+ cpu->activateStage(O3CPU::IEWIdx);
}
template<class Impl>
void
-SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+DefaultIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
- DPRINTF(IEW, "IEW: Setting time buffer pointer.\n");
+ DPRINTF(IEW, "Setting time buffer pointer.\n");
timeBuffer = tb_ptr;
// Setup wire to read information from time buffer, from commit.
@@ -189,15 +300,17 @@ SimpleIEW<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
// Setup wire to write information back to previous stages.
toRename = timeBuffer->getWire(0);
+ toFetch = timeBuffer->getWire(0);
+
// Instruction queue also needs main time buffer.
instQueue.setTimeBuffer(tb_ptr);
}
template<class Impl>
void
-SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+DefaultIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
{
- DPRINTF(IEW, "IEW: Setting rename queue pointer.\n");
+ DPRINTF(IEW, "Setting rename queue pointer.\n");
renameQueue = rq_ptr;
// Setup wire to read information from rename queue.
@@ -206,9 +319,9 @@ SimpleIEW<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
template<class Impl>
void
-SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
+DefaultIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
{
- DPRINTF(IEW, "IEW: Setting IEW queue pointer.\n");
+ DPRINTF(IEW, "Setting IEW queue pointer.\n");
iewQueue = iq_ptr;
// Setup wire to write instructions to commit.
@@ -217,355 +330,947 @@ SimpleIEW<Impl>::setIEWQueue(TimeBuffer<IEWStruct> *iq_ptr)
template<class Impl>
void
-SimpleIEW<Impl>::setRenameMap(RenameMap *rm_ptr)
+DefaultIEW<Impl>::setActiveThreads(list<unsigned> *at_ptr)
{
- DPRINTF(IEW, "IEW: Setting rename map pointer.\n");
- renameMap = rm_ptr;
+ DPRINTF(IEW, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+
+ ldstQueue.setActiveThreads(at_ptr);
+ instQueue.setActiveThreads(at_ptr);
}
template<class Impl>
void
-SimpleIEW<Impl>::squash()
+DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
+{
+ DPRINTF(IEW, "Setting scoreboard pointer.\n");
+ scoreboard = sb_ptr;
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::switchOut()
+{
+ // IEW is ready to switch out at any time.
+ cpu->signalSwitched();
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::doSwitchOut()
{
- DPRINTF(IEW, "IEW: Squashing all instructions.\n");
- _status = Squashing;
+ // Clear any state.
+ switchedOut = true;
+
+ instQueue.switchOut();
+ ldstQueue.switchOut();
+ fuPool->switchOut();
+
+ for (int i = 0; i < numThreads; i++) {
+ while (!insts[i].empty())
+ insts[i].pop();
+ while (!skidBuffer[i].empty())
+ skidBuffer[i].pop();
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::takeOverFrom()
+{
+ // Reset all state.
+ _status = Active;
+ exeStatus = Running;
+ wbStatus = Idle;
+ switchedOut = false;
+
+ instQueue.takeOverFrom();
+ ldstQueue.takeOverFrom();
+ fuPool->takeOverFrom();
+
+ initStage();
+ cpu->activityThisCycle();
+
+ for (int i=0; i < numThreads; i++) {
+ dispatchStatus[i] = Running;
+ stalls[i].commit = false;
+ fetchRedirect[i] = false;
+ }
+
+ updateLSQNextCycle = false;
+
+ // @todo: Fix hardcoded number
+ for (int i = 0; i < 6; ++i) {
+ issueToExecQueue.advance();
+ }
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::squash(unsigned tid)
+{
+ DPRINTF(IEW, "[tid:%i]: Squashing all instructions.\n",
+ tid);
// Tell the IQ to start squashing.
- instQueue.squash();
+ instQueue.squash(tid);
// Tell the LDSTQ to start squashing.
- ldstQueue.squash(fromCommit->commitInfo.doneSeqNum);
+ ldstQueue.squash(fromCommit->commitInfo[tid].doneSeqNum, tid);
+
+ updatedQueues = true;
+
+ // Clear the skid buffer in case it has any data in it.
+ while (!skidBuffer[tid].empty()) {
+
+ if (skidBuffer[tid].front()->isLoad() ||
+ skidBuffer[tid].front()->isStore() ) {
+ toRename->iewInfo[tid].dispatchedToLSQ++;
+ }
+
+ toRename->iewInfo[tid].dispatched++;
+
+ skidBuffer[tid].pop();
+ }
+
+ emptyRenameInsts(tid);
}
template<class Impl>
void
-SimpleIEW<Impl>::squashDueToBranch(DynInstPtr &inst)
-{
- DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
- inst->PC);
- // Perhaps leave the squashing up to the ROB stage to tell it when to
- // squash?
- _status = Squashing;
-
- // Tell rename to squash through the time buffer.
- toCommit->squash = true;
- // Also send PC update information back to prior stages.
- toCommit->squashedSeqNum = inst->seqNum;
- toCommit->mispredPC = inst->readPC();
- toCommit->nextPC = inst->readNextPC();
- toCommit->branchMispredict = true;
- // Prediction was incorrect, so send back inverse.
- toCommit->branchTaken = inst->readNextPC() !=
+DefaultIEW<Impl>::squashDueToBranch(DynInstPtr &inst, unsigned tid)
+{
+ DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, PC: %#x "
+ "[sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+
+ toCommit->squash[tid] = true;
+ toCommit->squashedSeqNum[tid] = inst->seqNum;
+ toCommit->mispredPC[tid] = inst->readPC();
+ toCommit->nextPC[tid] = inst->readNextPC();
+ toCommit->branchMispredict[tid] = true;
+ toCommit->branchTaken[tid] = inst->readNextPC() !=
(inst->readPC() + sizeof(TheISA::MachInst));
+
+ toCommit->includeSquashInst[tid] = false;
+
+ wroteToTimeBuffer = true;
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::squashDueToMemOrder(DynInstPtr &inst, unsigned tid)
+{
+ DPRINTF(IEW, "[tid:%i]: Squashing from a specific instruction, "
+ "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+
+ toCommit->squash[tid] = true;
+ toCommit->squashedSeqNum[tid] = inst->seqNum;
+ toCommit->nextPC[tid] = inst->readNextPC();
+
+ toCommit->includeSquashInst[tid] = false;
+
+ wroteToTimeBuffer = true;
}
template<class Impl>
void
-SimpleIEW<Impl>::squashDueToMem(DynInstPtr &inst)
+DefaultIEW<Impl>::squashDueToMemBlocked(DynInstPtr &inst, unsigned tid)
{
- DPRINTF(IEW, "IEW: Squashing from a specific instruction, PC: %#x.\n",
- inst->PC);
- // Perhaps leave the squashing up to the ROB stage to tell it when to
- // squash?
- _status = Squashing;
+ DPRINTF(IEW, "[tid:%i]: Memory blocked, squashing load and younger insts, "
+ "PC: %#x [sn:%i].\n", tid, inst->readPC(), inst->seqNum);
+
+ toCommit->squash[tid] = true;
+ toCommit->squashedSeqNum[tid] = inst->seqNum;
+ toCommit->nextPC[tid] = inst->readPC();
+
+ // Must include the broadcasted SN in the squash.
+ toCommit->includeSquashInst[tid] = true;
- // Tell rename to squash through the time buffer.
- toCommit->squash = true;
- // Also send PC update information back to prior stages.
- toCommit->squashedSeqNum = inst->seqNum;
- toCommit->nextPC = inst->readNextPC();
+ ldstQueue.setLoadBlockedHandled(tid);
+
+ wroteToTimeBuffer = true;
}
template<class Impl>
void
-SimpleIEW<Impl>::block()
+DefaultIEW<Impl>::block(unsigned tid)
{
- DPRINTF(IEW, "IEW: Blocking.\n");
- // Set the status to Blocked.
- _status = Blocked;
+ DPRINTF(IEW, "[tid:%u]: Blocking.\n", tid);
+
+ if (dispatchStatus[tid] != Blocked &&
+ dispatchStatus[tid] != Unblocking) {
+ toRename->iewBlock[tid] = true;
+ wroteToTimeBuffer = true;
+ }
// Add the current inputs to the skid buffer so they can be
// reprocessed when this stage unblocks.
- skidBuffer.push(*fromRename);
+ skidInsert(tid);
- // Note that this stage only signals previous stages to stall when
- // it is the cause of the stall originates at this stage. Otherwise
- // the previous stages are expected to check all possible stall signals.
+ dispatchStatus[tid] = Blocked;
}
template<class Impl>
-inline void
-SimpleIEW<Impl>::unblock()
+void
+DefaultIEW<Impl>::unblock(unsigned tid)
{
- // Check if there's information in the skid buffer. If there is, then
- // set status to unblocking, otherwise set it directly to running.
- DPRINTF(IEW, "IEW: Reading instructions out of the skid "
- "buffer.\n");
- // Remove the now processed instructions from the skid buffer.
- skidBuffer.pop();
-
- // If there's still information in the skid buffer, then
- // continue to tell previous stages to stall. They will be
- // able to restart once the skid buffer is empty.
- if (!skidBuffer.empty()) {
- toRename->iewInfo.stall = true;
- } else {
- DPRINTF(IEW, "IEW: Stage is done unblocking.\n");
- _status = Running;
+ DPRINTF(IEW, "[tid:%i]: Reading instructions out of the skid "
+ "buffer %u.\n",tid, tid);
+
+ // If the skid bufffer is empty, signal back to previous stages to unblock.
+ // Also switch status to running.
+ if (skidBuffer[tid].empty()) {
+ toRename->iewUnblock[tid] = true;
+ wroteToTimeBuffer = true;
+ DPRINTF(IEW, "[tid:%i]: Done unblocking.\n",tid);
+ dispatchStatus[tid] = Running;
}
}
template<class Impl>
void
-SimpleIEW<Impl>::wakeDependents(DynInstPtr &inst)
+DefaultIEW<Impl>::wakeDependents(DynInstPtr &inst)
{
instQueue.wakeDependents(inst);
}
+template<class Impl>
+void
+DefaultIEW<Impl>::rescheduleMemInst(DynInstPtr &inst)
+{
+ instQueue.rescheduleMemInst(inst);
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::replayMemInst(DynInstPtr &inst)
+{
+ instQueue.replayMemInst(inst);
+}
template<class Impl>
void
-SimpleIEW<Impl>::instToCommit(DynInstPtr &inst)
+DefaultIEW<Impl>::instToCommit(DynInstPtr &inst)
{
+ // First check the time slot that this instruction will write
+ // to. If there are free write ports at the time, then go ahead
+ // and write the instruction to that time. If there are not,
+ // keep looking back to see where's the first time there's a
+ // free slot.
+ while ((*iewQueue)[wbCycle].insts[wbNumInst]) {
+ ++wbNumInst;
+ if (wbNumInst == issueWidth) {
+ ++wbCycle;
+ wbNumInst = 0;
+ }
+ assert(wbCycle < 5);
+ }
+
+ // Add finished instruction to queue to commit.
+ (*iewQueue)[wbCycle].insts[wbNumInst] = inst;
+ (*iewQueue)[wbCycle].size++;
}
template <class Impl>
+unsigned
+DefaultIEW<Impl>::validInstsFromRename()
+{
+ unsigned inst_count = 0;
+
+ for (int i=0; i<fromRename->size; i++) {
+ if (!fromRename->insts[i]->isSquashed())
+ inst_count++;
+ }
+
+ return inst_count;
+}
+
+template<class Impl>
void
-SimpleIEW<Impl>::dispatchInsts()
-{
- ////////////////////////////////////////
- // DISPATCH/ISSUE stage
- ////////////////////////////////////////
-
- //Put into its own function?
- //Add instructions to IQ if there are any instructions there
-
- // Check if there are any instructions coming from rename, and we're.
- // not squashing.
- if (fromRename->size > 0) {
- int insts_to_add = fromRename->size;
-
- // Loop through the instructions, putting them in the instruction
- // queue.
- for (int inst_num = 0; inst_num < insts_to_add; ++inst_num)
- {
- DynInstPtr inst = fromRename->insts[inst_num];
-
- // Make sure there's a valid instruction there.
- assert(inst);
-
- DPRINTF(IEW, "IEW: Issue: Adding PC %#x to IQ.\n",
- inst->readPC());
-
- // Be sure to mark these instructions as ready so that the
- // commit stage can go ahead and execute them, and mark
- // them as issued so the IQ doesn't reprocess them.
- if (inst->isSquashed()) {
- ++iewDispSquashedInsts;
- continue;
- } else if (instQueue.isFull()) {
- DPRINTF(IEW, "IEW: Issue: IQ has become full.\n");
- // Call function to start blocking.
- block();
- // Tell previous stage to stall.
- toRename->iewInfo.stall = true;
-
- ++iewIQFullEvents;
- break;
- } else if (inst->isLoad()) {
- DPRINTF(IEW, "IEW: Issue: Memory instruction "
- "encountered, adding to LDSTQ.\n");
-
- // Reserve a spot in the load store queue for this
- // memory access.
- ldstQueue.insertLoad(inst);
-
- ++iewDispLoadInsts;
- } else if (inst->isStore()) {
- ldstQueue.insertStore(inst);
+DefaultIEW<Impl>::skidInsert(unsigned tid)
+{
+ DynInstPtr inst = NULL;
- ++iewDispStoreInsts;
- } else if (inst->isNonSpeculative()) {
- DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "
- "encountered, skipping.\n");
+ while (!insts[tid].empty()) {
+ inst = insts[tid].front();
- // Same hack as with stores.
- inst->setCanCommit();
+ insts[tid].pop();
+
+ DPRINTF(Decode,"[tid:%i]: Inserting [sn:%lli] PC:%#x into "
+ "dispatch skidBuffer %i\n",tid, inst->seqNum,
+ inst->readPC(),tid);
+
+ skidBuffer[tid].push(inst);
+ }
+
+ assert(skidBuffer[tid].size() <= skidBufferMax &&
+ "Skidbuffer Exceeded Max Size");
+}
+
+template<class Impl>
+int
+DefaultIEW<Impl>::skidCount()
+{
+ int max=0;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned thread_count = skidBuffer[*threads++].size();
+ if (max < thread_count)
+ max = thread_count;
+ }
+
+ return max;
+}
+
+template<class Impl>
+bool
+DefaultIEW<Impl>::skidsEmpty()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ if (!skidBuffer[*threads++].empty())
+ return false;
+ }
+
+ return true;
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::updateStatus()
+{
+ bool any_unblocking = false;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (dispatchStatus[tid] == Unblocking) {
+ any_unblocking = true;
+ break;
+ }
+ }
+
+ // If there are no ready instructions waiting to be scheduled by the IQ,
+ // and there's no stores waiting to write back, and dispatch is not
+ // unblocking, then there is no internal activity for the IEW stage.
+ if (_status == Active && !instQueue.hasReadyInsts() &&
+ !ldstQueue.willWB() && !any_unblocking) {
+ DPRINTF(IEW, "IEW switching to idle\n");
+
+ deactivateStage();
+
+ _status = Inactive;
+ } else if (_status == Inactive && (instQueue.hasReadyInsts() ||
+ ldstQueue.willWB() ||
+ any_unblocking)) {
+ // Otherwise there is internal activity. Set to active.
+ DPRINTF(IEW, "IEW switching to active\n");
+
+ activateStage();
+
+ _status = Active;
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::resetEntries()
+{
+ instQueue.resetEntries();
+ ldstQueue.resetEntries();
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::readStallSignals(unsigned tid)
+{
+ if (fromCommit->commitBlock[tid]) {
+ stalls[tid].commit = true;
+ }
+
+ if (fromCommit->commitUnblock[tid]) {
+ assert(stalls[tid].commit);
+ stalls[tid].commit = false;
+ }
+}
+
+template <class Impl>
+bool
+DefaultIEW<Impl>::checkStall(unsigned tid)
+{
+ bool ret_val(false);
+
+ if (stalls[tid].commit) {
+ DPRINTF(IEW,"[tid:%i]: Stall from Commit stage detected.\n",tid);
+ ret_val = true;
+ } else if (instQueue.isFull(tid)) {
+ DPRINTF(IEW,"[tid:%i]: Stall: IQ is full.\n",tid);
+ ret_val = true;
+ } else if (ldstQueue.isFull(tid)) {
+ DPRINTF(IEW,"[tid:%i]: Stall: LSQ is full\n",tid);
+
+ if (ldstQueue.numLoads(tid) > 0 ) {
+
+ DPRINTF(IEW,"[tid:%i]: LSQ oldest load: [sn:%i] \n",
+ tid,ldstQueue.getLoadHeadSeqNum(tid));
+ }
+
+ if (ldstQueue.numStores(tid) > 0) {
+
+ DPRINTF(IEW,"[tid:%i]: LSQ oldest store: [sn:%i] \n",
+ tid,ldstQueue.getStoreHeadSeqNum(tid));
+ }
+
+ ret_val = true;
+ } else if (ldstQueue.isStalled(tid)) {
+ DPRINTF(IEW,"[tid:%i]: Stall: LSQ stall detected.\n",tid);
+ ret_val = true;
+ }
+
+ return ret_val;
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::checkSignalsAndUpdate(unsigned tid)
+{
+ // Check if there's a squash signal, squash if there is
+ // Check stall signals, block if there is.
+ // If status was Blocked
+ // if so then go to unblocking
+ // If status was Squashing
+ // check if squashing is not high. Switch to running this cycle.
+
+ readStallSignals(tid);
+
+ if (fromCommit->commitInfo[tid].squash) {
+ squash(tid);
+
+ if (dispatchStatus[tid] == Blocked ||
+ dispatchStatus[tid] == Unblocking) {
+ toRename->iewUnblock[tid] = true;
+ wroteToTimeBuffer = true;
+ }
+
+ dispatchStatus[tid] = Squashing;
+
+ fetchRedirect[tid] = false;
+ return;
+ }
+
+ if (fromCommit->commitInfo[tid].robSquashing) {
+ DPRINTF(IEW, "[tid:%i]: ROB is still squashing.\n", tid);
+
+ dispatchStatus[tid] = Squashing;
+
+ emptyRenameInsts(tid);
+ wroteToTimeBuffer = true;
+ return;
+ }
+
+ if (checkStall(tid)) {
+ block(tid);
+ dispatchStatus[tid] = Blocked;
+ return;
+ }
+
+ if (dispatchStatus[tid] == Blocked) {
+ // Status from previous cycle was blocked, but there are no more stall
+ // conditions. Switch over to unblocking.
+ DPRINTF(IEW, "[tid:%i]: Done blocking, switching to unblocking.\n",
+ tid);
+
+ dispatchStatus[tid] = Unblocking;
+
+ unblock(tid);
- // Specificall insert it as nonspeculative.
+ return;
+ }
+
+ if (dispatchStatus[tid] == Squashing) {
+ // Switch status to running if rename isn't being told to block or
+ // squash this cycle.
+ DPRINTF(IEW, "[tid:%i]: Done squashing, switching to running.\n",
+ tid);
+
+ dispatchStatus[tid] = Running;
+
+ return;
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::sortInsts()
+{
+ int insts_from_rename = fromRename->size;
+#ifdef DEBUG
+ for (int i = 0; i < numThreads; i++)
+ assert(insts[i].empty());
+#endif
+ for (int i = 0; i < insts_from_rename; ++i) {
+ insts[fromRename->insts[i]->threadNumber].push(fromRename->insts[i]);
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::emptyRenameInsts(unsigned tid)
+{
+ while (!insts[tid].empty()) {
+ if (insts[tid].front()->isLoad() ||
+ insts[tid].front()->isStore() ) {
+ toRename->iewInfo[tid].dispatchedToLSQ++;
+ }
+
+ toRename->iewInfo[tid].dispatched++;
+
+ insts[tid].pop();
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::wakeCPU()
+{
+ cpu->wakeCPU();
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::activityThisCycle()
+{
+ DPRINTF(Activity, "Activity this cycle.\n");
+ cpu->activityThisCycle();
+}
+
+template <class Impl>
+inline void
+DefaultIEW<Impl>::activateStage()
+{
+ DPRINTF(Activity, "Activating stage.\n");
+ cpu->activateStage(O3CPU::IEWIdx);
+}
+
+template <class Impl>
+inline void
+DefaultIEW<Impl>::deactivateStage()
+{
+ DPRINTF(Activity, "Deactivating stage.\n");
+ cpu->deactivateStage(O3CPU::IEWIdx);
+}
+
+template<class Impl>
+void
+DefaultIEW<Impl>::dispatch(unsigned tid)
+{
+ // If status is Running or idle,
+ // call dispatchInsts()
+ // If status is Unblocking,
+ // buffer any instructions coming from rename
+ // continue trying to empty skid buffer
+ // check if stall conditions have passed
+
+ if (dispatchStatus[tid] == Blocked) {
+ ++iewBlockCycles;
+
+ } else if (dispatchStatus[tid] == Squashing) {
+ ++iewSquashCycles;
+ }
+
+ // Dispatch should try to dispatch as many instructions as its bandwidth
+ // will allow, as long as it is not currently blocked.
+ if (dispatchStatus[tid] == Running ||
+ dispatchStatus[tid] == Idle) {
+ DPRINTF(IEW, "[tid:%i] Not blocked, so attempting to run "
+ "dispatch.\n", tid);
+
+ dispatchInsts(tid);
+ } else if (dispatchStatus[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.
+ dispatchInsts(tid);
+
+ ++iewUnblockCycles;
+
+ if (validInstsFromRename() && dispatchedAllInsts) {
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidInsert(tid);
+ }
+
+ unblock(tid);
+ }
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::dispatchInsts(unsigned tid)
+{
+ dispatchedAllInsts = true;
+
+ // Obtain instructions from skid buffer if unblocking, or queue from rename
+ // otherwise.
+ std::queue<DynInstPtr> &insts_to_dispatch =
+ dispatchStatus[tid] == Unblocking ?
+ skidBuffer[tid] : insts[tid];
+
+ int insts_to_add = insts_to_dispatch.size();
+
+ DynInstPtr inst;
+ bool add_to_iq = false;
+ int dis_num_inst = 0;
+
+ // Loop through the instructions, putting them in the instruction
+ // queue.
+ for ( ; dis_num_inst < insts_to_add &&
+ dis_num_inst < issueReadWidth;
+ ++dis_num_inst)
+ {
+ inst = insts_to_dispatch.front();
+
+ if (dispatchStatus[tid] == Unblocking) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Examining instruction from skid "
+ "buffer\n", tid);
+ }
+
+ // Make sure there's a valid instruction there.
+ assert(inst);
+
+ DPRINTF(IEW, "[tid:%i]: Issue: Adding PC %#x [sn:%lli] [tid:%i] to "
+ "IQ.\n",
+ tid, inst->readPC(), inst->seqNum, inst->threadNumber);
+
+ // Be sure to mark these instructions as ready so that the
+ // commit stage can go ahead and execute them, and mark
+ // them as issued so the IQ doesn't reprocess them.
+
+ // Check for squashed instructions.
+ if (inst->isSquashed()) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Squashed instruction encountered, "
+ "not adding to IQ.\n", tid);
+
+ ++iewDispSquashedInsts;
+
+ insts_to_dispatch.pop();
+
+ //Tell Rename That An Instruction has been processed
+ if (inst->isLoad() || inst->isStore()) {
+ toRename->iewInfo[tid].dispatchedToLSQ++;
+ }
+ toRename->iewInfo[tid].dispatched++;
+
+ continue;
+ }
+
+ // Check for full conditions.
+ if (instQueue.isFull(tid)) {
+ DPRINTF(IEW, "[tid:%i]: Issue: IQ has become full.\n", tid);
+
+ // Call function to start blocking.
+ block(tid);
+
+ // Set unblock to false. Special case where we are using
+ // skidbuffer (unblocking) instructions but then we still
+ // get full in the IQ.
+ toRename->iewUnblock[tid] = false;
+
+ dispatchedAllInsts = false;
+
+ ++iewIQFullEvents;
+ break;
+ } else if (ldstQueue.isFull(tid)) {
+ DPRINTF(IEW, "[tid:%i]: Issue: LSQ has become full.\n",tid);
+
+ // Call function to start blocking.
+ block(tid);
+
+ // Set unblock to false. Special case where we are using
+ // skidbuffer (unblocking) instructions but then we still
+ // get full in the IQ.
+ toRename->iewUnblock[tid] = false;
+
+ dispatchedAllInsts = false;
+
+ ++iewLSQFullEvents;
+ break;
+ }
+
+ // Otherwise issue the instruction just fine.
+ if (inst->isLoad()) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction "
+ "encountered, adding to LSQ.\n", tid);
+
+ // Reserve a spot in the load store queue for this
+ // memory access.
+ ldstQueue.insertLoad(inst);
+
+ ++iewDispLoadInsts;
+
+ add_to_iq = true;
+
+ toRename->iewInfo[tid].dispatchedToLSQ++;
+ } else if (inst->isStore()) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Memory instruction "
+ "encountered, adding to LSQ.\n", tid);
+
+ ldstQueue.insertStore(inst);
+
+ ++iewDispStoreInsts;
+
+ if (inst->isStoreConditional()) {
+ // Store conditionals need to be set as "canCommit()"
+ // so that commit can process them when they reach the
+ // head of commit.
+ // @todo: This is somewhat specific to Alpha.
+ inst->setCanCommit();
instQueue.insertNonSpec(inst);
+ add_to_iq = false;
++iewDispNonSpecInsts;
+ } else {
+ add_to_iq = true;
+ }
- continue;
- } else if (inst->isNop()) {
- DPRINTF(IEW, "IEW: Issue: Nop instruction encountered "
- ", skipping.\n");
+ toRename->iewInfo[tid].dispatchedToLSQ++;
+#if FULL_SYSTEM
+ } else if (inst->isMemBarrier() || inst->isWriteBarrier()) {
+ // Same as non-speculative stores.
+ inst->setCanCommit();
+ instQueue.insertBarrier(inst);
+ add_to_iq = false;
+#endif
+ } else if (inst->isNonSpeculative()) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Nonspeculative instruction "
+ "encountered, skipping.\n", tid);
- inst->setIssued();
- inst->setExecuted();
- inst->setCanCommit();
+ // Same as non-speculative stores.
+ inst->setCanCommit();
- instQueue.advanceTail(inst);
+ // Specifically insert it as nonspeculative.
+ instQueue.insertNonSpec(inst);
- continue;
- } else if (inst->isExecuted()) {
- assert(0 && "Instruction shouldn't be executed.\n");
- DPRINTF(IEW, "IEW: Issue: Executed branch encountered, "
- "skipping.\n");
+ ++iewDispNonSpecInsts;
- inst->setIssued();
- inst->setCanCommit();
+ add_to_iq = false;
+ } else if (inst->isNop()) {
+ DPRINTF(IEW, "[tid:%i]: Issue: Nop instruction encountered, "
+ "skipping.\n", tid);
- instQueue.advanceTail(inst);
+ inst->setIssued();
+ inst->setExecuted();
+ inst->setCanCommit();
- continue;
- }
+ instQueue.recordProducer(inst);
- // If the instruction queue is not full, then add the
- // instruction.
- instQueue.insert(fromRename->insts[inst_num]);
+ iewExecutedNop[tid]++;
- ++iewDispatchedInsts;
+ add_to_iq = false;
+ } else if (inst->isExecuted()) {
+ assert(0 && "Instruction shouldn't be executed.\n");
+ DPRINTF(IEW, "Issue: Executed branch encountered, "
+ "skipping.\n");
+
+ inst->setIssued();
+ inst->setCanCommit();
+
+ instQueue.recordProducer(inst);
+
+ add_to_iq = false;
+ } else {
+ add_to_iq = true;
}
+
+ // If the instruction queue is not full, then add the
+ // instruction.
+ if (add_to_iq) {
+ instQueue.insert(inst);
+ }
+
+ insts_to_dispatch.pop();
+
+ toRename->iewInfo[tid].dispatched++;
+
+ ++iewDispatchedInsts;
+ }
+
+ if (!insts_to_dispatch.empty()) {
+ DPRINTF(IEW,"[tid:%i]: Issue: Bandwidth Full. Blocking.\n");
+ block(tid);
+ toRename->iewUnblock[tid] = false;
+ }
+
+ if (dispatchStatus[tid] == Idle && dis_num_inst) {
+ dispatchStatus[tid] = Running;
+
+ updatedQueues = true;
}
+
+ dis_num_inst = 0;
}
template <class Impl>
void
-SimpleIEW<Impl>::executeInsts()
+DefaultIEW<Impl>::printAvailableInsts()
{
- ////////////////////////////////////////
- //EXECUTE/WRITEBACK stage
- ////////////////////////////////////////
+ int inst = 0;
+
+ cout << "Available Instructions: ";
+
+ while (fromIssue->insts[inst]) {
+
+ if (inst%3==0) cout << "\n\t";
- //Put into its own function?
- //Similarly should probably have separate execution for int vs FP.
- // Above comment is handled by the issue queue only issuing a valid
- // mix of int/fp instructions.
- //Actually okay to just have one execution, buuuuuut will need
- //somewhere that defines the execution latency of all instructions.
- // @todo: Move to the FU pool used in the current full cpu.
+ cout << "PC: " << fromIssue->insts[inst]->readPC()
+ << " TN: " << fromIssue->insts[inst]->threadNumber
+ << " SN: " << fromIssue->insts[inst]->seqNum << " | ";
+
+ inst++;
+
+ }
+
+ cout << "\n";
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::executeInsts()
+{
+ wbNumInst = 0;
+ wbCycle = 0;
- int fu_usage = 0;
- bool fetch_redirect = false;
- int inst_slot = 0;
- int time_slot = 0;
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+ fetchRedirect[tid] = false;
+ }
+
+ // Uncomment this if you want to see all available instructions.
+// printAvailableInsts();
// Execute/writeback any instructions that are available.
- for (int inst_num = 0;
- fu_usage < executeWidth && /* Haven't exceeded available FU's. */
- inst_num < issueWidth &&
- fromIssue->insts[inst_num];
- ++inst_num) {
+ int insts_to_execute = fromIssue->size;
+ int inst_num = 0;
+ for (; inst_num < insts_to_execute;
+ ++inst_num) {
- DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n");
+ DPRINTF(IEW, "Execute: Executing instructions from IQ.\n");
- // Get instruction from issue's queue.
- DynInstPtr inst = fromIssue->insts[inst_num];
+ DynInstPtr inst = instQueue.getInstToExecute();
- DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC());
+ DPRINTF(IEW, "Execute: Processing PC %#x, [tid:%i] [sn:%i].\n",
+ inst->readPC(), inst->threadNumber,inst->seqNum);
// Check if the instruction is squashed; if so then skip it
- // and don't count it towards the FU usage.
if (inst->isSquashed()) {
- DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n");
+ DPRINTF(IEW, "Execute: Instruction was squashed.\n");
// Consider this instruction executed so that commit can go
// ahead and retire the instruction.
inst->setExecuted();
- toCommit->insts[inst_num] = inst;
+ // Not sure if I should set this here or just let commit try to
+ // commit any squashed instructions. I like the latter a bit more.
+ inst->setCanCommit();
++iewExecSquashedInsts;
continue;
}
- inst->setExecuted();
-
- // If an instruction is executed, then count it towards FU usage.
- ++fu_usage;
+ Fault fault = NoFault;
// Execute instruction.
// Note that if the instruction faults, it will be handled
// at the commit stage.
- if (inst->isMemRef()) {
- DPRINTF(IEW, "IEW: Execute: Calculating address for memory "
+ if (inst->isMemRef() &&
+ (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
+ DPRINTF(IEW, "Execute: Calculating address for memory "
"reference.\n");
// Tell the LDSTQ to execute this instruction (if it is a load).
if (inst->isLoad()) {
- ldstQueue.executeLoad(inst);
-
- ++iewExecLoadInsts;
+ // Loads will mark themselves as executed, and their writeback
+ // event adds the instruction to the queue to commit
+ fault = ldstQueue.executeLoad(inst);
} else if (inst->isStore()) {
ldstQueue.executeStore(inst);
- ++iewExecStoreInsts;
+ // If the store had a fault then it may not have a mem req
+ if (inst->req && !(inst->req->getFlags() & LOCKED)) {
+ inst->setExecuted();
+
+ instToCommit(inst);
+ }
+
+ // Store conditionals will mark themselves as
+ // executed, and their writeback event will add the
+ // instruction to the queue to commit.
} else {
- panic("IEW: Unexpected memory type!\n");
+ panic("Unexpected memory type!\n");
}
} else {
inst->execute();
- ++iewExecutedInsts;
+ inst->setExecuted();
+
+ instToCommit(inst);
}
- // First check the time slot that this instruction will write
- // to. If there are free write ports at the time, then go ahead
- // and write the instruction to that time. If there are not,
- // keep looking back to see where's the first time there's a
- // free slot. What happens if you run out of free spaces?
- // For now naively assume that all instructions take one cycle.
- // Otherwise would have to look into the time buffer based on the
- // latency of the instruction.
- (*iewQueue)[time_slot].insts[inst_slot];
- while ((*iewQueue)[time_slot].insts[inst_slot]) {
- if (inst_slot < issueWidth) {
- ++inst_slot;
- } else {
- ++time_slot;
- inst_slot = 0;
- }
+ updateExeInstStats(inst);
- assert(time_slot < 5);
- }
+ // Check if branch prediction was correct, if not then we need
+ // to tell commit to squash in flight instructions. Only
+ // handle this if there hasn't already been something that
+ // redirects fetch in this group of instructions.
- // May actually have to work this out, especially with loads and stores
+ // This probably needs to prioritize the redirects if a different
+ // scheduler is used. Currently the scheduler schedules the oldest
+ // instruction first, so the branch resolution order will be correct.
+ unsigned tid = inst->threadNumber;
- // Add finished instruction to queue to commit.
- (*iewQueue)[time_slot].insts[inst_slot] = inst;
- (*iewQueue)[time_slot].size++;
+ if (!fetchRedirect[tid]) {
- // Check if branch was correct. This check happens after the
- // instruction is added to the queue because even if the branch
- // is mispredicted, the branch instruction itself is still valid.
- // Only handle this if there hasn't already been something that
- // redirects fetch in this group of instructions.
- if (!fetch_redirect) {
if (inst->mispredicted()) {
- fetch_redirect = true;
+ fetchRedirect[tid] = true;
- DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n");
- DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n",
+ DPRINTF(IEW, "Execute: Branch mispredict detected.\n");
+ DPRINTF(IEW, "Execute: Redirecting fetch to PC: %#x.\n",
inst->nextPC);
// If incorrect, then signal the ROB that it must be squashed.
- squashDueToBranch(inst);
+ squashDueToBranch(inst, tid);
if (inst->predTaken()) {
predictedTakenIncorrect++;
+ } else {
+ predictedNotTakenIncorrect++;
}
- } else if (ldstQueue.violation()) {
- fetch_redirect = true;
+ } else if (ldstQueue.violation(tid)) {
+ fetchRedirect[tid] = true;
- // Get the DynInst that caused the violation.
- DynInstPtr violator = ldstQueue.getMemDepViolator();
+ // If there was an ordering violation, then get the
+ // DynInst that caused the violation. Note that this
+ // clears the violation signal.
+ DynInstPtr violator;
+ violator = ldstQueue.getMemDepViolator(tid);
- DPRINTF(IEW, "IEW: LDSTQ detected a violation. Violator PC: "
+ DPRINTF(IEW, "LDSTQ detected a violation. Violator PC: "
"%#x, inst PC: %#x. Addr is: %#x.\n",
violator->readPC(), inst->readPC(), inst->physEffAddr);
@@ -573,164 +1278,236 @@ SimpleIEW<Impl>::executeInsts()
instQueue.violation(inst, violator);
// Squash.
- squashDueToMem(inst);
+ squashDueToMemOrder(inst,tid);
++memOrderViolationEvents;
+ } else if (ldstQueue.loadBlocked(tid) &&
+ !ldstQueue.isLoadBlockedHandled(tid)) {
+ fetchRedirect[tid] = true;
+
+ DPRINTF(IEW, "Load operation couldn't execute because the "
+ "memory system is blocked. PC: %#x [sn:%lli]\n",
+ inst->readPC(), inst->seqNum);
+
+ squashDueToMemBlocked(inst, tid);
+ }
+ }
+ }
+
+ // Update and record activity if we processed any instructions.
+ if (inst_num) {
+ if (exeStatus == Idle) {
+ exeStatus = Running;
+ }
+
+ updatedQueues = true;
+
+ cpu->activityThisCycle();
+ }
+
+ // Need to reset this in case a writeback event needs to write into the
+ // iew queue. That way the writeback event will write into the correct
+ // spot in the queue.
+ wbNumInst = 0;
+}
+
+template <class Impl>
+void
+DefaultIEW<Impl>::writebackInsts()
+{
+ // Loop through the head of the time buffer and wake any
+ // dependents. These instructions are about to write back. Also
+ // mark scoreboard that this instruction is finally complete.
+ // Either have IEW have direct access to scoreboard, or have this
+ // as part of backwards communication.
+ for (int inst_num = 0; inst_num < issueWidth &&
+ toCommit->insts[inst_num]; inst_num++) {
+ DynInstPtr inst = toCommit->insts[inst_num];
+ int tid = inst->threadNumber;
+
+ DPRINTF(IEW, "Sending instructions to commit, [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ iewInstsToCommit[tid]++;
+
+ // Some instructions will be sent to commit without having
+ // executed because they need commit to handle them.
+ // E.g. Uncached loads have not actually executed when they
+ // are first sent to commit. Instead commit must tell the LSQ
+ // when it's ready to execute the uncached load.
+ if (!inst->isSquashed() && inst->isExecuted()) {
+ int dependents = instQueue.wakeDependents(inst);
+
+ for (int i = 0; i < inst->numDestRegs(); i++) {
+ //mark as Ready
+ DPRINTF(IEW,"Setting Destination Register %i\n",
+ inst->renamedDestRegIdx(i));
+ scoreboard->setReg(inst->renamedDestRegIdx(i));
}
+
+ if (dependents) {
+ producerInst[tid]++;
+ consumerInst[tid]+= dependents;
+ }
+ writebackCount[tid]++;
}
}
}
template<class Impl>
void
-SimpleIEW<Impl>::tick()
+DefaultIEW<Impl>::tick()
{
- // Considering putting all the state-determining stuff in this section.
+ wbNumInst = 0;
+ wbCycle = 0;
- // Try to fill up issue queue with as many instructions as bandwidth
- // allows.
- // Decode should try to execute as many instructions as its bandwidth
- // will allow, as long as it is not currently blocked.
+ wroteToTimeBuffer = false;
+ updatedQueues = false;
- // Check if the stage is in a running status.
- if (_status != Blocked && _status != Squashing) {
- DPRINTF(IEW, "IEW: Status is not blocked, attempting to run "
- "stage.\n");
- iew();
+ sortInsts();
- // If it's currently unblocking, check to see if it should switch
- // to running.
- if (_status == Unblocking) {
- unblock();
+ // Free function units marked as being freed this cycle.
+ fuPool->processFreeUnits();
- ++iewUnblockCycles;
- }
- } else if (_status == Squashing) {
+ list<unsigned>::iterator threads = (*activeThreads).begin();
- DPRINTF(IEW, "IEW: Still squashing.\n");
+ // Check stall and squash signals, dispatch any instructions.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
- // Check if stage should remain squashing. Stop squashing if the
- // squash signal clears.
- if (!fromCommit->commitInfo.squash &&
- !fromCommit->commitInfo.robSquashing) {
- DPRINTF(IEW, "IEW: Done squashing, changing status to "
- "running.\n");
+ DPRINTF(IEW,"Issue: Processing [tid:%i]\n",tid);
- _status = Running;
- instQueue.stopSquash();
- } else {
- instQueue.doSquash();
- }
+ checkSignalsAndUpdate(tid);
+ dispatch(tid);
+ }
- ++iewSquashCycles;
- } else if (_status == Blocked) {
- // Continue to tell previous stage to stall.
- toRename->iewInfo.stall = true;
-
- // Check if possible stall conditions have cleared.
- if (!fromCommit->commitInfo.stall &&
- !instQueue.isFull()) {
- DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n");
- _status = Unblocking;
- }
+ if (exeStatus != Squashing) {
+ executeInsts();
- // If there's still instructions coming from rename, continue to
- // put them on the skid buffer.
- if (fromRename->size == 0) {
- block();
- }
+ writebackInsts();
- if (fromCommit->commitInfo.squash ||
- fromCommit->commitInfo.robSquashing) {
- squash();
- }
+ // Have the instruction queue try to schedule any ready instructions.
+ // (In actuality, this scheduling is for instructions that will
+ // be executed next cycle.)
+ instQueue.scheduleReadyInsts();
- ++iewBlockCycles;
+ // Also should advance its own time buffers if the stage ran.
+ // Not the best place for it, but this works (hopefully).
+ issueToExecQueue.advance();
}
- // @todo: Maybe put these at the beginning, so if it's idle it can
- // return early.
- // Write back number of free IQ entries here.
- toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries();
+ bool broadcast_free_entries = false;
+
+ if (updatedQueues || exeStatus == Running || updateLSQNextCycle) {
+ exeStatus = Idle;
+ updateLSQNextCycle = false;
+ broadcast_free_entries = true;
+ }
+
+ // Writeback any stores using any leftover bandwidth.
ldstQueue.writebackStores();
// Check the committed load/store signals to see if there's a load
// or store to commit. Also check if it's being told to execute a
// nonspeculative instruction.
// This is pretty inefficient...
- if (!fromCommit->commitInfo.squash &&
- !fromCommit->commitInfo.robSquashing) {
- ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum);
- ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum);
- }
- if (fromCommit->commitInfo.nonSpecSeqNum != 0) {
- instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum);
- }
+ threads = (*activeThreads).begin();
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = (*threads++);
- DPRINTF(IEW, "IEW: IQ has %i free entries.\n",
- instQueue.numFreeEntries());
-}
+ DPRINTF(IEW,"Processing [tid:%i]\n",tid);
-template<class Impl>
-void
-SimpleIEW<Impl>::iew()
-{
- // Might want to put all state checks in the tick() function.
- // Check if being told to stall from commit.
- if (fromCommit->commitInfo.stall) {
- block();
- return;
- } else if (fromCommit->commitInfo.squash ||
- fromCommit->commitInfo.robSquashing) {
- // Also check if commit is telling this stage to squash.
- squash();
- return;
- }
+ // Update structures based on instructions committed.
+ if (fromCommit->commitInfo[tid].doneSeqNum != 0 &&
+ !fromCommit->commitInfo[tid].squash &&
+ !fromCommit->commitInfo[tid].robSquashing) {
- dispatchInsts();
+ ldstQueue.commitStores(fromCommit->commitInfo[tid].doneSeqNum,tid);
- // Have the instruction queue try to schedule any ready instructions.
- instQueue.scheduleReadyInsts();
+ ldstQueue.commitLoads(fromCommit->commitInfo[tid].doneSeqNum,tid);
- executeInsts();
+ updateLSQNextCycle = true;
+ instQueue.commit(fromCommit->commitInfo[tid].doneSeqNum,tid);
+ }
- // Loop through the head of the time buffer and wake any dependents.
- // These instructions are about to write back. In the simple model
- // this loop can really happen within the previous loop, but when
- // instructions have actual latencies, this loop must be separate.
- // Also mark scoreboard that this instruction is finally complete.
- // Either have IEW have direct access to rename map, or have this as
- // part of backwards communication.
- for (int inst_num = 0; inst_num < issueWidth &&
- toCommit->insts[inst_num]; inst_num++)
- {
- DynInstPtr inst = toCommit->insts[inst_num];
+ if (fromCommit->commitInfo[tid].nonSpecSeqNum != 0) {
+
+ //DPRINTF(IEW,"NonspecInst from thread %i",tid);
+ if (fromCommit->commitInfo[tid].uncached) {
+ instQueue.replayMemInst(fromCommit->commitInfo[tid].uncachedLoad);
+ } else {
+ instQueue.scheduleNonSpec(
+ fromCommit->commitInfo[tid].nonSpecSeqNum);
+ }
+ }
- DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n",
- inst->readPC());
+ if (broadcast_free_entries) {
+ toFetch->iewInfo[tid].iqCount =
+ instQueue.getCount(tid);
+ toFetch->iewInfo[tid].ldstqCount =
+ ldstQueue.getCount(tid);
- if(!inst->isSquashed()) {
- instQueue.wakeDependents(inst);
+ toRename->iewInfo[tid].usedIQ = true;
+ toRename->iewInfo[tid].freeIQEntries =
+ instQueue.numFreeEntries();
+ toRename->iewInfo[tid].usedLSQ = true;
+ toRename->iewInfo[tid].freeLSQEntries =
+ ldstQueue.numFreeEntries(tid);
- for (int i = 0; i < inst->numDestRegs(); i++)
- {
- renameMap->markAsReady(inst->renamedDestRegIdx(i));
- }
+ wroteToTimeBuffer = true;
}
+
+ DPRINTF(IEW, "[tid:%i], Dispatch dispatched %i instructions.\n",
+ tid, toRename->iewInfo[tid].dispatched);
}
- // Also should advance its own time buffers if the stage ran.
- // Not the best place for it, but this works (hopefully).
- issueToExecQueue.advance();
+ DPRINTF(IEW, "IQ has %i free entries (Can schedule: %i). "
+ "LSQ has %i free entries.\n",
+ instQueue.numFreeEntries(), instQueue.hasReadyInsts(),
+ ldstQueue.numFreeEntries());
+
+ updateStatus();
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+ cpu->activityThisCycle();
+ }
}
-#if !FULL_SYSTEM
-template<class Impl>
+template <class Impl>
void
-SimpleIEW<Impl>::lsqWriteback()
+DefaultIEW<Impl>::updateExeInstStats(DynInstPtr &inst)
{
- ldstQueue.writebackAllInsts();
-}
+ int thread_number = inst->threadNumber;
+
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch())
+ iewExecutedSwp[thread_number]++;
+ else
+ iewIewExecutedcutedInsts++;
+#else
+ iewExecutedInsts++;
#endif
+
+ //
+ // Control operations
+ //
+ if (inst->isControl())
+ iewExecutedBranches[thread_number]++;
+
+ //
+ // Memory operations
+ //
+ if (inst->isMemRef()) {
+ iewExecutedRefs[thread_number]++;
+
+ if (inst->isLoad()) {
+ iewExecLoadInsts[thread_number]++;
+ }
+ }
+}
diff --git a/src/cpu/o3/inst_queue.cc b/src/cpu/o3/inst_queue.cc
index 2ff2282b4..a539066f9 100644
--- a/src/cpu/o3/inst_queue.cc
+++ b/src/cpu/o3/inst_queue.cc
@@ -24,15 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/inst_queue_impl.hh"
// Force instantiation of InstructionQueue.
-template class InstructionQueue<AlphaSimpleImpl>;
-
-template<>
-unsigned
-InstructionQueue<AlphaSimpleImpl>::DependencyEntry::mem_alloc_counter = 0;
+template class InstructionQueue<O3CPUImpl>;
diff --git a/src/cpu/o3/inst_queue.hh b/src/cpu/o3/inst_queue.hh
index 43fe96c49..4c69ca384 100644
--- a/src/cpu/o3/inst_queue.hh
+++ b/src/cpu/o3/inst_queue.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,10 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_INST_QUEUE_HH__
-#define __CPU_O3_CPU_INST_QUEUE_HH__
+#ifndef __CPU_O3_INST_QUEUE_HH__
+#define __CPU_O3_INST_QUEUE_HH__
#include <list>
#include <map>
@@ -37,8 +40,13 @@
#include "base/statistics.hh"
#include "base/timebuf.hh"
#include "cpu/inst_seq.hh"
+#include "cpu/o3/dep_graph.hh"
+#include "cpu/op_class.hh"
#include "sim/host.hh"
+class FUPool;
+class MemInterface;
+
/**
* A standard instruction queue class. It holds ready instructions, in
* order, in seperate priority queues to facilitate the scheduling of
@@ -47,98 +55,216 @@
* floating point registers have their indices start after the integer
* registers (ie with 96 int and 96 fp registers, regs 0-95 are integer
* and 96-191 are fp). This remains true even for both logical and
- * physical register indices.
+ * physical register indices. The IQ depends on the memory dependence unit to
+ * track when memory operations are ready in terms of ordering; register
+ * dependencies are tracked normally. Right now the IQ also handles the
+ * execution timing; this is mainly to allow back-to-back scheduling without
+ * requiring IEW to be able to peek into the IQ. At the end of the execution
+ * latency, the instruction is put into the queue to execute, where it will
+ * have the execute() function called on it.
+ * @todo: Make IQ able to handle multiple FU pools.
*/
template <class Impl>
class InstructionQueue
{
public:
//Typedefs from the Impl.
- typedef typename Impl::FullCPU FullCPU;
+ 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;
typedef typename Impl::CPUPol::IssueStruct IssueStruct;
typedef typename Impl::CPUPol::TimeStruct TimeStruct;
- // Typedef of iterator through the list of instructions. Might be
- // better to untie this from the FullCPU or pass its information to
- // the stages.
+ // Typedef of iterator through the list of instructions.
typedef typename std::list<DynInstPtr>::iterator ListIt;
- /**
- * Struct for comparing entries to be added to the priority queue. This
- * gives reverse ordering to the instructions in terms of sequence
- * numbers: the instructions with smaller sequence numbers (and hence
- * are older) will be at the top of the priority queue.
- */
- struct pqCompare
- {
- bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
- {
- return lhs->seqNum > rhs->seqNum;
- }
- };
+ friend class Impl::O3CPU;
- /**
- * Struct for comparing entries to be added to the set. This gives
- * standard ordering in terms of sequence numbers.
- */
- struct setCompare
- {
- bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
- {
- return lhs->seqNum < rhs->seqNum;
- }
+ /** FU completion event class. */
+ class FUCompletion : public Event {
+ private:
+ /** Executing instruction. */
+ DynInstPtr inst;
+
+ /** Index of the FU used for executing. */
+ int fuIdx;
+
+ /** Pointer back to the instruction queue. */
+ InstructionQueue<Impl> *iqPtr;
+
+ /** Should the FU be added to the list to be freed upon
+ * completing this event.
+ */
+ bool freeFU;
+
+ public:
+ /** Construct a FU completion event. */
+ FUCompletion(DynInstPtr &_inst, int fu_idx,
+ InstructionQueue<Impl> *iq_ptr);
+
+ virtual void process();
+ virtual const char *description();
+ void setFreeFU() { freeFU = true; }
};
- typedef std::priority_queue<DynInstPtr, vector<DynInstPtr>, pqCompare>
- ReadyInstQueue;
+ /** Constructs an IQ. */
+ InstructionQueue(Params *params);
- InstructionQueue(Params &params);
+ /** Destructs the IQ. */
+ ~InstructionQueue();
+ /** Returns the name of the IQ. */
+ std::string name() const;
+
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu);
+ /** Resets all instruction queue state. */
+ void resetState();
+
+ /** Sets CPU pointer. */
+ void setCPU(O3CPU *_cpu) { cpu = _cpu; }
+
+ /** Sets active threads list. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Sets the IEW pointer. */
+ void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; }
+ /** Sets the timer buffer between issue and execute. */
void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue);
+ /** Sets the global time buffer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+ /** Switches out the instruction queue. */
+ void switchOut();
+
+ /** Takes over execution from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Returns if the IQ is switched out. */
+ bool isSwitchedOut() { return switchedOut; }
+
+ /** Number of entries needed for given amount of threads. */
+ int entryAmount(int num_threads);
+
+ /** Resets max entries for all threads. */
+ void resetEntries();
+
+ /** Returns total number of free entries. */
unsigned numFreeEntries();
+ /** Returns number of free entries for a thread. */
+ unsigned numFreeEntries(unsigned tid);
+
+ /** Returns whether or not the IQ is full. */
bool isFull();
+ /** Returns whether or not the IQ is full for a specific thread. */
+ bool isFull(unsigned tid);
+
+ /** Returns if there are any ready instructions in the IQ. */
+ bool hasReadyInsts();
+
+ /** Inserts a new instruction into the IQ. */
void insert(DynInstPtr &new_inst);
+ /** Inserts a new, non-speculative instruction into the IQ. */
void insertNonSpec(DynInstPtr &new_inst);
- void advanceTail(DynInstPtr &inst);
+ /** Inserts a memory or write barrier into the IQ to make sure
+ * loads and stores are ordered properly.
+ */
+ void insertBarrier(DynInstPtr &barr_inst);
+
+ /** Returns the oldest scheduled instruction, and removes it from
+ * the list of instructions waiting to execute.
+ */
+ DynInstPtr getInstToExecute();
+
+ /**
+ * Records the instruction as the producer of a register without
+ * adding it to the rest of the IQ.
+ */
+ void recordProducer(DynInstPtr &inst)
+ { addToProducers(inst); }
+ /** Process FU completion event. */
+ void processFUCompletion(DynInstPtr &inst, int fu_idx);
+
+ /**
+ * Schedules ready instructions, adding the ready ones (oldest first) to
+ * the queue to execute.
+ */
void scheduleReadyInsts();
+ /** Schedules a single specific non-speculative instruction. */
void scheduleNonSpec(const InstSeqNum &inst);
- void wakeDependents(DynInstPtr &completed_inst);
+ /**
+ * Commits all instructions up to and including the given sequence number,
+ * for a specific thread.
+ */
+ void commit(const InstSeqNum &inst, unsigned tid = 0);
+
+ /** Wakes all dependents of a completed instruction. */
+ int wakeDependents(DynInstPtr &completed_inst);
+
+ /** Adds a ready memory instruction to the ready list. */
+ void addReadyMemInst(DynInstPtr &ready_inst);
+
+ /**
+ * Reschedules a memory instruction. It will be ready to issue once
+ * replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &resched_inst);
+ /** Replays a memory instruction. It must be rescheduled first. */
+ void replayMemInst(DynInstPtr &replay_inst);
+
+ /** Completes a memory operation. */
+ void completeMemInst(DynInstPtr &completed_inst);
+
+ /** Indicates an ordering violation between a store and a load. */
void violation(DynInstPtr &store, DynInstPtr &faulting_load);
- // Change this to take in the sequence number
- void squash();
+ /**
+ * Squashes instructions for a thread. Squashing information is obtained
+ * from the time buffer.
+ */
+ void squash(unsigned tid);
- void doSquash();
+ /** Returns the number of used entries for a thread. */
+ unsigned getCount(unsigned tid) { return count[tid]; };
- void stopSquash();
+ /** Debug function to print all instructions. */
+ void printInsts();
private:
+ /** Does the actual squashing. */
+ void doSquash(unsigned tid);
+
+ /////////////////////////
+ // Various pointers
+ /////////////////////////
+
/** Pointer to the CPU. */
- FullCPU *cpu;
+ O3CPU *cpu;
+
+ /** Cache interface. */
+ MemInterface *dcacheInterface;
+
+ /** Pointer to IEW stage. */
+ IEW *iewStage;
/** The memory dependence unit, which tracks/predicts memory dependences
* between instructions.
*/
- MemDepUnit memDepUnit;
+ MemDepUnit memDepUnit[Impl::MaxThreads];
/** The queue to the execute stage. Issued instructions will be written
* into it.
@@ -151,36 +277,40 @@ class InstructionQueue
/** Wire to read information from timebuffer. */
typename TimeBuffer<TimeStruct>::wire fromCommit;
- enum InstList {
- Int,
- Float,
- Branch,
- Memory,
- Misc,
- Squashed,
- None
- };
+ /** Function unit pool. */
+ FUPool *fuPool;
- /** List of ready int instructions. Used to keep track of the order in
- * which instructions should issue.
- */
- ReadyInstQueue readyIntInsts;
+ //////////////////////////////////////
+ // Instruction lists, ready queues, and ordering
+ //////////////////////////////////////
+
+ /** List of all the instructions in the IQ (some of which may be issued). */
+ std::list<DynInstPtr> instList[Impl::MaxThreads];
- /** List of ready floating point instructions. */
- ReadyInstQueue readyFloatInsts;
+ /** List of instructions that are ready to be executed. */
+ std::list<DynInstPtr> instsToExecute;
- /** List of ready branch instructions. */
- ReadyInstQueue readyBranchInsts;
+ /**
+ * Struct for comparing entries to be added to the priority queue.
+ * This gives reverse ordering to the instructions in terms of
+ * sequence numbers: the instructions with smaller sequence
+ * numbers (and hence are older) will be at the top of the
+ * priority queue.
+ */
+ struct pqCompare {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum > rhs->seqNum;
+ }
+ };
- /** List of ready miscellaneous instructions. */
- ReadyInstQueue readyMiscInsts;
+ typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare>
+ ReadyInstQueue;
- /** List of squashed instructions (which are still valid and in IQ).
- * Implemented using a priority queue; the entries must contain both
- * the IQ index and sequence number of each instruction so that
- * ordering based on sequence numbers can be used.
+ /** List of ready instructions, per op class. They are separated by op
+ * class to allow for easy mapping to FUs.
*/
- ReadyInstQueue squashedInsts;
+ ReadyInstQueue readyInsts[Num_OpClasses];
/** List of non-speculative instructions that will be scheduled
* once the IQ gets a signal from commit. While it's redundant to
@@ -191,34 +321,80 @@ class InstructionQueue
*/
std::map<InstSeqNum, DynInstPtr> nonSpecInsts;
- typedef typename std::map<InstSeqNum, DynInstPtr>::iterator non_spec_it_t;
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt;
- /** Number of free IQ entries left. */
- unsigned freeEntries;
+ /** Entry for the list age ordering by op class. */
+ struct ListOrderEntry {
+ OpClass queueType;
+ InstSeqNum oldestInst;
+ };
- /** The number of entries in the instruction queue. */
- unsigned numEntries;
+ /** List that contains the age order of the oldest instruction of each
+ * ready queue. Used to select the oldest instruction available
+ * among op classes.
+ * @todo: Might be better to just move these entries around instead
+ * of creating new ones every time the position changes due to an
+ * instruction issuing. Not sure std::list supports this.
+ */
+ std::list<ListOrderEntry> listOrder;
- /** The number of integer instructions that can be issued in one
- * cycle.
+ typedef typename std::list<ListOrderEntry>::iterator ListOrderIt;
+
+ /** Tracks if each ready queue is on the age order list. */
+ bool queueOnList[Num_OpClasses];
+
+ /** Iterators of each ready queue. Points to their spot in the age order
+ * list.
*/
- unsigned intWidth;
+ ListOrderIt readyIt[Num_OpClasses];
+
+ /** Add an op class to the age order list. */
+ void addToOrderList(OpClass op_class);
- /** The number of floating point instructions that can be issued
- * in one cycle.
+ /**
+ * Called when the oldest instruction has been removed from a ready queue;
+ * this places that ready queue into the proper spot in the age order list.
*/
- unsigned floatWidth;
+ void moveToYoungerInst(ListOrderIt age_order_it);
+
+ DependencyGraph<DynInstPtr> dependGraph;
+
+ //////////////////////////////////////
+ // Various parameters
+ //////////////////////////////////////
+
+ /** IQ Resource Sharing Policy */
+ enum IQPolicy {
+ Dynamic,
+ Partitioned,
+ Threshold
+ };
+
+ /** IQ sharing policy for SMT. */
+ IQPolicy iqPolicy;
+
+ /** Number of Total Threads*/
+ unsigned numThreads;
- /** The number of branches that can be issued in one cycle. */
- unsigned branchWidth;
+ /** Pointer to list of active threads. */
+ std::list<unsigned> *activeThreads;
- /** The number of memory instructions that can be issued in one cycle. */
- unsigned memoryWidth;
+ /** Per Thread IQ count */
+ unsigned count[Impl::MaxThreads];
+
+ /** Max IQ Entries Per Thread */
+ unsigned maxEntries[Impl::MaxThreads];
+
+ /** Number of free IQ entries left. */
+ unsigned freeEntries;
+
+ /** The number of entries in the instruction queue. */
+ unsigned numEntries;
/** The total number of instructions that can be issued in one cycle. */
unsigned totalWidth;
- //The number of physical registers in the CPU.
+ /** The number of physical registers in the CPU. */
unsigned numPhysRegs;
/** The number of physical integer registers in the CPU. */
@@ -232,55 +408,11 @@ class InstructionQueue
*/
unsigned commitToIEWDelay;
- //////////////////////////////////
- // Variables needed for squashing
- //////////////////////////////////
+ /** Is the IQ switched out. */
+ bool switchedOut;
/** The sequence number of the squashed instruction. */
- InstSeqNum squashedSeqNum;
-
- /** Iterator that points to the youngest instruction in the IQ. */
- ListIt tail;
-
- /** Iterator that points to the last instruction that has been squashed.
- * This will not be valid unless the IQ is in the process of squashing.
- */
- ListIt squashIt;
-
- ///////////////////////////////////
- // Dependency graph stuff
- ///////////////////////////////////
-
- class DependencyEntry
- {
- public:
- DynInstPtr inst;
- //Might want to include data about what arch. register the
- //dependence is waiting on.
- DependencyEntry *next;
-
- //This function, and perhaps this whole class, stand out a little
- //bit as they don't fit a classification well. I want access
- //to the underlying structure of the linked list, yet at
- //the same time it feels like this should be something abstracted
- //away. So for now it will sit here, within the IQ, until
- //a better implementation is decided upon.
- // This function probably shouldn't be within the entry...
- void insert(DynInstPtr &new_inst);
-
- void remove(DynInstPtr &inst_to_remove);
-
- // Debug variable, remove when done testing.
- static unsigned mem_alloc_counter;
- };
-
- /** Array of linked lists. Each linked list is a list of all the
- * instructions that depend upon a given register. The actual
- * register's index is used to index into the graph; ie all
- * instructions in flight that are dependent upon r34 will be
- * in the linked list of dependGraph[34].
- */
- DependencyEntry *dependGraph;
+ InstSeqNum squashedSeqNum[Impl::MaxThreads];
/** A cache of the recently woken registers. It is 1 if the register
* has been woken up recently, and 0 if the register has been added
@@ -288,49 +420,89 @@ class InstructionQueue
* is basically a secondary scoreboard, and should pretty much mirror
* the scoreboard that exists in the rename map.
*/
- vector<bool> regScoreboard;
+ std::vector<bool> regScoreboard;
+ /** Adds an instruction to the dependency graph, as a consumer. */
bool addToDependents(DynInstPtr &new_inst);
- void insertDependency(DynInstPtr &new_inst);
- void createDependency(DynInstPtr &new_inst);
+ /** Adds an instruction to the dependency graph, as a producer. */
+ void addToProducers(DynInstPtr &new_inst);
+
+ /** Moves an instruction to the ready queue if it is ready. */
void addIfReady(DynInstPtr &inst);
- private:
/** Debugging function to count how many entries are in the IQ. It does
* a linear walk through the instructions, so do not call this function
* during normal execution.
*/
int countInsts();
- /** Debugging function to dump out the dependency graph.
- */
- void dumpDependGraph();
-
/** Debugging function to dump all the list sizes, as well as print
* out the list of nonspeculative instructions. Should not be used
* in any other capacity, but it has no harmful sideaffects.
*/
void dumpLists();
+ /** Debugging function to dump out all instructions that are in the
+ * IQ.
+ */
+ void dumpInsts();
+
+ /** Stat for number of instructions added. */
Stats::Scalar<> iqInstsAdded;
+ /** Stat for number of non-speculative instructions added. */
Stats::Scalar<> iqNonSpecInstsAdded;
-// Stats::Scalar<> iqIntInstsAdded;
+
+ Stats::Scalar<> iqInstsIssued;
+ /** Stat for number of integer instructions issued. */
Stats::Scalar<> iqIntInstsIssued;
-// Stats::Scalar<> iqFloatInstsAdded;
+ /** Stat for number of floating point instructions issued. */
Stats::Scalar<> iqFloatInstsIssued;
-// Stats::Scalar<> iqBranchInstsAdded;
+ /** Stat for number of branch instructions issued. */
Stats::Scalar<> iqBranchInstsIssued;
-// Stats::Scalar<> iqMemInstsAdded;
+ /** Stat for number of memory instructions issued. */
Stats::Scalar<> iqMemInstsIssued;
-// Stats::Scalar<> iqMiscInstsAdded;
+ /** Stat for number of miscellaneous instructions issued. */
Stats::Scalar<> iqMiscInstsIssued;
+ /** Stat for number of squashed instructions that were ready to issue. */
Stats::Scalar<> iqSquashedInstsIssued;
- Stats::Scalar<> iqLoopSquashStalls;
+ /** Stat for number of squashed instructions examined when squashing. */
Stats::Scalar<> iqSquashedInstsExamined;
+ /** Stat for number of squashed instruction operands examined when
+ * squashing.
+ */
Stats::Scalar<> iqSquashedOperandsExamined;
+ /** Stat for number of non-speculative instructions removed due to a squash.
+ */
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;
+ /** Distribution of the number of instructions issued. */
+ 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;
+
+ /** Number of times an instruction could not be issued because a
+ * FU was busy.
+ */
+ Stats::Vector<> statFuBusy;
+// Stats::Vector<> dist_unissued;
+ /** Stat for total number issued for each instruction type. */
+ Stats::Vector2d<> statIssuedInstType;
+
+ /** Number of instructions issued per cycle. */
+ Stats::Formula issueRate;
+
+ /** Number of times the FU was busy. */
+ Stats::Vector<> fuBusy;
+ /** Number of times the FU was busy per instruction issued. */
+ Stats::Formula fuBusyRate;
};
-#endif //__CPU_O3_CPU_INST_QUEUE_HH__
+#endif //__CPU_O3_INST_QUEUE_HH__
diff --git a/src/cpu/o3/inst_queue_impl.hh b/src/cpu/o3/inst_queue_impl.hh
index 048dc7c00..b99bd0900 100644
--- a/src/cpu/o3/inst_queue_impl.hh
+++ b/src/cpu/o3/inst_queue_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,75 +24,153 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Todo:
-// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake
-// it; either do in reverse order, or have added instructions put into a
-// different ready queue that, in scheduleRreadyInsts(), gets put onto the
-// normal ready queue. This would however give only a one cycle delay,
-// but probably is more flexible to actually add in a delay parameter than
-// just running it backwards.
-
#include <limits>
#include <vector>
#include "sim/root.hh"
+#include "cpu/o3/fu_pool.hh"
#include "cpu/o3/inst_queue.hh"
-// Either compile error or max int due to sign extension.
-// Hack to avoid compile warnings.
-const InstSeqNum MaxInstSeqNum = std::numeric_limits<InstSeqNum>::max();
+using namespace std;
template <class Impl>
-InstructionQueue<Impl>::InstructionQueue(Params &params)
- : memDepUnit(params),
- numEntries(params.numIQEntries),
- intWidth(params.executeIntWidth),
- floatWidth(params.executeFloatWidth),
- branchWidth(params.executeBranchWidth),
- memoryWidth(params.executeMemoryWidth),
- totalWidth(params.issueWidth),
- numPhysIntRegs(params.numPhysIntRegs),
- numPhysFloatRegs(params.numPhysFloatRegs),
- commitToIEWDelay(params.commitToIEWDelay)
+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)
{
- // Initialize the number of free IQ entries.
- freeEntries = numEntries;
+ this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::FUCompletion::process()
+{
+ iqPtr->processFUCompletion(inst, freeFU ? fuIdx : -1);
+ inst = NULL;
+}
+
+
+template <class Impl>
+const char *
+InstructionQueue<Impl>::FUCompletion::description()
+{
+ return "Functional unit completion event";
+}
+
+template <class Impl>
+InstructionQueue<Impl>::InstructionQueue(Params *params)
+ : fuPool(params->fuPool),
+ numEntries(params->numIQEntries),
+ totalWidth(params->issueWidth),
+ numPhysIntRegs(params->numPhysIntRegs),
+ numPhysFloatRegs(params->numPhysFloatRegs),
+ commitToIEWDelay(params->commitToIEWDelay)
+{
+ assert(fuPool);
+
+ switchedOut = false;
+
+ numThreads = params->numberOfThreads;
// Set the number of physical registers as the number of int + float
numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
- DPRINTF(IQ, "IQ: There are %i physical registers.\n", numPhysRegs);
+ DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs);
//Create an entry for each physical register within the
//dependency graph.
- dependGraph = new DependencyEntry[numPhysRegs];
+ dependGraph.resize(numPhysRegs);
// Resize the register scoreboard.
regScoreboard.resize(numPhysRegs);
- // Initialize all the head pointers to point to NULL, and all the
- // entries as unready.
- // Note that in actuality, the registers corresponding to the logical
- // registers start off as ready. However this doesn't matter for the
- // IQ as the instruction should have been correctly told if those
- // registers are ready in rename. Thus it can all be initialized as
- // unready.
- for (int i = 0; i < numPhysRegs; ++i)
- {
- dependGraph[i].next = NULL;
- dependGraph[i].inst = NULL;
- regScoreboard[i] = false;
+ //Initialize Mem Dependence Units
+ for (int i = 0; i < numThreads; i++) {
+ memDepUnit[i].init(params,i);
+ memDepUnit[i].setIQ(this);
}
+ resetState();
+
+ string policy = params->smtIQPolicy;
+
+ //Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ //Figure out resource sharing policy
+ if (policy == "dynamic") {
+ iqPolicy = Dynamic;
+
+ //Set Max Entries to Total ROB Capacity
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = numEntries;
+ }
+
+ } else if (policy == "partitioned") {
+ iqPolicy = Partitioned;
+
+ //@todo:make work if part_amt doesnt divide evenly.
+ int part_amt = numEntries / numThreads;
+
+ //Divide ROB up evenly
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = part_amt;
+ }
+
+ DPRINTF(IQ, "IQ sharing policy set to Partitioned:"
+ "%i entries per thread.\n",part_amt);
+
+ } else if (policy == "threshold") {
+ iqPolicy = Threshold;
+
+ double threshold = (double)params->smtIQThreshold / 100;
+
+ int thresholdIQ = (int)((double)threshold * numEntries);
+
+ //Divide up by threshold amount
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = thresholdIQ;
+ }
+
+ DPRINTF(IQ, "IQ sharing policy set to Threshold:"
+ "%i entries per thread.\n",thresholdIQ);
+ } else {
+ assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic,"
+ "Partitioned, Threshold}");
+ }
+}
+
+template <class Impl>
+InstructionQueue<Impl>::~InstructionQueue()
+{
+ dependGraph.reset();
+#ifdef DEBUG
+ cprintf("Nodes traversed: %i, removed: %i\n",
+ dependGraph.nodesTraversed, dependGraph.nodesRemoved);
+#endif
+}
+
+template <class Impl>
+std::string
+InstructionQueue<Impl>::name() const
+{
+ return cpu->name() + ".iq";
}
template <class Impl>
void
InstructionQueue<Impl>::regStats()
{
+ using namespace Stats;
iqInstsAdded
.name(name() + ".iqInstsAdded")
.desc("Number of instructions added to the IQ (excludes non-spec)")
@@ -103,36 +181,31 @@ InstructionQueue<Impl>::regStats()
.desc("Number of non-speculative instructions added to the IQ")
.prereq(iqNonSpecInstsAdded);
-// iqIntInstsAdded;
+ iqInstsIssued
+ .name(name() + ".iqInstsIssued")
+ .desc("Number of instructions issued")
+ .prereq(iqInstsIssued);
iqIntInstsIssued
.name(name() + ".iqIntInstsIssued")
.desc("Number of integer instructions issued")
.prereq(iqIntInstsIssued);
-// iqFloatInstsAdded;
-
iqFloatInstsIssued
.name(name() + ".iqFloatInstsIssued")
.desc("Number of float instructions issued")
.prereq(iqFloatInstsIssued);
-// iqBranchInstsAdded;
-
iqBranchInstsIssued
.name(name() + ".iqBranchInstsIssued")
.desc("Number of branch instructions issued")
.prereq(iqBranchInstsIssued);
-// iqMemInstsAdded;
-
iqMemInstsIssued
.name(name() + ".iqMemInstsIssued")
.desc("Number of memory instructions issued")
.prereq(iqMemInstsIssued);
-// iqMiscInstsAdded;
-
iqMiscInstsIssued
.name(name() + ".iqMiscInstsIssued")
.desc("Number of miscellaneous instructions issued")
@@ -143,12 +216,6 @@ InstructionQueue<Impl>::regStats()
.desc("Number of squashed instructions issued")
.prereq(iqSquashedInstsIssued);
- iqLoopSquashStalls
- .name(name() + ".iqLoopSquashStalls")
- .desc("Number of times issue loop had to restart due to squashed "
- "inst; mainly for profiling")
- .prereq(iqLoopSquashStalls);
-
iqSquashedInstsExamined
.name(name() + ".iqSquashedInstsExamined")
.desc("Number of squashed instructions iterated over during squash;"
@@ -166,25 +233,143 @@ InstructionQueue<Impl>::regStats()
.desc("Number of squashed non-spec instructions that were removed")
.prereq(iqSquashedNonSpecRemoved);
- // Tell mem dependence unit to reg stats as well.
- memDepUnit.regStats();
+ queueResDist
+ .init(Num_OpClasses, 0, 99, 2)
+ .name(name() + ".IQ:residence:")
+ .desc("cycles from dispatch to issue")
+ .flags(total | pdf | cdf )
+ ;
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ queueResDist.subname(i, opClassStrings[i]);
+ }
+ numIssuedDist
+ .init(0,totalWidth,1)
+ .name(name() + ".ISSUE:issued_per_cycle")
+ .desc("Number of insts issued each cycle")
+ .flags(pdf)
+ ;
+/*
+ dist_unissued
+ .init(Num_OpClasses+2)
+ .name(name() + ".ISSUE:unissued_cause")
+ .desc("Reason ready instruction not issued")
+ .flags(pdf | dist)
+ ;
+ for (int i=0; i < (Num_OpClasses + 2); ++i) {
+ dist_unissued.subname(i, unissued_names[i]);
+ }
+*/
+ statIssuedInstType
+ .init(numThreads,Num_OpClasses)
+ .name(name() + ".ISSUE:FU_type")
+ .desc("Type of FU issued")
+ .flags(total | pdf | dist)
+ ;
+ statIssuedInstType.ysubnames(opClassStrings);
+
+ //
+ // How long did instructions for a particular FU type wait prior to issue
+ //
+
+ issueDelayDist
+ .init(Num_OpClasses,0,99,2)
+ .name(name() + ".ISSUE:")
+ .desc("cycles from operands ready to issue")
+ .flags(pdf | cdf)
+ ;
+
+ for (int i=0; i<Num_OpClasses; ++i) {
+ stringstream subname;
+ subname << opClassStrings[i] << "_delay";
+ issueDelayDist.subname(i, subname.str());
+ }
+
+ issueRate
+ .name(name() + ".ISSUE:rate")
+ .desc("Inst issue rate")
+ .flags(total)
+ ;
+ issueRate = iqInstsIssued / cpu->numCycles;
+
+ statFuBusy
+ .init(Num_OpClasses)
+ .name(name() + ".ISSUE:fu_full")
+ .desc("attempts to use FU when none available")
+ .flags(pdf | dist)
+ ;
+ for (int i=0; i < Num_OpClasses; ++i) {
+ statFuBusy.subname(i, opClassStrings[i]);
+ }
+
+ fuBusy
+ .init(numThreads)
+ .name(name() + ".ISSUE:fu_busy_cnt")
+ .desc("FU busy when requested")
+ .flags(total)
+ ;
+
+ fuBusyRate
+ .name(name() + ".ISSUE:fu_busy_rate")
+ .desc("FU busy rate (busy events/executed inst)")
+ .flags(total)
+ ;
+ fuBusyRate = fuBusy / iqInstsIssued;
+
+ for ( int i=0; i < numThreads; i++) {
+ // Tell mem dependence unit to reg stats as well.
+ memDepUnit[i].regStats();
+ }
}
template <class Impl>
void
-InstructionQueue<Impl>::setCPU(FullCPU *cpu_ptr)
+InstructionQueue<Impl>::resetState()
{
- cpu = cpu_ptr;
+ //Initialize thread IQ counts
+ for (int i = 0; i <numThreads; i++) {
+ count[i] = 0;
+ instList[i].clear();
+ }
- tail = cpu->instList.begin();
+ // Initialize the number of free IQ entries.
+ freeEntries = numEntries;
+
+ // Note that in actuality, the registers corresponding to the logical
+ // registers start off as ready. However this doesn't matter for the
+ // IQ as the instruction should have been correctly told if those
+ // registers are ready in rename. Thus it can all be initialized as
+ // unready.
+ for (int i = 0; i < numPhysRegs; ++i) {
+ regScoreboard[i] = false;
+ }
+
+ for (int i = 0; i < numThreads; ++i) {
+ squashedSeqNum[i] = 0;
+ }
+
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ while (!readyInsts[i].empty())
+ readyInsts[i].pop();
+ queueOnList[i] = false;
+ readyIt[i] = listOrder.end();
+ }
+ nonSpecInsts.clear();
+ listOrder.clear();
}
template <class Impl>
void
-InstructionQueue<Impl>::setIssueToExecuteQueue(
- TimeBuffer<IssueStruct> *i2e_ptr)
+InstructionQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr)
{
- DPRINTF(IQ, "IQ: Set the issue to execute queue.\n");
+ DPRINTF(IQ, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr)
+{
+ DPRINTF(IQ, "Set the issue to execute queue.\n");
issueToExecuteQueue = i2e_ptr;
}
@@ -192,19 +377,77 @@ template <class Impl>
void
InstructionQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
- DPRINTF(IQ, "IQ: Set the time buffer.\n");
+ DPRINTF(IQ, "Set the time buffer.\n");
timeBuffer = tb_ptr;
fromCommit = timeBuffer->getWire(-commitToIEWDelay);
}
template <class Impl>
+void
+InstructionQueue<Impl>::switchOut()
+{
+ resetState();
+ dependGraph.reset();
+ switchedOut = true;
+ for (int i = 0; i < numThreads; ++i) {
+ memDepUnit[i].switchOut();
+ }
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::takeOverFrom()
+{
+ switchedOut = false;
+}
+
+template <class Impl>
+int
+InstructionQueue<Impl>::entryAmount(int num_threads)
+{
+ if (iqPolicy == Partitioned) {
+ return numEntries / num_threads;
+ } else {
+ return 0;
+ }
+}
+
+
+template <class Impl>
+void
+InstructionQueue<Impl>::resetEntries()
+{
+ if (iqPolicy != Dynamic || numThreads > 1) {
+ int active_threads = (*activeThreads).size();
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<unsigned>::iterator list_end = (*activeThreads).end();
+
+ while (threads != list_end) {
+ if (iqPolicy == Partitioned) {
+ maxEntries[*threads++] = numEntries / active_threads;
+ } else if(iqPolicy == Threshold && active_threads == 1) {
+ maxEntries[*threads++] = numEntries;
+ }
+ }
+ }
+}
+
+template <class Impl>
unsigned
InstructionQueue<Impl>::numFreeEntries()
{
return freeEntries;
}
+template <class Impl>
+unsigned
+InstructionQueue<Impl>::numFreeEntries(unsigned tid)
+{
+ return maxEntries[tid] - count[tid];
+}
+
// Might want to do something more complex if it knows how many instructions
// will be issued this cycle.
template <class Impl>
@@ -219,447 +462,412 @@ InstructionQueue<Impl>::isFull()
}
template <class Impl>
+bool
+InstructionQueue<Impl>::isFull(unsigned tid)
+{
+ if (numFreeEntries(tid) == 0) {
+ return(true);
+ } else {
+ return(false);
+ }
+}
+
+template <class Impl>
+bool
+InstructionQueue<Impl>::hasReadyInsts()
+{
+ if (!listOrder.empty()) {
+ return true;
+ }
+
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ if (!readyInsts[i].empty()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <class Impl>
void
InstructionQueue<Impl>::insert(DynInstPtr &new_inst)
{
// Make sure the instruction is valid
assert(new_inst);
- DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
- new_inst->readPC());
+ DPRINTF(IQ, "Adding instruction [sn:%lli] PC %#x to the IQ.\n",
+ new_inst->seqNum, new_inst->readPC());
- // Check if there are any free entries. Panic if there are none.
- // Might want to have this return a fault in the future instead of
- // panicing.
assert(freeEntries != 0);
- // If the IQ currently has nothing in it, then there's a possibility
- // that the tail iterator is invalid (might have been pointing at an
- // instruction that was retired). Reset the tail iterator.
- if (freeEntries == numEntries) {
- tail = cpu->instList.begin();
- }
+ instList[new_inst->threadNumber].push_back(new_inst);
- // Move the tail iterator. Instructions may not have been issued
- // to the IQ, so we may have to increment the iterator more than once.
- while ((*tail) != new_inst) {
- tail++;
-
- // Make sure the tail iterator points at something legal.
- assert(tail != cpu->instList.end());
- }
-
-
- // Decrease the number of free entries.
--freeEntries;
+ new_inst->setInIQ();
+
// Look through its source registers (physical regs), and mark any
// dependencies.
addToDependents(new_inst);
// Have this instruction set itself as the producer of its destination
// register(s).
- createDependency(new_inst);
+ addToProducers(new_inst);
- // If it's a memory instruction, add it to the memory dependency
- // unit.
if (new_inst->isMemRef()) {
- memDepUnit.insert(new_inst);
- // Uh..forgot to look it up and put it on the proper dependency list
- // if the instruction should not go yet.
+ memDepUnit[new_inst->threadNumber].insert(new_inst);
} else {
- // If the instruction is ready then add it to the ready list.
addIfReady(new_inst);
}
++iqInstsAdded;
+ count[new_inst->threadNumber]++;
+
assert(freeEntries == (numEntries - countInsts()));
}
template <class Impl>
void
-InstructionQueue<Impl>::insertNonSpec(DynInstPtr &inst)
+InstructionQueue<Impl>::insertNonSpec(DynInstPtr &new_inst)
{
- nonSpecInsts[inst->seqNum] = inst;
-
// @todo: Clean up this code; can do it by setting inst as unable
// to issue, then calling normal insert on the inst.
- // Make sure the instruction is valid
- assert(inst);
+ assert(new_inst);
- DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
- inst->readPC());
+ nonSpecInsts[new_inst->seqNum] = new_inst;
- // Check if there are any free entries. Panic if there are none.
- // Might want to have this return a fault in the future instead of
- // panicing.
- assert(freeEntries != 0);
+ DPRINTF(IQ, "Adding non-speculative instruction [sn:%lli] PC %#x "
+ "to the IQ.\n",
+ new_inst->seqNum, new_inst->readPC());
- // If the IQ currently has nothing in it, then there's a possibility
- // that the tail iterator is invalid (might have been pointing at an
- // instruction that was retired). Reset the tail iterator.
- if (freeEntries == numEntries) {
- tail = cpu->instList.begin();
- }
-
- // Move the tail iterator. Instructions may not have been issued
- // to the IQ, so we may have to increment the iterator more than once.
- while ((*tail) != inst) {
- tail++;
+ assert(freeEntries != 0);
- // Make sure the tail iterator points at something legal.
- assert(tail != cpu->instList.end());
- }
+ instList[new_inst->threadNumber].push_back(new_inst);
- // Decrease the number of free entries.
--freeEntries;
+ new_inst->setInIQ();
+
// Have this instruction set itself as the producer of its destination
// register(s).
- createDependency(inst);
+ addToProducers(new_inst);
// If it's a memory instruction, add it to the memory dependency
// unit.
- if (inst->isMemRef()) {
- memDepUnit.insertNonSpec(inst);
+ if (new_inst->isMemRef()) {
+ memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);
}
++iqNonSpecInstsAdded;
+
+ count[new_inst->threadNumber]++;
+
+ assert(freeEntries == (numEntries - countInsts()));
}
-// Slightly hack function to advance the tail iterator in the case that
-// the IEW stage issues an instruction that is not added to the IQ. This
-// is needed in case a long chain of such instructions occurs.
-// I don't think this is used anymore.
template <class Impl>
void
-InstructionQueue<Impl>::advanceTail(DynInstPtr &inst)
+InstructionQueue<Impl>::insertBarrier(DynInstPtr &barr_inst)
{
- // Make sure the instruction is valid
- assert(inst);
-
- DPRINTF(IQ, "IQ: Adding instruction PC %#x to the IQ.\n",
- inst->readPC());
+ memDepUnit[barr_inst->threadNumber].insertBarrier(barr_inst);
- // Check if there are any free entries. Panic if there are none.
- // Might want to have this return a fault in the future instead of
- // panicing.
- assert(freeEntries != 0);
-
- // If the IQ currently has nothing in it, then there's a possibility
- // that the tail iterator is invalid (might have been pointing at an
- // instruction that was retired). Reset the tail iterator.
- if (freeEntries == numEntries) {
- tail = cpu->instList.begin();
- }
-
- // Move the tail iterator. Instructions may not have been issued
- // to the IQ, so we may have to increment the iterator more than once.
- while ((*tail) != inst) {
- tail++;
-
- // Make sure the tail iterator points at something legal.
- assert(tail != cpu->instList.end());
- }
-
- assert(freeEntries <= numEntries);
+ insertNonSpec(barr_inst);
+}
- // Have this instruction set itself as the producer of its destination
- // register(s).
- createDependency(inst);
+template <class Impl>
+typename Impl::DynInstPtr
+InstructionQueue<Impl>::getInstToExecute()
+{
+ assert(!instsToExecute.empty());
+ DynInstPtr inst = instsToExecute.front();
+ instsToExecute.pop_front();
+ return inst;
}
-// Need to make sure the number of float and integer instructions
-// issued does not exceed the total issue bandwidth.
-// @todo: Figure out a better way to remove the squashed items from the
-// lists. Checking the top item of each list to see if it's squashed
-// wastes time and forces jumps.
template <class Impl>
void
-InstructionQueue<Impl>::scheduleReadyInsts()
+InstructionQueue<Impl>::addToOrderList(OpClass op_class)
{
- DPRINTF(IQ, "IQ: Attempting to schedule ready instructions from "
- "the IQ.\n");
-
- int int_issued = 0;
- int float_issued = 0;
- int branch_issued = 0;
- int memory_issued = 0;
- int squashed_issued = 0;
- int total_issued = 0;
-
- IssueStruct *i2e_info = issueToExecuteQueue->access(0);
-
- bool insts_available = !readyBranchInsts.empty() ||
- !readyIntInsts.empty() ||
- !readyFloatInsts.empty() ||
- !memDepUnit.empty() ||
- !readyMiscInsts.empty() ||
- !squashedInsts.empty();
-
- // Note: Requires a globally defined constant.
- InstSeqNum oldest_inst = MaxInstSeqNum;
- InstList list_with_oldest = None;
-
- // Temporary values.
- DynInstPtr int_head_inst;
- DynInstPtr float_head_inst;
- DynInstPtr branch_head_inst;
- DynInstPtr mem_head_inst;
- DynInstPtr misc_head_inst;
- DynInstPtr squashed_head_inst;
-
- // Somewhat nasty code to look at all of the lists where issuable
- // instructions are located, and choose the oldest instruction among
- // those lists. Consider a rewrite in the future.
- while (insts_available && total_issued < totalWidth)
- {
- // Set this to false. Each if-block is required to set it to true
- // if there were instructions available this check. This will cause
- // this loop to run once more than necessary, but avoids extra calls.
- insts_available = false;
-
- oldest_inst = MaxInstSeqNum;
+ assert(!readyInsts[op_class].empty());
- list_with_oldest = None;
+ ListOrderEntry queue_entry;
- if (!readyIntInsts.empty() &&
- int_issued < intWidth) {
+ queue_entry.queueType = op_class;
- insts_available = true;
+ queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
- int_head_inst = readyIntInsts.top();
+ ListOrderIt list_it = listOrder.begin();
+ ListOrderIt list_end_it = listOrder.end();
- if (int_head_inst->isSquashed()) {
- readyIntInsts.pop();
-
- ++iqLoopSquashStalls;
-
- continue;
- }
-
- oldest_inst = int_head_inst->seqNum;
-
- list_with_oldest = Int;
+ while (list_it != list_end_it) {
+ if ((*list_it).oldestInst > queue_entry.oldestInst) {
+ break;
}
- if (!readyFloatInsts.empty() &&
- float_issued < floatWidth) {
-
- insts_available = true;
-
- float_head_inst = readyFloatInsts.top();
-
- if (float_head_inst->isSquashed()) {
- readyFloatInsts.pop();
-
- ++iqLoopSquashStalls;
-
- continue;
- } else if (float_head_inst->seqNum < oldest_inst) {
- oldest_inst = float_head_inst->seqNum;
+ list_it++;
+ }
- list_with_oldest = Float;
- }
- }
+ readyIt[op_class] = listOrder.insert(list_it, queue_entry);
+ queueOnList[op_class] = true;
+}
- if (!readyBranchInsts.empty() &&
- branch_issued < branchWidth) {
+template <class Impl>
+void
+InstructionQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it)
+{
+ // Get iterator of next item on the list
+ // Delete the original iterator
+ // Determine if the next item is either the end of the list or younger
+ // than the new instruction. If so, then add in a new iterator right here.
+ // If not, then move along.
+ ListOrderEntry queue_entry;
+ OpClass op_class = (*list_order_it).queueType;
+ ListOrderIt next_it = list_order_it;
+
+ ++next_it;
+
+ queue_entry.queueType = op_class;
+ queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
+
+ while (next_it != listOrder.end() &&
+ (*next_it).oldestInst < queue_entry.oldestInst) {
+ ++next_it;
+ }
- insts_available = true;
+ readyIt[op_class] = listOrder.insert(next_it, queue_entry);
+}
- branch_head_inst = readyBranchInsts.top();
+template <class Impl>
+void
+InstructionQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
+{
+ // The CPU could have been sleeping until this op completed (*extremely*
+ // long latency op). Wake it if it was. This may be overkill.
+ if (isSwitchedOut()) {
+ return;
+ }
- if (branch_head_inst->isSquashed()) {
- readyBranchInsts.pop();
+ iewStage->wakeCPU();
- ++iqLoopSquashStalls;
+ if (fu_idx > -1)
+ fuPool->freeUnitNextCycle(fu_idx);
- continue;
- } else if (branch_head_inst->seqNum < oldest_inst) {
- oldest_inst = branch_head_inst->seqNum;
+ // @todo: Ensure that these FU Completions happen at the beginning
+ // of a cycle, otherwise they could add too many instructions to
+ // the queue.
+ issueToExecuteQueue->access(0)->size++;
+ instsToExecute.push_back(inst);
+}
- list_with_oldest = Branch;
- }
+// @todo: Figure out a better way to remove the squashed items from the
+// lists. Checking the top item of each list to see if it's squashed
+// wastes time and forces jumps.
+template <class Impl>
+void
+InstructionQueue<Impl>::scheduleReadyInsts()
+{
+ DPRINTF(IQ, "Attempting to schedule ready instructions from "
+ "the IQ.\n");
- }
+ IssueStruct *i2e_info = issueToExecuteQueue->access(0);
- if (!memDepUnit.empty() &&
- memory_issued < memoryWidth) {
+ // Have iterator to head of the list
+ // While I haven't exceeded bandwidth or reached the end of the list,
+ // Try to get a FU that can do what this op needs.
+ // If successful, change the oldestInst to the new top of the list, put
+ // the queue in the proper place in the list.
+ // Increment the iterator.
+ // This will avoid trying to schedule a certain op class if there are no
+ // FUs that handle it.
+ ListOrderIt order_it = listOrder.begin();
+ ListOrderIt order_end_it = listOrder.end();
+ int total_issued = 0;
- insts_available = true;
+ while (total_issued < totalWidth &&
+ order_it != order_end_it) {
+ OpClass op_class = (*order_it).queueType;
- mem_head_inst = memDepUnit.top();
+ assert(!readyInsts[op_class].empty());
- if (mem_head_inst->isSquashed()) {
- memDepUnit.pop();
+ DynInstPtr issuing_inst = readyInsts[op_class].top();
- ++iqLoopSquashStalls;
+ assert(issuing_inst->seqNum == (*order_it).oldestInst);
- continue;
- } else if (mem_head_inst->seqNum < oldest_inst) {
- oldest_inst = mem_head_inst->seqNum;
+ if (issuing_inst->isSquashed()) {
+ readyInsts[op_class].pop();
- list_with_oldest = Memory;
+ if (!readyInsts[op_class].empty()) {
+ moveToYoungerInst(order_it);
+ } else {
+ readyIt[op_class] = listOrder.end();
+ queueOnList[op_class] = false;
}
- }
-
- if (!readyMiscInsts.empty()) {
- insts_available = true;
+ listOrder.erase(order_it++);
- misc_head_inst = readyMiscInsts.top();
+ ++iqSquashedInstsIssued;
- if (misc_head_inst->isSquashed()) {
- readyMiscInsts.pop();
-
- ++iqLoopSquashStalls;
-
- continue;
- } else if (misc_head_inst->seqNum < oldest_inst) {
- oldest_inst = misc_head_inst->seqNum;
-
- list_with_oldest = Misc;
- }
+ continue;
}
- if (!squashedInsts.empty()) {
+ int idx = -2;
+ int op_latency = 1;
+ int tid = issuing_inst->threadNumber;
- insts_available = true;
+ if (op_class != No_OpClass) {
+ idx = fuPool->getUnit(op_class);
- squashed_head_inst = squashedInsts.top();
-
- if (squashed_head_inst->seqNum < oldest_inst) {
- list_with_oldest = Squashed;
+ if (idx > -1) {
+ op_latency = fuPool->getOpLatency(op_class);
}
-
}
- DynInstPtr issuing_inst = NULL;
-
- switch (list_with_oldest) {
- case None:
- DPRINTF(IQ, "IQ: Not able to schedule any instructions. Issuing "
- "inst is %#x.\n", issuing_inst);
- break;
-
- case Int:
- issuing_inst = int_head_inst;
- readyIntInsts.pop();
- ++int_issued;
- DPRINTF(IQ, "IQ: Issuing integer instruction PC %#x.\n",
- issuing_inst->readPC());
- break;
-
- case Float:
- issuing_inst = float_head_inst;
- readyFloatInsts.pop();
- ++float_issued;
- DPRINTF(IQ, "IQ: Issuing float instruction PC %#x.\n",
- issuing_inst->readPC());
- break;
-
- case Branch:
- issuing_inst = branch_head_inst;
- readyBranchInsts.pop();
- ++branch_issued;
- DPRINTF(IQ, "IQ: Issuing branch instruction PC %#x.\n",
- issuing_inst->readPC());
- break;
-
- case Memory:
- issuing_inst = mem_head_inst;
+ // If we have an instruction that doesn't require a FU, or a
+ // valid FU, then schedule for execution.
+ if (idx == -2 || idx != -1) {
+ if (op_latency == 1) {
+ i2e_info->size++;
+ instsToExecute.push_back(issuing_inst);
+
+ // Add the FU onto the list of FU's to be freed next
+ // cycle if we used one.
+ if (idx >= 0)
+ fuPool->freeUnitNextCycle(idx);
+ } else {
+ int issue_latency = fuPool->getIssueLatency(op_class);
+ // Generate completion event for the FU
+ FUCompletion *execution = new FUCompletion(issuing_inst,
+ idx, this);
+
+ execution->schedule(curTick + cpu->cycles(issue_latency - 1));
+
+ // @todo: Enforce that issue_latency == 1 or op_latency
+ if (issue_latency > 1) {
+ // If FU isn't pipelined, then it must be freed
+ // upon the execution completing.
+ execution->setFreeFU();
+ } else {
+ // Add the FU onto the list of FU's to be freed next cycle.
+ fuPool->freeUnitNextCycle(idx);
+ }
+ }
- memDepUnit.pop();
- ++memory_issued;
- DPRINTF(IQ, "IQ: Issuing memory instruction PC %#x.\n",
- issuing_inst->readPC());
- break;
+ DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "
+ "[sn:%lli]\n",
+ tid, issuing_inst->readPC(),
+ issuing_inst->seqNum);
- case Misc:
- issuing_inst = misc_head_inst;
- readyMiscInsts.pop();
+ readyInsts[op_class].pop();
- ++iqMiscInstsIssued;
+ if (!readyInsts[op_class].empty()) {
+ moveToYoungerInst(order_it);
+ } else {
+ readyIt[op_class] = listOrder.end();
+ queueOnList[op_class] = false;
+ }
- DPRINTF(IQ, "IQ: Issuing a miscellaneous instruction PC %#x.\n",
- issuing_inst->readPC());
- break;
+ issuing_inst->setIssued();
+ ++total_issued;
- case Squashed:
- assert(0 && "Squashed insts should not issue any more!");
- squashedInsts.pop();
- // Set the squashed instruction as able to commit so that commit
- // can just drop it from the ROB. This is a bit faked.
- ++squashed_issued;
- ++freeEntries;
+ if (!issuing_inst->isMemRef()) {
+ // Memory instructions can not be freed from the IQ until they
+ // complete.
+ ++freeEntries;
+ count[tid]--;
+ issuing_inst->clearInIQ();
+ } else {
+ memDepUnit[tid].issue(issuing_inst);
+ }
- DPRINTF(IQ, "IQ: Issuing squashed instruction PC %#x.\n",
- squashed_head_inst->readPC());
- break;
+ listOrder.erase(order_it++);
+ statIssuedInstType[tid][op_class]++;
+ } else {
+ statFuBusy[op_class]++;
+ fuBusy[tid]++;
+ ++order_it;
}
+ }
- if (list_with_oldest != None && list_with_oldest != Squashed) {
- i2e_info->insts[total_issued] = issuing_inst;
- i2e_info->size++;
-
- issuing_inst->setIssued();
+ numIssuedDist.sample(total_issued);
+ iqInstsIssued+= total_issued;
- ++freeEntries;
- ++total_issued;
- }
-
- assert(freeEntries == (numEntries - countInsts()));
+ // If we issued any instructions, tell the CPU we had activity.
+ if (total_issued) {
+ cpu->activityThisCycle();
+ } else {
+ DPRINTF(IQ, "Not able to schedule any instructions.\n");
}
-
- iqIntInstsIssued += int_issued;
- iqFloatInstsIssued += float_issued;
- iqBranchInstsIssued += branch_issued;
- iqMemInstsIssued += memory_issued;
- iqSquashedInstsIssued += squashed_issued;
}
template <class Impl>
void
InstructionQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst)
{
- DPRINTF(IQ, "IQ: Marking nonspeculative instruction with sequence "
- "number %i as ready to execute.\n", inst);
+ DPRINTF(IQ, "Marking nonspeculative instruction [sn:%lli] as ready "
+ "to execute.\n", inst);
- non_spec_it_t inst_it = nonSpecInsts.find(inst);
+ NonSpecMapIt inst_it = nonSpecInsts.find(inst);
assert(inst_it != nonSpecInsts.end());
- // Mark this instruction as ready to issue.
+ unsigned tid = (*inst_it).second->threadNumber;
+
(*inst_it).second->setCanIssue();
- // Now schedule the instruction.
if (!(*inst_it).second->isMemRef()) {
addIfReady((*inst_it).second);
} else {
- memDepUnit.nonSpecInstReady((*inst_it).second);
+ memDepUnit[tid].nonSpecInstReady((*inst_it).second);
}
+ (*inst_it).second = NULL;
+
nonSpecInsts.erase(inst_it);
}
template <class Impl>
void
+InstructionQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid)
+{
+ DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n",
+ tid,inst);
+
+ ListIt iq_it = instList[tid].begin();
+
+ while (iq_it != instList[tid].end() &&
+ (*iq_it)->seqNum <= inst) {
+ ++iq_it;
+ instList[tid].pop_front();
+ }
+
+ assert(freeEntries == (numEntries - countInsts()));
+}
+
+template <class Impl>
+int
InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
{
- DPRINTF(IQ, "IQ: Waking dependents of completed instruction.\n");
- //Look at the physical destination register of the DynInst
- //and look it up on the dependency graph. Then mark as ready
- //any instructions within the instruction queue.
- DependencyEntry *curr;
+ int dependents = 0;
- // Tell the memory dependence unit to wake any dependents on this
- // instruction if it is a memory instruction.
+ DPRINTF(IQ, "Waking dependents of completed instruction.\n");
+
+ assert(!completed_inst->isSquashed());
+ // Tell the memory dependence unit to wake any dependents on this
+ // instruction if it is a memory instruction. Also complete the memory
+ // instruction at this point since we know it executed without issues.
+ // @todo: Might want to rename "completeMemInst" to something that
+ // indicates that it won't need to be replayed, and call this
+ // earlier. Might not be a big deal.
if (completed_inst->isMemRef()) {
- memDepUnit.wakeDependents(completed_inst);
+ memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst);
+ completeMemInst(completed_inst);
+ } else if (completed_inst->isMemBarrier() ||
+ completed_inst->isWriteBarrier()) {
+ memDepUnit[completed_inst->threadNumber].completeBarrier(completed_inst);
}
for (int dest_reg_idx = 0;
@@ -676,44 +884,94 @@ InstructionQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
continue;
}
- DPRINTF(IQ, "IQ: Waking any dependents on register %i.\n",
+ DPRINTF(IQ, "Waking any dependents on register %i.\n",
(int) dest_reg);
- //Maybe abstract this part into a function.
- //Go through the dependency chain, marking the registers as ready
- //within the waiting instructions.
- while (dependGraph[dest_reg].next) {
+ //Go through the dependency chain, marking the registers as
+ //ready within the waiting instructions.
+ DynInstPtr dep_inst = dependGraph.pop(dest_reg);
- curr = dependGraph[dest_reg].next;
-
- DPRINTF(IQ, "IQ: Waking up a dependent instruction, PC%#x.\n",
- curr->inst->readPC());
+ while (dep_inst) {
+ DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n",
+ dep_inst->readPC());
// Might want to give more information to the instruction
- // so that it knows which of its source registers is ready.
- // However that would mean that the dependency graph entries
- // would need to hold the src_reg_idx.
- curr->inst->markSrcRegReady();
-
- addIfReady(curr->inst);
-
- dependGraph[dest_reg].next = curr->next;
+ // so that it knows which of its source registers is
+ // ready. However that would mean that the dependency
+ // graph entries would need to hold the src_reg_idx.
+ dep_inst->markSrcRegReady();
- DependencyEntry::mem_alloc_counter--;
+ addIfReady(dep_inst);
- curr->inst = NULL;
+ dep_inst = dependGraph.pop(dest_reg);
- delete curr;
+ ++dependents;
}
- // Reset the head node now that all of its dependents have been woken
- // up.
- dependGraph[dest_reg].next = NULL;
- dependGraph[dest_reg].inst = NULL;
+ // Reset the head node now that all of its dependents have
+ // been woken up.
+ assert(dependGraph.empty(dest_reg));
+ dependGraph.clearInst(dest_reg);
// Mark the scoreboard as having that register ready.
regScoreboard[dest_reg] = true;
}
+ return dependents;
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst)
+{
+ OpClass op_class = ready_inst->opClass();
+
+ readyInsts[op_class].push(ready_inst);
+
+ // Will need to reorder the list if either a queue is not on the list,
+ // or it has an older instruction than last time.
+ if (!queueOnList[op_class]) {
+ addToOrderList(op_class);
+ } else if (readyInsts[op_class].top()->seqNum <
+ (*readyIt[op_class]).oldestInst) {
+ listOrder.erase(readyIt[op_class]);
+ addToOrderList(op_class);
+ }
+
+ DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
+ "the ready list, PC %#x opclass:%i [sn:%lli].\n",
+ ready_inst->readPC(), op_class, ready_inst->seqNum);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst)
+{
+ memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::replayMemInst(DynInstPtr &replay_inst)
+{
+ memDepUnit[replay_inst->threadNumber].replay(replay_inst);
+}
+
+template <class Impl>
+void
+InstructionQueue<Impl>::completeMemInst(DynInstPtr &completed_inst)
+{
+ int tid = completed_inst->threadNumber;
+
+ DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n",
+ completed_inst->readPC(), completed_inst->seqNum);
+
+ ++freeEntries;
+
+ completed_inst->memOpDone = true;
+
+ memDepUnit[tid].completed(completed_inst);
+
+ count[tid]--;
}
template <class Impl>
@@ -721,58 +979,64 @@ void
InstructionQueue<Impl>::violation(DynInstPtr &store,
DynInstPtr &faulting_load)
{
- memDepUnit.violation(store, faulting_load);
+ memDepUnit[store->threadNumber].violation(store, faulting_load);
}
template <class Impl>
void
-InstructionQueue<Impl>::squash()
+InstructionQueue<Impl>::squash(unsigned tid)
{
- DPRINTF(IQ, "IQ: Starting to squash instructions in the IQ.\n");
+ DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in "
+ "the IQ.\n", tid);
// Read instruction sequence number of last instruction out of the
// time buffer.
- squashedSeqNum = fromCommit->commitInfo.doneSeqNum;
-
- // Setup the squash iterator to point to the tail.
- squashIt = tail;
+ squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum;
// Call doSquash if there are insts in the IQ
- if (freeEntries != numEntries) {
- doSquash();
+ if (count[tid] > 0) {
+ doSquash(tid);
}
// Also tell the memory dependence unit to squash.
- memDepUnit.squash(squashedSeqNum);
+ memDepUnit[tid].squash(squashedSeqNum[tid], tid);
}
template <class Impl>
void
-InstructionQueue<Impl>::doSquash()
+InstructionQueue<Impl>::doSquash(unsigned tid)
{
- // Make sure the squash iterator isn't pointing to nothing.
- assert(squashIt != cpu->instList.end());
- // Make sure the squashed sequence number is valid.
- assert(squashedSeqNum != 0);
+ // Start at the tail.
+ ListIt squash_it = instList[tid].end();
+ --squash_it;
- DPRINTF(IQ, "IQ: Squashing instructions in the IQ.\n");
+ DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n",
+ tid, squashedSeqNum[tid]);
// Squash any instructions younger than the squashed sequence number
// given.
- while ((*squashIt)->seqNum > squashedSeqNum) {
- DynInstPtr squashed_inst = (*squashIt);
+ while (squash_it != instList[tid].end() &&
+ (*squash_it)->seqNum > squashedSeqNum[tid]) {
+
+ DynInstPtr squashed_inst = (*squash_it);
// Only handle the instruction if it actually is in the IQ and
// hasn't already been squashed in the IQ.
- if (!squashed_inst->isIssued() &&
- !squashed_inst->isSquashedInIQ()) {
+ if (squashed_inst->threadNumber != tid ||
+ squashed_inst->isSquashedInIQ()) {
+ --squash_it;
+ continue;
+ }
+
+ if (!squashed_inst->isIssued() ||
+ (squashed_inst->isMemRef() &&
+ !squashed_inst->memOpDone)) {
// Remove the instruction from the dependency list.
- // Hack for now: These below don't add themselves to the
- // dependency list, so don't try to remove them.
- if (!squashed_inst->isNonSpeculative()/* &&
- !squashed_inst->isStore()*/
- ) {
+ if (!squashed_inst->isNonSpeculative() &&
+ !squashed_inst->isStoreConditional() &&
+ !squashed_inst->isMemBarrier() &&
+ !squashed_inst->isWriteBarrier()) {
for (int src_reg_idx = 0;
src_reg_idx < squashed_inst->numSrcRegs();
@@ -781,25 +1045,31 @@ InstructionQueue<Impl>::doSquash()
PhysRegIndex src_reg =
squashed_inst->renamedSrcRegIdx(src_reg_idx);
- // Only remove it from the dependency graph if it was
- // placed there in the first place.
- // HACK: This assumes that instructions woken up from the
- // dependency chain aren't informed that a specific src
- // register has become ready. This may not always be true
- // in the future.
+ // Only remove it from the dependency graph if it
+ // was placed there in the first place.
+
+ // Instead of doing a linked list traversal, we
+ // can just remove these squashed instructions
+ // either at issue time, or when the register is
+ // overwritten. The only downside to this is it
+ // leaves more room for error.
+
if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
src_reg < numPhysRegs) {
- dependGraph[src_reg].remove(squashed_inst);
+ dependGraph.remove(src_reg, squashed_inst);
}
+
++iqSquashedOperandsExamined;
}
-
- // Might want to remove producers as well.
} else {
- nonSpecInsts[squashed_inst->seqNum] = NULL;
+ NonSpecMapIt ns_inst_it =
+ nonSpecInsts.find(squashed_inst->seqNum);
+ assert(ns_inst_it != nonSpecInsts.end());
- nonSpecInsts.erase(squashed_inst->seqNum);
+ (*ns_inst_it).second = NULL;
+
+ nonSpecInsts.erase(ns_inst_it);
++iqSquashedNonSpecRemoved;
}
@@ -809,91 +1079,25 @@ InstructionQueue<Impl>::doSquash()
// Mark it as squashed within the IQ.
squashed_inst->setSquashedInIQ();
-// squashedInsts.push(squashed_inst);
+ // @todo: Remove this hack where several statuses are set so the
+ // inst will flow through the rest of the pipeline.
squashed_inst->setIssued();
squashed_inst->setCanCommit();
+ squashed_inst->clearInIQ();
+
+ //Update Thread IQ Count
+ count[squashed_inst->threadNumber]--;
++freeEntries;
- DPRINTF(IQ, "IQ: Instruction PC %#x squashed.\n",
- squashed_inst->readPC());
+ DPRINTF(IQ, "[tid:%i]: Instruction [sn:%lli] PC %#x "
+ "squashed.\n",
+ tid, squashed_inst->seqNum, squashed_inst->readPC());
}
- --squashIt;
+ instList[tid].erase(squash_it--);
++iqSquashedInstsExamined;
}
-
- assert(freeEntries <= numEntries);
-
- if (freeEntries == numEntries) {
- tail = cpu->instList.end();
- }
-
-}
-
-template <class Impl>
-void
-InstructionQueue<Impl>::stopSquash()
-{
- // Clear up the squash variables to ensure that squashing doesn't
- // get called improperly.
- squashedSeqNum = 0;
-
- squashIt = cpu->instList.end();
-}
-
-template <class Impl>
-void
-InstructionQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst)
-{
- //Add this new, dependent instruction at the head of the dependency
- //chain.
-
- // First create the entry that will be added to the head of the
- // dependency chain.
- DependencyEntry *new_entry = new DependencyEntry;
- new_entry->next = this->next;
- new_entry->inst = new_inst;
-
- // Then actually add it to the chain.
- this->next = new_entry;
-
- ++mem_alloc_counter;
-}
-
-template <class Impl>
-void
-InstructionQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove)
-{
- DependencyEntry *prev = this;
- DependencyEntry *curr = this->next;
-
- // Make sure curr isn't NULL. Because this instruction is being
- // removed from a dependency list, it must have been placed there at
- // an earlier time. The dependency chain should not be empty,
- // unless the instruction dependent upon it is already ready.
- if (curr == NULL) {
- return;
- }
-
- // Find the instruction to remove within the dependency linked list.
- while(curr->inst != inst_to_remove)
- {
- prev = curr;
- curr = curr->next;
-
- assert(curr != NULL);
- }
-
- // Now remove this instruction from the list.
- prev->next = curr->next;
-
- --mem_alloc_counter;
-
- // Could push this off to the destructor of DependencyEntry
- curr->inst = NULL;
-
- delete curr;
}
template <class Impl>
@@ -920,21 +1124,21 @@ InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst)
if (src_reg >= numPhysRegs) {
continue;
} else if (regScoreboard[src_reg] == false) {
- DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
+ DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
"is being added to the dependency chain.\n",
new_inst->readPC(), src_reg);
- dependGraph[src_reg].insert(new_inst);
+ dependGraph.insert(src_reg, new_inst);
// Change the return value to indicate that something
// was added to the dependency graph.
return_val = true;
} else {
- DPRINTF(IQ, "IQ: Instruction PC %#x has src reg %i that "
+ DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
"became ready before it reached the IQ.\n",
new_inst->readPC(), src_reg);
// Mark a register ready within the instruction.
- new_inst->markSrcRegReady();
+ new_inst->markSrcRegReady(src_reg_idx);
}
}
}
@@ -944,12 +1148,12 @@ InstructionQueue<Impl>::addToDependents(DynInstPtr &new_inst)
template <class Impl>
void
-InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
+InstructionQueue<Impl>::addToProducers(DynInstPtr &new_inst)
{
- //Actually nothing really needs to be marked when an
- //instruction becomes the producer of a register's value,
- //but for convenience a ptr to the producing instruction will
- //be placed in the head node of the dependency links.
+ // Nothing really needs to be marked when an instruction becomes
+ // the producer of a register's value, but for convenience a ptr
+ // to the producing instruction will be placed in the head node of
+ // the dependency links.
int8_t total_dest_regs = new_inst->numDestRegs();
for (int dest_reg_idx = 0;
@@ -966,13 +1170,13 @@ InstructionQueue<Impl>::createDependency(DynInstPtr &new_inst)
continue;
}
- dependGraph[dest_reg].inst = new_inst;
-
- if (dependGraph[dest_reg].next) {
- dumpDependGraph();
- panic("IQ: Dependency graph not empty!");
+ if (!dependGraph.empty(dest_reg)) {
+ dependGraph.dump();
+ panic("Dependency graph %i not empty!", dest_reg);
}
+ dependGraph.setInst(dest_reg, new_inst);
+
// Mark the scoreboard to say it's not yet ready.
regScoreboard[dest_reg] = false;
}
@@ -982,155 +1186,204 @@ template <class Impl>
void
InstructionQueue<Impl>::addIfReady(DynInstPtr &inst)
{
- //If the instruction now has all of its source registers
+ // If the instruction now has all of its source registers
// available, then add it to the list of ready instructions.
if (inst->readyToIssue()) {
//Add the instruction to the proper ready list.
- if (inst->isControl()) {
+ if (inst->isMemRef()) {
- DPRINTF(IQ, "IQ: Branch instruction is ready to issue, "
- "putting it onto the ready list, PC %#x.\n",
- inst->readPC());
- readyBranchInsts.push(inst);
-
- } else if (inst->isMemRef()) {
-
- DPRINTF(IQ, "IQ: Checking if memory instruction can issue.\n");
+ DPRINTF(IQ, "Checking if memory instruction can issue.\n");
// Message to the mem dependence unit that this instruction has
// its registers ready.
+ memDepUnit[inst->threadNumber].regsReady(inst);
- memDepUnit.regsReady(inst);
-
-#if 0
- if (memDepUnit.readyToIssue(inst)) {
- DPRINTF(IQ, "IQ: Memory instruction is ready to issue, "
- "putting it onto the ready list, PC %#x.\n",
- inst->readPC());
- readyMemInsts.push(inst);
- } else {
- // Make dependent on the store.
- // Will need some way to get the store instruction it should
- // be dependent upon; then when the store issues it can
- // put the instruction on the ready list.
- // Yet another tree?
- assert(0 && "Instruction has no way to actually issue");
- }
-#endif
-
- } else if (inst->isInteger()) {
-
- DPRINTF(IQ, "IQ: Integer instruction is ready to issue, "
- "putting it onto the ready list, PC %#x.\n",
- inst->readPC());
- readyIntInsts.push(inst);
+ return;
+ }
- } else if (inst->isFloating()) {
+ OpClass op_class = inst->opClass();
- DPRINTF(IQ, "IQ: Floating instruction is ready to issue, "
- "putting it onto the ready list, PC %#x.\n",
- inst->readPC());
- readyFloatInsts.push(inst);
+ DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
+ "the ready list, PC %#x opclass:%i [sn:%lli].\n",
+ inst->readPC(), op_class, inst->seqNum);
- } else {
- DPRINTF(IQ, "IQ: Miscellaneous instruction is ready to issue, "
- "putting it onto the ready list, PC %#x..\n",
- inst->readPC());
+ readyInsts[op_class].push(inst);
- readyMiscInsts.push(inst);
+ // Will need to reorder the list if either a queue is not on the list,
+ // or it has an older instruction than last time.
+ if (!queueOnList[op_class]) {
+ addToOrderList(op_class);
+ } else if (readyInsts[op_class].top()->seqNum <
+ (*readyIt[op_class]).oldestInst) {
+ listOrder.erase(readyIt[op_class]);
+ addToOrderList(op_class);
}
}
}
-/*
- * Caution, this function must not be called prior to tail being updated at
- * least once, otherwise it will fail the assertion. This is because
- * instList.begin() actually changes upon the insertion of an element into the
- * list when the list is empty.
- */
template <class Impl>
int
InstructionQueue<Impl>::countInsts()
{
- ListIt count_it = cpu->instList.begin();
+#if 0
+ //ksewell:This works but definitely could use a cleaner write
+ //with a more intuitive way of counting. Right now it's
+ //just brute force ....
+ // Change the #if if you want to use this method.
int total_insts = 0;
- if (tail == cpu->instList.end())
- return 0;
+ for (int i = 0; i < numThreads; ++i) {
+ ListIt count_it = instList[i].begin();
+
+ while (count_it != instList[i].end()) {
+ if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) {
+ if (!(*count_it)->isIssued()) {
+ ++total_insts;
+ } else if ((*count_it)->isMemRef() &&
+ !(*count_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++total_insts;
+ }
+ }
- while (count_it != tail) {
- if (!(*count_it)->isIssued()) {
- ++total_insts;
+ ++count_it;
}
-
- ++count_it;
-
- assert(count_it != cpu->instList.end());
- }
-
- // Need to count the tail iterator as well.
- if (count_it != cpu->instList.end() &&
- (*count_it) &&
- !(*count_it)->isIssued()) {
- ++total_insts;
}
return total_insts;
+#else
+ return numEntries - freeEntries;
+#endif
}
template <class Impl>
void
-InstructionQueue<Impl>::dumpDependGraph()
+InstructionQueue<Impl>::dumpLists()
{
- DependencyEntry *curr;
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ cprintf("Ready list %i size: %i\n", i, readyInsts[i].size());
- for (int i = 0; i < numPhysRegs; ++i)
- {
- curr = &dependGraph[i];
+ cprintf("\n");
+ }
- if (curr->inst) {
- cprintf("dependGraph[%i]: producer: %#x consumer: ", i,
- curr->inst->readPC());
- } else {
- cprintf("dependGraph[%i]: No producer. consumer: ", i);
- }
+ cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
- while (curr->next != NULL) {
- curr = curr->next;
+ NonSpecMapIt non_spec_it = nonSpecInsts.begin();
+ NonSpecMapIt non_spec_end_it = nonSpecInsts.end();
- cprintf("%#x ", curr->inst->readPC());
- }
+ cprintf("Non speculative list: ");
- cprintf("\n");
+ while (non_spec_it != non_spec_end_it) {
+ cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(),
+ (*non_spec_it).second->seqNum);
+ ++non_spec_it;
+ }
+
+ cprintf("\n");
+
+ ListOrderIt list_order_it = listOrder.begin();
+ ListOrderIt list_order_end_it = listOrder.end();
+ int i = 1;
+
+ cprintf("List order: ");
+
+ while (list_order_it != list_order_end_it) {
+ cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType,
+ (*list_order_it).oldestInst);
+
+ ++list_order_it;
+ ++i;
}
+
+ cprintf("\n");
}
+
template <class Impl>
void
-InstructionQueue<Impl>::dumpLists()
+InstructionQueue<Impl>::dumpInsts()
{
- cprintf("Ready integer list size: %i\n", readyIntInsts.size());
+ for (int i = 0; i < numThreads; ++i) {
+ int num = 0;
+ int valid_num = 0;
+ ListIt inst_list_it = instList[i].begin();
+
+ while (inst_list_it != instList[i].end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed
+ // still count towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
- cprintf("Ready float list size: %i\n", readyFloatInsts.size());
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
- cprintf("Ready branch list size: %i\n", readyBranchInsts.size());
+ cprintf("\n");
- cprintf("Ready misc list size: %i\n", readyMiscInsts.size());
+ inst_list_it++;
+ ++num;
+ }
+ }
- cprintf("Squashed list size: %i\n", squashedInsts.size());
+ cprintf("Insts to Execute list:\n");
- cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
+ int num = 0;
+ int valid_num = 0;
+ ListIt inst_list_it = instsToExecute.begin();
- non_spec_it_t non_spec_it = nonSpecInsts.begin();
+ while (inst_list_it != instsToExecute.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed
+ // still count towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
- cprintf("Non speculative list: ");
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
- while (non_spec_it != nonSpecInsts.end()) {
- cprintf("%#x ", (*non_spec_it).second->readPC());
- ++non_spec_it;
- }
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
- cprintf("\n");
+ cprintf("\n");
+ inst_list_it++;
+ ++num;
+ }
}
diff --git a/src/cpu/o3/isa_specific.hh b/src/cpu/o3/isa_specific.hh
new file mode 100755
index 000000000..f8a9dd8cc
--- /dev/null
+++ b/src/cpu/o3/isa_specific.hh
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ */
+
+#include "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"
+#else
+ #error "O3CPU doesnt support this ISA"
+#endif
diff --git a/src/cpu/o3/lsq.cc b/src/cpu/o3/lsq.cc
new file mode 100644
index 000000000..527947281
--- /dev/null
+++ b/src/cpu/o3/lsq.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Korey Sewell
+ */
+
+#include "cpu/o3/isa_specific.hh"
+#include "cpu/o3/lsq_impl.hh"
+
+// Force the instantiation of LDSTQ for all the implementations we care about.
+template class LSQ<O3CPUImpl>;
+
diff --git a/src/cpu/o3/lsq.hh b/src/cpu/o3/lsq.hh
new file mode 100644
index 000000000..89791fec9
--- /dev/null
+++ b/src/cpu/o3/lsq.hh
@@ -0,0 +1,321 @@
+/*
+ * 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: Korey Sewell
+ */
+
+#ifndef __CPU_O3_LSQ_HH__
+#define __CPU_O3_LSQ_HH__
+
+#include <map>
+#include <queue>
+
+#include "config/full_system.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/lsq_unit.hh"
+#include "mem/port.hh"
+#include "sim/sim_object.hh"
+
+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;
+ typedef typename Impl::CPUPol::LSQUnit LSQUnit;
+
+ /** SMT policy. */
+ enum LSQPolicy {
+ Dynamic,
+ Partitioned,
+ Threshold
+ };
+
+ /** Constructs an LSQ with the given parameters. */
+ LSQ(Params *params);
+
+ /** Returns the name of the LSQ. */
+ std::string name() const;
+
+ /** Registers statistics of each LSQ unit. */
+ void regStats();
+
+ /** Sets the pointer to the list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+ /** Sets the CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+ /** Sets the IEW stage pointer. */
+ void setIEW(IEW *iew_ptr);
+ /** Switches out the LSQ. */
+ void switchOut();
+ /** Takes over execution from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Number of entries needed for the given amount of threads.*/
+ int entryAmount(int num_threads);
+ void removeEntries(unsigned tid);
+ /** Reset the max entries for each thread. */
+ void resetEntries();
+ /** Resize the max entries for a thread. */
+ void resizeEntries(unsigned size, unsigned tid);
+
+ /** Ticks the LSQ. */
+ void tick();
+ /** Ticks a specific LSQ Unit. */
+ void tick(unsigned tid)
+ { thread[tid].tick(); }
+
+ /** Inserts a load into the LSQ. */
+ void insertLoad(DynInstPtr &load_inst);
+ /** Inserts a store into the LSQ. */
+ void insertStore(DynInstPtr &store_inst);
+
+ /** Executes a load. */
+ Fault executeLoad(DynInstPtr &inst);
+
+ /** Executes a store. */
+ Fault executeStore(DynInstPtr &inst);
+
+ /**
+ * Commits loads up until the given sequence number for a specific thread.
+ */
+ void commitLoads(InstSeqNum &youngest_inst, unsigned tid)
+ { thread[tid].commitLoads(youngest_inst); }
+
+ /**
+ * Commits stores up until the given sequence number for a specific thread.
+ */
+ void commitStores(InstSeqNum &youngest_inst, unsigned tid)
+ { thread[tid].commitStores(youngest_inst); }
+
+ /**
+ * Attempts to write back stores until all cache ports are used or the
+ * interface becomes blocked.
+ */
+ void writebackStores();
+ /** Same as above, but only for one thread. */
+ void writebackStores(unsigned tid);
+
+ /**
+ * Squash instructions from a thread until the specified sequence number.
+ */
+ void squash(const InstSeqNum &squashed_num, unsigned tid)
+ { thread[tid].squash(squashed_num); }
+
+ /** Returns whether or not there was a memory ordering violation. */
+ bool violation();
+ /**
+ * Returns whether or not there was a memory ordering violation for a
+ * specific thread.
+ */
+ bool violation(unsigned tid)
+ { return thread[tid].violation(); }
+
+ /** Returns if a load is blocked due to the memory system for a specific
+ * thread.
+ */
+ bool loadBlocked(unsigned tid)
+ { return thread[tid].loadBlocked(); }
+
+ bool isLoadBlockedHandled(unsigned tid)
+ { return thread[tid].isLoadBlockedHandled(); }
+
+ void setLoadBlockedHandled(unsigned tid)
+ { thread[tid].setLoadBlockedHandled(); }
+
+ /** Gets the instruction that caused the memory ordering violation. */
+ DynInstPtr getMemDepViolator(unsigned tid)
+ { return thread[tid].getMemDepViolator(); }
+
+ /** Returns the head index of the load queue for a specific thread. */
+ int getLoadHead(unsigned tid)
+ { return thread[tid].getLoadHead(); }
+
+ /** Returns the sequence number of the head of the load queue. */
+ InstSeqNum getLoadHeadSeqNum(unsigned tid)
+ {
+ return thread[tid].getLoadHeadSeqNum();
+ }
+
+ /** Returns the head index of the store queue. */
+ int getStoreHead(unsigned tid)
+ { return thread[tid].getStoreHead(); }
+
+ /** Returns the sequence number of the head of the store queue. */
+ InstSeqNum getStoreHeadSeqNum(unsigned tid)
+ {
+ return thread[tid].getStoreHeadSeqNum();
+ }
+
+ /** Returns the number of instructions in all of the queues. */
+ int getCount();
+ /** Returns the number of instructions in the queues of one thread. */
+ int getCount(unsigned tid)
+ { return thread[tid].getCount(); }
+
+ /** Returns the total number of loads in the load queue. */
+ int numLoads();
+ /** Returns the total number of loads for a single thread. */
+ int numLoads(unsigned tid)
+ { return thread[tid].numLoads(); }
+
+ /** Returns the total number of stores in the store queue. */
+ int numStores();
+ /** Returns the total number of stores for a single thread. */
+ int numStores(unsigned tid)
+ { return thread[tid].numStores(); }
+
+ /** Returns the total number of loads that are ready. */
+ int numLoadsReady();
+ /** Returns the number of loads that are ready for a single thread. */
+ int numLoadsReady(unsigned tid)
+ { return thread[tid].numLoadsReady(); }
+
+ /** Returns the number of free entries. */
+ unsigned numFreeEntries();
+ /** Returns the number of free entries for a specific thread. */
+ unsigned numFreeEntries(unsigned tid);
+
+ /** Returns if the LSQ is full (either LQ or SQ is full). */
+ bool isFull();
+ /**
+ * Returns if the LSQ is full for a specific thread (either LQ or SQ is
+ * full).
+ */
+ bool isFull(unsigned tid);
+
+ /** Returns if any of the LQs are full. */
+ bool lqFull();
+ /** Returns if the LQ of a given thread is full. */
+ bool lqFull(unsigned tid);
+
+ /** Returns if any of the SQs are full. */
+ bool sqFull();
+ /** Returns if the SQ of a given thread is full. */
+ bool sqFull(unsigned tid);
+
+ /**
+ * Returns if the LSQ is stalled due to a memory operation that must be
+ * replayed.
+ */
+ bool isStalled();
+ /**
+ * Returns if the LSQ of a specific thread is stalled due to a memory
+ * operation that must be replayed.
+ */
+ bool isStalled(unsigned tid);
+
+ /** Returns whether or not there are any stores to write back to memory. */
+ bool hasStoresToWB();
+
+ /** Returns whether or not a specific thread has any stores to write back
+ * to memory.
+ */
+ bool hasStoresToWB(unsigned tid)
+ { return thread[tid].hasStoresToWB(); }
+
+ /** Returns the number of stores a specific thread has to write back. */
+ int numStoresToWB(unsigned tid)
+ { return thread[tid].numStoresToWB(); }
+
+ /** Returns if the LSQ will write back to memory this cycle. */
+ bool willWB();
+ /** Returns if the LSQ of a specific thread will write back to memory this
+ * cycle.
+ */
+ bool willWB(unsigned tid)
+ { return thread[tid].willWB(); }
+
+ /** Debugging function to print out all instructions. */
+ void dumpInsts();
+ /** Debugging function to print out instructions from a specific thread. */
+ void dumpInsts(unsigned tid)
+ { thread[tid].dumpInsts(); }
+
+ /** Executes a read operation, using the load specified at the load index. */
+ template <class T>
+ Fault read(RequestPtr req, T &data, int load_idx);
+
+ /** Executes a store operation, using the store specified at the store
+ * index.
+ */
+ template <class T>
+ Fault write(RequestPtr req, T &data, int store_idx);
+
+ private:
+ /** The LSQ policy for SMT mode. */
+ LSQPolicy lsqPolicy;
+
+ /** The LSQ units for individual threads. */
+ LSQUnit thread[Impl::MaxThreads];
+
+ /** The CPU pointer. */
+ O3CPU *cpu;
+
+ /** The IEW stage pointer. */
+ IEW *iewStage;
+
+ /** List of Active Threads in System. */
+ std::list<unsigned> *activeThreads;
+
+ /** Total Size of LQ Entries. */
+ unsigned LQEntries;
+ /** Total Size of SQ Entries. */
+ unsigned SQEntries;
+
+ /** Max LQ Size - Used to Enforce Sharing Policies. */
+ unsigned maxLQEntries;
+
+ /** Max SQ Size - Used to Enforce Sharing Policies. */
+ unsigned maxSQEntries;
+
+ /** Number of Threads. */
+ unsigned numThreads;
+};
+
+template <class Impl>
+template <class T>
+Fault
+LSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
+{
+ unsigned tid = req->getThreadNum();
+
+ return thread[tid].read(req, data, load_idx);
+}
+
+template <class Impl>
+template <class T>
+Fault
+LSQ<Impl>::write(RequestPtr req, T &data, int store_idx)
+{
+ unsigned tid = req->getThreadNum();
+
+ return thread[tid].write(req, data, store_idx);
+}
+
+#endif // __CPU_O3_LSQ_HH__
diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh
new file mode 100644
index 000000000..5173f8be1
--- /dev/null
+++ b/src/cpu/o3/lsq_impl.hh
@@ -0,0 +1,539 @@
+/*
+ * 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: Korey Sewell
+ */
+
+#include <algorithm>
+#include <string>
+
+#include "cpu/o3/lsq.hh"
+
+using namespace std;
+
+template <class Impl>
+LSQ<Impl>::LSQ(Params *params)
+ : LQEntries(params->LQEntries), SQEntries(params->SQEntries),
+ numThreads(params->numberOfThreads)
+{
+ DPRINTF(LSQ, "Creating LSQ object.\n");
+
+ //**********************************************/
+ //************ Handle SMT Parameters ***********/
+ //**********************************************/
+ string policy = params->smtLSQPolicy;
+
+ //Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ //Figure out fetch policy
+ if (policy == "dynamic") {
+ lsqPolicy = Dynamic;
+
+ maxLQEntries = LQEntries;
+ maxSQEntries = SQEntries;
+
+ DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n");
+
+ } else if (policy == "partitioned") {
+ lsqPolicy = Partitioned;
+
+ //@todo:make work if part_amt doesnt divide evenly.
+ maxLQEntries = LQEntries / numThreads;
+ maxSQEntries = SQEntries / numThreads;
+
+ DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: "
+ "%i entries per LQ | %i entries per SQ",
+ maxLQEntries,maxSQEntries);
+
+ } else if (policy == "threshold") {
+ lsqPolicy = Threshold;
+
+ assert(params->smtLSQThreshold > LQEntries);
+ assert(params->smtLSQThreshold > SQEntries);
+
+ //Divide up by threshold amount
+ //@todo: Should threads check the max and the total
+ //amount of the LSQ
+ maxLQEntries = params->smtLSQThreshold;
+ maxSQEntries = params->smtLSQThreshold;
+
+ DPRINTF(LSQ, "LSQ sharing policy set to Threshold: "
+ "%i entries per LQ | %i entries per SQ",
+ maxLQEntries,maxSQEntries);
+
+ } else {
+ assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic,"
+ "Partitioned, Threshold}");
+ }
+
+ //Initialize LSQs
+ for (int tid=0; tid < numThreads; tid++) {
+ thread[tid].init(params, maxLQEntries, maxSQEntries, tid);
+ }
+}
+
+
+template<class Impl>
+std::string
+LSQ<Impl>::name() const
+{
+ return iewStage->name() + ".lsq";
+}
+
+template<class Impl>
+void
+LSQ<Impl>::regStats()
+{
+ //Initialize LSQs
+ for (int tid=0; tid < numThreads; tid++) {
+ thread[tid].regStats();
+ }
+}
+
+template<class Impl>
+void
+LSQ<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ activeThreads = at_ptr;
+ assert(activeThreads != 0);
+}
+
+template<class Impl>
+void
+LSQ<Impl>::setCPU(O3CPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ for (int tid=0; tid < numThreads; tid++) {
+ thread[tid].setCPU(cpu_ptr);
+ }
+}
+
+template<class Impl>
+void
+LSQ<Impl>::setIEW(IEW *iew_ptr)
+{
+ iewStage = iew_ptr;
+
+ for (int tid=0; tid < numThreads; tid++) {
+ thread[tid].setIEW(iew_ptr);
+ }
+}
+
+template <class Impl>
+void
+LSQ<Impl>::switchOut()
+{
+ for (int tid = 0; tid < numThreads; tid++) {
+ thread[tid].switchOut();
+ }
+}
+
+template <class Impl>
+void
+LSQ<Impl>::takeOverFrom()
+{
+ for (int tid = 0; tid < numThreads; tid++) {
+ thread[tid].takeOverFrom();
+ }
+}
+
+template <class Impl>
+int
+LSQ<Impl>::entryAmount(int num_threads)
+{
+ if (lsqPolicy == Partitioned) {
+ return LQEntries / num_threads;
+ } else {
+ return 0;
+ }
+}
+
+template <class Impl>
+void
+LSQ<Impl>::resetEntries()
+{
+ if (lsqPolicy != Dynamic || numThreads > 1) {
+ int active_threads = (*activeThreads).size();
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<unsigned>::iterator list_end = (*activeThreads).end();
+
+ int maxEntries;
+
+ if (lsqPolicy == Partitioned) {
+ maxEntries = LQEntries / active_threads;
+ } else if (lsqPolicy == Threshold && active_threads == 1) {
+ maxEntries = LQEntries;
+ } else {
+ maxEntries = LQEntries;
+ }
+
+ while (threads != list_end) {
+ resizeEntries(maxEntries,*threads++);
+ }
+ }
+}
+
+template<class Impl>
+void
+LSQ<Impl>::removeEntries(unsigned tid)
+{
+ thread[tid].clearLQ();
+ thread[tid].clearSQ();
+}
+
+template<class Impl>
+void
+LSQ<Impl>::resizeEntries(unsigned size,unsigned tid)
+{
+ thread[tid].resizeLQ(size);
+ thread[tid].resizeSQ(size);
+}
+
+template<class Impl>
+void
+LSQ<Impl>::tick()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+
+ thread[tid].tick();
+ }
+}
+
+template<class Impl>
+void
+LSQ<Impl>::insertLoad(DynInstPtr &load_inst)
+{
+ unsigned tid = load_inst->threadNumber;
+
+ thread[tid].insertLoad(load_inst);
+}
+
+template<class Impl>
+void
+LSQ<Impl>::insertStore(DynInstPtr &store_inst)
+{
+ unsigned tid = store_inst->threadNumber;
+
+ thread[tid].insertStore(store_inst);
+}
+
+template<class Impl>
+Fault
+LSQ<Impl>::executeLoad(DynInstPtr &inst)
+{
+ unsigned tid = inst->threadNumber;
+
+ return thread[tid].executeLoad(inst);
+}
+
+template<class Impl>
+Fault
+LSQ<Impl>::executeStore(DynInstPtr &inst)
+{
+ unsigned tid = inst->threadNumber;
+
+ return thread[tid].executeStore(inst);
+}
+
+template<class Impl>
+void
+LSQ<Impl>::writebackStores()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+
+ if (numStoresToWB(tid) > 0) {
+ DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores "
+ "available for Writeback.\n", tid, numStoresToWB(tid));
+ }
+
+ thread[tid].writebackStores();
+ }
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::violation()
+{
+ /* Answers: Does Anybody Have a Violation?*/
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (thread[tid].violation())
+ return true;
+ }
+
+ return false;
+}
+
+template<class Impl>
+int
+LSQ<Impl>::getCount()
+{
+ unsigned total = 0;
+
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ total += getCount(tid);
+ }
+
+ return total;
+}
+
+template<class Impl>
+int
+LSQ<Impl>::numLoads()
+{
+ unsigned total = 0;
+
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ total += numLoads(tid);
+ }
+
+ return total;
+}
+
+template<class Impl>
+int
+LSQ<Impl>::numStores()
+{
+ unsigned total = 0;
+
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ total += thread[tid].numStores();
+ }
+
+ return total;
+}
+
+template<class Impl>
+int
+LSQ<Impl>::numLoadsReady()
+{
+ unsigned total = 0;
+
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ total += thread[tid].numLoadsReady();
+ }
+
+ return total;
+}
+
+template<class Impl>
+unsigned
+LSQ<Impl>::numFreeEntries()
+{
+ unsigned total = 0;
+
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ total += thread[tid].numFreeEntries();
+ }
+
+ return total;
+}
+
+template<class Impl>
+unsigned
+LSQ<Impl>::numFreeEntries(unsigned tid)
+{
+ //if( lsqPolicy == Dynamic )
+ //return numFreeEntries();
+ //else
+ return thread[tid].numFreeEntries();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::isFull()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (! (thread[tid].lqFull() || thread[tid].sqFull()) )
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::isFull(unsigned tid)
+{
+ //@todo: Change to Calculate All Entries for
+ //Dynamic Policy
+ if( lsqPolicy == Dynamic )
+ return isFull();
+ else
+ return thread[tid].lqFull() || thread[tid].sqFull();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::lqFull()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (!thread[tid].lqFull())
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::lqFull(unsigned tid)
+{
+ //@todo: Change to Calculate All Entries for
+ //Dynamic Policy
+ if( lsqPolicy == Dynamic )
+ return lqFull();
+ else
+ return thread[tid].lqFull();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::sqFull()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (!sqFull(tid))
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::sqFull(unsigned tid)
+{
+ //@todo: Change to Calculate All Entries for
+ //Dynamic Policy
+ if( lsqPolicy == Dynamic )
+ return sqFull();
+ else
+ return thread[tid].sqFull();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::isStalled()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (!thread[tid].isStalled())
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::isStalled(unsigned tid)
+{
+ if( lsqPolicy == Dynamic )
+ return isStalled();
+ else
+ return thread[tid].isStalled();
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::hasStoresToWB()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (!hasStoresToWB(tid))
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+bool
+LSQ<Impl>::willWB()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ if (!willWB(tid))
+ return false;
+ }
+
+ return true;
+}
+
+template<class Impl>
+void
+LSQ<Impl>::dumpInsts()
+{
+ list<unsigned>::iterator active_threads = (*activeThreads).begin();
+
+ while (active_threads != (*activeThreads).end()) {
+ unsigned tid = *active_threads++;
+ thread[tid].dumpInsts();
+ }
+}
diff --git a/src/cpu/o3/lsq_unit.cc b/src/cpu/o3/lsq_unit.cc
new file mode 100644
index 000000000..3ca3fa667
--- /dev/null
+++ b/src/cpu/o3/lsq_unit.cc
@@ -0,0 +1,37 @@
+/*
+ * 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
+ */
+
+#include "cpu/o3/isa_specific.hh"
+#include "cpu/o3/lsq_unit_impl.hh"
+
+// Force the instantiation of LDSTQ for all the implementations we care about.
+template class LSQUnit<O3CPUImpl>;
+
diff --git a/src/cpu/o3/lsq_unit.hh b/src/cpu/o3/lsq_unit.hh
new file mode 100644
index 000000000..74b8fe5bb
--- /dev/null
+++ b/src/cpu/o3/lsq_unit.hh
@@ -0,0 +1,727 @@
+/*
+ * 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_O3_LSQ_UNIT_HH__
+#define __CPU_O3_LSQ_UNIT_HH__
+
+#include <algorithm>
+#include <map>
+#include <queue>
+
+#include "arch/faults.hh"
+#include "config/full_system.hh"
+#include "base/hashmap.hh"
+#include "cpu/inst_seq.hh"
+#include "mem/packet_impl.hh"
+#include "mem/port.hh"
+
+/**
+ * Class that implements the actual LQ and SQ for each specific
+ * thread. Both are circular queues; load entries are freed upon
+ * committing, while store entries are freed once they writeback. The
+ * LSQUnit tracks if there are memory ordering violations, and also
+ * detects partial load to store forwarding cases (a store only has
+ * part of a load's data) that requires the load to wait until the
+ * store writes back. In the former case it holds onto the instruction
+ * until the dependence unit looks at it, and in the latter it stalls
+ * the LSQ until the store writes back. At that point the load is
+ * replayed.
+ */
+template <class Impl>
+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;
+ typedef typename Impl::CPUPol::IssueStruct IssueStruct;
+
+ public:
+ /** Constructs an LSQ unit. init() must be called prior to use. */
+ LSQUnit();
+
+ /** Initializes the LSQ unit with the specified number of entries. */
+ void init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id);
+
+ /** Returns the name of the LSQ unit. */
+ std::string name() const;
+
+ /** Registers statistics. */
+ void regStats();
+
+ /** Sets the CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+
+ /** Sets the IEW stage pointer. */
+ void setIEW(IEW *iew_ptr)
+ { iewStage = iew_ptr; }
+
+ /** Switches out LSQ unit. */
+ void switchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Returns if the LSQ is switched out. */
+ bool isSwitchedOut() { return switchedOut; }
+
+ /** Ticks the LSQ unit, which in this case only resets the number of
+ * used cache ports.
+ * @todo: Move the number of used ports up to the LSQ level so it can
+ * be shared by all LSQ units.
+ */
+ void tick() { usedPorts = 0; }
+
+ /** Inserts an instruction. */
+ void insert(DynInstPtr &inst);
+ /** Inserts a load instruction. */
+ void insertLoad(DynInstPtr &load_inst);
+ /** Inserts a store instruction. */
+ void insertStore(DynInstPtr &store_inst);
+
+ /** Executes a load instruction. */
+ Fault executeLoad(DynInstPtr &inst);
+
+ Fault executeLoad(int lq_idx) { panic("Not implemented"); return NoFault; }
+ /** Executes a store instruction. */
+ Fault executeStore(DynInstPtr &inst);
+
+ /** Commits the head load. */
+ void commitLoad();
+ /** Commits loads older than a specific sequence number. */
+ void commitLoads(InstSeqNum &youngest_inst);
+
+ /** Commits stores older than a specific sequence number. */
+ void commitStores(InstSeqNum &youngest_inst);
+
+ /** Writes back stores. */
+ void writebackStores();
+
+ /** Completes the data access that has been returned from the
+ * memory system. */
+ void completeDataAccess(PacketPtr pkt);
+
+ /** Clears all the entries in the LQ. */
+ void clearLQ();
+
+ /** Clears all the entries in the SQ. */
+ void clearSQ();
+
+ /** Resizes the LQ to a given size. */
+ void resizeLQ(unsigned size);
+
+ /** Resizes the SQ to a given size. */
+ void resizeSQ(unsigned size);
+
+ /** Squashes all instructions younger than a specific sequence number. */
+ void squash(const InstSeqNum &squashed_num);
+
+ /** Returns if there is a memory ordering violation. Value is reset upon
+ * call to getMemDepViolator().
+ */
+ bool violation() { return memDepViolator; }
+
+ /** Returns the memory ordering violator. */
+ DynInstPtr getMemDepViolator();
+
+ /** Returns if a load became blocked due to the memory system. */
+ bool loadBlocked()
+ { return isLoadBlocked; }
+
+ /** Clears the signal that a load became blocked. */
+ void clearLoadBlocked()
+ { isLoadBlocked = false; }
+
+ /** Returns if the blocked load was handled. */
+ bool isLoadBlockedHandled()
+ { return loadBlockedHandled; }
+
+ /** Records the blocked load as being handled. */
+ void setLoadBlockedHandled()
+ { loadBlockedHandled = true; }
+
+ /** Returns the number of free entries (min of free LQ and SQ entries). */
+ unsigned numFreeEntries();
+
+ /** Returns the number of loads ready to execute. */
+ int numLoadsReady();
+
+ /** Returns the number of loads in the LQ. */
+ int numLoads() { return loads; }
+
+ /** Returns the number of stores in the SQ. */
+ int numStores() { return stores; }
+
+ /** Returns if either the LQ or SQ is full. */
+ bool isFull() { return lqFull() || sqFull(); }
+
+ /** Returns if the LQ is full. */
+ bool lqFull() { return loads >= (LQEntries - 1); }
+
+ /** Returns if the SQ is full. */
+ bool sqFull() { return stores >= (SQEntries - 1); }
+
+ /** Returns the number of instructions in the LSQ. */
+ unsigned getCount() { return loads + stores; }
+
+ /** Returns if there are any stores to writeback. */
+ bool hasStoresToWB() { return storesToWB; }
+
+ /** Returns the number of stores to writeback. */
+ int numStoresToWB() { return storesToWB; }
+
+ /** Returns if the LSQ unit will writeback on this cycle. */
+ bool willWB() { return storeQueue[storeWBIdx].canWB &&
+ !storeQueue[storeWBIdx].completed &&
+ !isStoreBlocked; }
+
+ private:
+ /** Writes back the instruction, sending it to IEW. */
+ void writeback(DynInstPtr &inst, PacketPtr pkt);
+
+ /** Handles completing the send of a store to memory. */
+ void storePostSend(Packet *pkt);
+
+ /** Completes the store at the specified index. */
+ void completeStore(int store_idx);
+
+ /** Handles doing the retry. */
+ void recvRetry();
+
+ /** Increments the given store index (circular queue). */
+ inline void incrStIdx(int &store_idx);
+ /** Decrements the given store index (circular queue). */
+ inline void decrStIdx(int &store_idx);
+ /** Increments the given load index (circular queue). */
+ inline void incrLdIdx(int &load_idx);
+ /** Decrements the given load index (circular queue). */
+ inline void decrLdIdx(int &load_idx);
+
+ public:
+ /** Debugging function to dump instructions in the LSQ. */
+ void dumpInsts();
+
+ private:
+ /** Pointer to the CPU. */
+ O3CPU *cpu;
+
+ /** Pointer to the IEW stage. */
+ IEW *iewStage;
+
+ /** Pointer to memory object. */
+ MemObject *mem;
+
+ /** DcachePort class for this LSQ Unit. Handles doing the
+ * communication with the cache/memory.
+ * @todo: Needs to be moved to the LSQ level and have some sort
+ * of arbitration.
+ */
+ class DcachePort : public Port
+ {
+ protected:
+ /** Pointer to CPU. */
+ O3CPU *cpu;
+ /** Pointer to LSQ. */
+ LSQUnit *lsq;
+
+ public:
+ /** Default constructor. */
+ DcachePort(O3CPU *_cpu, LSQUnit *_lsq)
+ : Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
+ { }
+
+ 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 writing back and
+ * completing the load or store that has returned from
+ * memory. */
+ virtual bool recvTiming(PacketPtr pkt);
+
+ /** Handles doing a retry of the previous send. */
+ virtual void recvRetry();
+ };
+
+ /** Pointer to the D-cache. */
+ DcachePort *dcachePort;
+
+ /** Derived class to hold any sender state the LSQ needs. */
+ class LSQSenderState : public Packet::SenderState
+ {
+ public:
+ /** Default constructor. */
+ LSQSenderState()
+ : noWB(false)
+ { }
+
+ /** Instruction who initiated the access to memory. */
+ DynInstPtr inst;
+ /** Whether or not it is a load. */
+ bool isLoad;
+ /** The LQ/SQ index of the instruction. */
+ int idx;
+ /** Whether or not the instruction will need to writeback. */
+ bool noWB;
+ };
+
+ /** Writeback event, specifically for when stores forward data to loads. */
+ class WritebackEvent : public Event {
+ public:
+ /** Constructs a writeback event. */
+ WritebackEvent(DynInstPtr &_inst, PacketPtr pkt, LSQUnit *lsq_ptr);
+
+ /** Processes the writeback event. */
+ void process();
+
+ /** Returns the description of this event. */
+ const char *description();
+
+ private:
+ /** Instruction whose results are being written back. */
+ DynInstPtr inst;
+
+ /** The packet that would have been sent to memory. */
+ PacketPtr pkt;
+
+ /** The pointer to the LSQ unit that issued the store. */
+ LSQUnit<Impl> *lsqPtr;
+ };
+
+ public:
+ struct SQEntry {
+ /** Constructs an empty store queue entry. */
+ SQEntry()
+ : inst(NULL), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0)
+ { }
+
+ /** Constructs a store queue entry for a given instruction. */
+ SQEntry(DynInstPtr &_inst)
+ : inst(_inst), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0)
+ { }
+
+ /** The store instruction. */
+ DynInstPtr inst;
+ /** The request for the store. */
+ RequestPtr req;
+ /** The size of the store. */
+ int size;
+ /** The store data. */
+ IntReg data;
+ /** Whether or not the store can writeback. */
+ bool canWB;
+ /** Whether or not the store is committed. */
+ bool committed;
+ /** Whether or not the store is completed. */
+ bool completed;
+ };
+
+ private:
+ /** The LSQUnit thread id. */
+ unsigned lsqID;
+
+ /** The store queue. */
+ std::vector<SQEntry> storeQueue;
+
+ /** The load queue. */
+ std::vector<DynInstPtr> loadQueue;
+
+ /** The number of LQ entries, plus a sentinel entry (circular queue).
+ * @todo: Consider having var that records the true number of LQ entries.
+ */
+ unsigned LQEntries;
+ /** The number of SQ entries, plus a sentinel entry (circular queue).
+ * @todo: Consider having var that records the true number of SQ entries.
+ */
+ unsigned SQEntries;
+
+ /** The number of load instructions in the LQ. */
+ int loads;
+ /** The number of store instructions in the SQ. */
+ int stores;
+ /** The number of store instructions in the SQ waiting to writeback. */
+ int storesToWB;
+
+ /** The index of the head instruction in the LQ. */
+ int loadHead;
+ /** The index of the tail instruction in the LQ. */
+ int loadTail;
+
+ /** The index of the head instruction in the SQ. */
+ int storeHead;
+ /** The index of the first instruction that may be ready to be
+ * written back, and has not yet been written back.
+ */
+ int storeWBIdx;
+ /** The index of the tail instruction in the SQ. */
+ int storeTail;
+
+ /// @todo Consider moving to a more advanced model with write vs read ports
+ /** The number of cache ports available each cycle. */
+ int cachePorts;
+
+ /** The number of used cache ports in this cycle. */
+ int usedPorts;
+
+ /** Is the LSQ switched out. */
+ bool switchedOut;
+
+ //list<InstSeqNum> mshrSeqNums;
+
+ /** Wire to read information from the issue stage time queue. */
+ typename TimeBuffer<IssueStruct>::wire fromIssue;
+
+ /** Whether or not the LSQ is stalled. */
+ bool stalled;
+ /** The store that causes the stall due to partial store to load
+ * forwarding.
+ */
+ InstSeqNum stallingStoreIsn;
+ /** The index of the above store. */
+ int stallingLoadIdx;
+
+ /** The packet that needs to be retried. */
+ PacketPtr retryPkt;
+
+ /** Whehter or not a store is blocked due to the memory system. */
+ bool isStoreBlocked;
+
+ /** Whether or not a load is blocked due to the memory system. */
+ bool isLoadBlocked;
+
+ /** Has the blocked load been handled. */
+ bool loadBlockedHandled;
+
+ /** The sequence number of the blocked load. */
+ InstSeqNum blockedLoadSeqNum;
+
+ /** The oldest load that caused a memory ordering violation. */
+ DynInstPtr memDepViolator;
+
+ // Will also need how many read/write ports the Dcache has. Or keep track
+ // 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;
+
+ /** Total number of loads ignored due to invalid addresses. */
+ Stats::Scalar<> invAddrLoads;
+
+ /** Total number of squashed loads. */
+ Stats::Scalar<> lsqSquashedLoads;
+
+ /** Total number of responses from the memory system that are
+ * ignored due to the instruction already being squashed. */
+ Stats::Scalar<> lsqIgnoredResponses;
+
+ /** Total number of squashed stores. */
+ Stats::Scalar<> lsqSquashedStores;
+
+ /** Total number of software prefetches ignored due to invalid addresses. */
+ Stats::Scalar<> invAddrSwpfs;
+
+ /** Ready loads blocked due to partial store-forwarding. */
+ Stats::Scalar<> lsqBlockedLoads;
+
+ /** Number of loads that were rescheduled. */
+ Stats::Scalar<> lsqRescheduledLoads;
+
+ /** Number of times the LSQ is blocked due to the cache. */
+ Stats::Scalar<> lsqCacheBlocked;
+
+ public:
+ /** Executes the load at the given index. */
+ template <class T>
+ Fault read(Request *req, T &data, int load_idx);
+
+ /** Executes the store at the given index. */
+ template <class T>
+ Fault write(Request *req, T &data, int store_idx);
+
+ /** Returns the index of the head load instruction. */
+ int getLoadHead() { return loadHead; }
+ /** Returns the sequence number of the head load instruction. */
+ InstSeqNum getLoadHeadSeqNum()
+ {
+ if (loadQueue[loadHead]) {
+ return loadQueue[loadHead]->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns the index of the head store instruction. */
+ int getStoreHead() { return storeHead; }
+ /** Returns the sequence number of the head store instruction. */
+ InstSeqNum getStoreHeadSeqNum()
+ {
+ if (storeQueue[storeHead].inst) {
+ return storeQueue[storeHead].inst->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns whether or not the LSQ unit is stalled. */
+ bool isStalled() { return stalled; }
+};
+
+template <class Impl>
+template <class T>
+Fault
+LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
+{
+ DynInstPtr load_inst = loadQueue[load_idx];
+
+ assert(load_inst);
+
+ assert(!load_inst->isExecuted());
+
+ // Make sure this isn't an uncacheable access
+ // A bit of a hackish way to get uncached accesses to work only if they're
+ // at the head of the LSQ and are ready to commit (at the head of the ROB
+ // too).
+ if (req->getFlags() & UNCACHEABLE &&
+ (load_idx != loadHead || !load_inst->isAtCommit())) {
+ iewStage->rescheduleMemInst(load_inst);
+ ++lsqRescheduledLoads;
+ return TheISA::genMachineCheckFault();
+ }
+
+ // Check the SQ for any previous stores that might lead to forwarding
+ int store_idx = load_inst->sqIdx;
+
+ int store_size = 0;
+
+ DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
+ "storeHead: %i addr: %#x\n",
+ load_idx, store_idx, storeHead, req->getPaddr());
+
+#if FULL_SYSTEM
+ if (req->getFlags() & LOCKED) {
+ cpu->lockAddr = req->getPaddr();
+ cpu->lockFlag = true;
+ }
+#endif
+
+ while (store_idx != -1) {
+ // End once we've reached the top of the LSQ
+ if (store_idx == storeWBIdx) {
+ break;
+ }
+
+ // Move the index to one younger
+ if (--store_idx < 0)
+ store_idx += SQEntries;
+
+ assert(storeQueue[store_idx].inst);
+
+ store_size = storeQueue[store_idx].size;
+
+ if (store_size == 0)
+ continue;
+
+ // Check if the store data is within the lower and upper bounds of
+ // addresses that the request needs.
+ bool store_has_lower_limit =
+ req->getVaddr() >= storeQueue[store_idx].inst->effAddr;
+ bool store_has_upper_limit =
+ (req->getVaddr() + req->getSize()) <=
+ (storeQueue[store_idx].inst->effAddr + store_size);
+ bool lower_load_has_store_part =
+ req->getVaddr() < (storeQueue[store_idx].inst->effAddr +
+ store_size);
+ bool upper_load_has_store_part =
+ (req->getVaddr() + req->getSize()) >
+ storeQueue[store_idx].inst->effAddr;
+
+ // If the store's data has all of the data needed, we can forward.
+ if (store_has_lower_limit && store_has_upper_limit) {
+ // Get shift amount for offset into the store's data.
+ int shift_amt = req->getVaddr() & (store_size - 1);
+ // @todo: Magic number, assumes byte addressing
+ shift_amt = shift_amt << 3;
+
+ // Cast this to type T?
+ data = storeQueue[store_idx].data >> shift_amt;
+
+ assert(!load_inst->memData);
+ load_inst->memData = new uint8_t[64];
+
+ memcpy(load_inst->memData, &data, req->getSize());
+
+ DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
+ "addr %#x, data %#x\n",
+ store_idx, req->getVaddr(), data);
+
+ PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(load_inst->memData);
+
+ WritebackEvent *wb = new WritebackEvent(load_inst, data_pkt, this);
+
+ // We'll say this has a 1 cycle load-store forwarding latency
+ // for now.
+ // @todo: Need to make this a parameter.
+ wb->schedule(curTick);
+
+ ++lsqForwLoads;
+ return NoFault;
+ } else if ((store_has_lower_limit && lower_load_has_store_part) ||
+ (store_has_upper_limit && upper_load_has_store_part) ||
+ (lower_load_has_store_part && upper_load_has_store_part)) {
+ // This is the partial store-load forwarding case where a store
+ // has only part of the load's data.
+
+ // If it's already been written back, then don't worry about
+ // stalling on it.
+ if (storeQueue[store_idx].completed) {
+ continue;
+ }
+
+ // Must stall load and force it to retry, so long as it's the oldest
+ // load that needs to do so.
+ if (!stalled ||
+ (stalled &&
+ load_inst->seqNum <
+ loadQueue[stallingLoadIdx]->seqNum)) {
+ stalled = true;
+ stallingStoreIsn = storeQueue[store_idx].inst->seqNum;
+ stallingLoadIdx = load_idx;
+ }
+
+ // Tell IQ/mem dep unit that this instruction will need to be
+ // rescheduled eventually
+ iewStage->rescheduleMemInst(load_inst);
+ ++lsqRescheduledLoads;
+
+ // Do not generate a writeback event as this instruction is not
+ // complete.
+ DPRINTF(LSQUnit, "Load-store forwarding mis-match. "
+ "Store idx %i to load addr %#x\n",
+ store_idx, req->getVaddr());
+
+ ++lsqBlockedLoads;
+ return NoFault;
+ }
+ }
+
+ // If there's no forwarding case, then go access memory
+ DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n",
+ load_inst->seqNum, load_inst->readPC());
+
+ assert(!load_inst->memData);
+ load_inst->memData = new uint8_t[64];
+
+ ++usedPorts;
+
+ DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n",
+ load_inst->readPC());
+
+ PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(load_inst->memData);
+
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = true;
+ state->idx = load_idx;
+ state->inst = load_inst;
+ data_pkt->senderState = state;
+
+ // if we have a cache, do cache access too
+ if (!dcachePort->sendTiming(data_pkt)) {
+ ++lsqCacheBlocked;
+ // There's an older load that's already going to squash.
+ if (isLoadBlocked && blockedLoadSeqNum < load_inst->seqNum)
+ return NoFault;
+
+ // Record that the load was blocked due to memory. This
+ // load will squash all instructions after it, be
+ // refetched, and re-executed.
+ isLoadBlocked = true;
+ loadBlockedHandled = false;
+ blockedLoadSeqNum = load_inst->seqNum;
+ // No fault occurred, even though the interface is blocked.
+ return NoFault;
+ }
+
+ if (data_pkt->result != Packet::Success) {
+ DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
+ DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
+ load_inst->seqNum);
+ } else {
+ DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
+ DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
+ load_inst->seqNum);
+ }
+
+ return NoFault;
+}
+
+template <class Impl>
+template <class T>
+Fault
+LSQUnit<Impl>::write(Request *req, T &data, int store_idx)
+{
+ assert(storeQueue[store_idx].inst);
+
+ DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x"
+ " | storeHead:%i [sn:%i]\n",
+ store_idx, req->getPaddr(), data, storeHead,
+ storeQueue[store_idx].inst->seqNum);
+
+ storeQueue[store_idx].req = req;
+ storeQueue[store_idx].size = sizeof(T);
+ storeQueue[store_idx].data = data;
+
+ // This function only writes the data to the store queue, so no fault
+ // can happen here.
+ return NoFault;
+}
+
+#endif // __CPU_O3_LSQ_UNIT_HH__
diff --git a/src/cpu/o3/lsq_unit_impl.hh b/src/cpu/o3/lsq_unit_impl.hh
new file mode 100644
index 000000000..714acb2ef
--- /dev/null
+++ b/src/cpu/o3/lsq_unit_impl.hh
@@ -0,0 +1,986 @@
+/*
+ * 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
+ */
+
+#include "config/use_checker.hh"
+
+#include "cpu/o3/lsq_unit.hh"
+#include "base/str.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
+template<class Impl>
+LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
+ LSQUnit *lsq_ptr)
+ : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::WritebackEvent::process()
+{
+ if (!lsqPtr->isSwitchedOut()) {
+ lsqPtr->writeback(inst, pkt);
+ }
+ delete pkt;
+}
+
+template<class Impl>
+const char *
+LSQUnit<Impl>::WritebackEvent::description()
+{
+ return "Store writeback event";
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
+{
+ LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
+ DynInstPtr inst = state->inst;
+ DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);
+ DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);
+
+ //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+
+ if (isSwitchedOut() || inst->isSquashed()) {
+ delete state;
+ delete pkt;
+ return;
+ } else {
+ if (!state->noWB) {
+ writeback(inst, pkt);
+ }
+
+ if (inst->isStore()) {
+ completeStore(state->idx);
+ }
+ }
+
+ delete state;
+ delete pkt;
+}
+
+template <class Impl>
+Tick
+LSQUnit<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("O3CPU model does not work with atomic mode!");
+ return curTick;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
+{
+ panic("O3CPU doesn't expect recvFunctional callback!");
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::DcachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("O3CPU doesn't expect recvStatusChange callback!");
+}
+
+template <class Impl>
+bool
+LSQUnit<Impl>::DcachePort::recvTiming(PacketPtr pkt)
+{
+ lsq->completeDataAccess(pkt);
+ return true;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::DcachePort::recvRetry()
+{
+ lsq->recvRetry();
+}
+
+template <class Impl>
+LSQUnit<Impl>::LSQUnit()
+ : loads(0), stores(0), storesToWB(0), stalled(false),
+ isStoreBlocked(false), isLoadBlocked(false),
+ loadBlockedHandled(false)
+{
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id)
+{
+ DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
+
+ switchedOut = false;
+
+ lsqID = id;
+
+ // Add 1 for the sentinel entry (they are circular queues).
+ LQEntries = maxLQEntries + 1;
+ SQEntries = maxSQEntries + 1;
+
+ loadQueue.resize(LQEntries);
+ storeQueue.resize(SQEntries);
+
+ loadHead = loadTail = 0;
+
+ storeHead = storeWBIdx = storeTail = 0;
+
+ usedPorts = 0;
+ cachePorts = params->cachePorts;
+
+ mem = params->mem;
+
+ memDepViolator = NULL;
+
+ blockedLoadSeqNum = 0;
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::setCPU(O3CPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+ dcachePort = new DcachePort(cpu, this);
+
+ Port *mem_dport = mem->getPort("");
+ dcachePort->setPeer(mem_dport);
+ mem_dport->setPeer(dcachePort);
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setDcachePort(dcachePort);
+ }
+#endif
+}
+
+template<class Impl>
+std::string
+LSQUnit<Impl>::name() const
+{
+ if (Impl::MaxThreads == 1) {
+ return iewStage->name() + ".lsq";
+ } else {
+ return iewStage->name() + ".lsq.thread." + to_string(lsqID);
+ }
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::regStats()
+{
+ lsqForwLoads
+ .name(name() + ".forwLoads")
+ .desc("Number of loads that had data forwarded from stores");
+
+ invAddrLoads
+ .name(name() + ".invAddrLoads")
+ .desc("Number of loads ignored due to an invalid address");
+
+ lsqSquashedLoads
+ .name(name() + ".squashedLoads")
+ .desc("Number of loads squashed");
+
+ lsqIgnoredResponses
+ .name(name() + ".ignoredResponses")
+ .desc("Number of memory responses ignored because the instruction is squashed");
+
+ lsqSquashedStores
+ .name(name() + ".squashedStores")
+ .desc("Number of stores squashed");
+
+ invAddrSwpfs
+ .name(name() + ".invAddrSwpfs")
+ .desc("Number of software prefetches ignored due to an invalid address");
+
+ lsqBlockedLoads
+ .name(name() + ".blockedLoads")
+ .desc("Number of blocked loads due to partial load-store forwarding");
+
+ lsqRescheduledLoads
+ .name(name() + ".rescheduledLoads")
+ .desc("Number of loads that were rescheduled");
+
+ lsqCacheBlocked
+ .name(name() + ".cacheBlocked")
+ .desc("Number of times an access to memory failed due to the cache being blocked");
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::clearLQ()
+{
+ loadQueue.clear();
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::clearSQ()
+{
+ storeQueue.clear();
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::switchOut()
+{
+ switchedOut = true;
+ for (int i = 0; i < loadQueue.size(); ++i)
+ loadQueue[i] = NULL;
+
+ assert(storesToWB == 0);
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::takeOverFrom()
+{
+ switchedOut = false;
+ loads = stores = storesToWB = 0;
+
+ loadHead = loadTail = 0;
+
+ storeHead = storeWBIdx = storeTail = 0;
+
+ usedPorts = 0;
+
+ memDepViolator = NULL;
+
+ blockedLoadSeqNum = 0;
+
+ stalled = false;
+ isLoadBlocked = false;
+ loadBlockedHandled = false;
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::resizeLQ(unsigned size)
+{
+ unsigned size_plus_sentinel = size + 1;
+ assert(size_plus_sentinel >= LQEntries);
+
+ if (size_plus_sentinel > LQEntries) {
+ while (size_plus_sentinel > loadQueue.size()) {
+ DynInstPtr dummy;
+ loadQueue.push_back(dummy);
+ LQEntries++;
+ }
+ } else {
+ LQEntries = size_plus_sentinel;
+ }
+
+}
+
+template<class Impl>
+void
+LSQUnit<Impl>::resizeSQ(unsigned size)
+{
+ unsigned size_plus_sentinel = size + 1;
+ if (size_plus_sentinel > SQEntries) {
+ while (size_plus_sentinel > storeQueue.size()) {
+ SQEntry dummy;
+ storeQueue.push_back(dummy);
+ SQEntries++;
+ }
+ } else {
+ SQEntries = size_plus_sentinel;
+ }
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::insert(DynInstPtr &inst)
+{
+ assert(inst->isMemRef());
+
+ assert(inst->isLoad() || inst->isStore());
+
+ if (inst->isLoad()) {
+ insertLoad(inst);
+ } else {
+ insertStore(inst);
+ }
+
+ inst->setInLSQ();
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
+{
+ assert((loadTail + 1) % LQEntries != loadHead);
+ assert(loads < LQEntries);
+
+ DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
+ load_inst->readPC(), loadTail, load_inst->seqNum);
+
+ load_inst->lqIdx = loadTail;
+
+ if (stores == 0) {
+ load_inst->sqIdx = -1;
+ } else {
+ load_inst->sqIdx = storeTail;
+ }
+
+ loadQueue[loadTail] = load_inst;
+
+ incrLdIdx(loadTail);
+
+ ++loads;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
+{
+ // Make sure it is not full before inserting an instruction.
+ assert((storeTail + 1) % SQEntries != storeHead);
+ assert(stores < SQEntries);
+
+ DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
+ store_inst->readPC(), storeTail, store_inst->seqNum);
+
+ store_inst->sqIdx = storeTail;
+ store_inst->lqIdx = loadTail;
+
+ storeQueue[storeTail] = SQEntry(store_inst);
+
+ incrStIdx(storeTail);
+
+ ++stores;
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+LSQUnit<Impl>::getMemDepViolator()
+{
+ DynInstPtr temp = memDepViolator;
+
+ memDepViolator = NULL;
+
+ return temp;
+}
+
+template <class Impl>
+unsigned
+LSQUnit<Impl>::numFreeEntries()
+{
+ unsigned free_lq_entries = LQEntries - loads;
+ unsigned free_sq_entries = SQEntries - stores;
+
+ // Both the LQ and SQ entries have an extra dummy entry to differentiate
+ // empty/full conditions. Subtract 1 from the free entries.
+ if (free_lq_entries < free_sq_entries) {
+ return free_lq_entries - 1;
+ } else {
+ return free_sq_entries - 1;
+ }
+}
+
+template <class Impl>
+int
+LSQUnit<Impl>::numLoadsReady()
+{
+ int load_idx = loadHead;
+ int retval = 0;
+
+ while (load_idx != loadTail) {
+ assert(loadQueue[load_idx]);
+
+ if (loadQueue[load_idx]->readyToIssue()) {
+ ++retval;
+ }
+ }
+
+ return retval;
+}
+
+template <class Impl>
+Fault
+LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
+{
+ // Execute a specific load.
+ Fault load_fault = NoFault;
+
+ DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
+ inst->readPC(),inst->seqNum);
+
+ load_fault = inst->initiateAcc();
+
+ // If the instruction faulted, then we need to send it along to commit
+ // without the instruction completing.
+ if (load_fault != NoFault) {
+ // Send this instruction to commit, also make sure iew stage
+ // realizes there is activity.
+ iewStage->instToCommit(inst);
+ iewStage->activityThisCycle();
+ }
+
+ return load_fault;
+}
+
+template <class Impl>
+Fault
+LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
+{
+ using namespace TheISA;
+ // Make sure that a store exists.
+ assert(stores != 0);
+
+ int store_idx = store_inst->sqIdx;
+
+ DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
+ store_inst->readPC(), store_inst->seqNum);
+
+ // Check the recently completed loads to see if any match this store's
+ // address. If so, then we have a memory ordering violation.
+ int load_idx = store_inst->lqIdx;
+
+ Fault store_fault = store_inst->initiateAcc();
+
+ if (storeQueue[store_idx].size == 0) {
+ DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
+ store_inst->readPC(),store_inst->seqNum);
+
+ return store_fault;
+ }
+
+ assert(store_fault == NoFault);
+
+ if (store_inst->isStoreConditional()) {
+ // Store conditionals need to set themselves as able to
+ // writeback if we haven't had a fault by here.
+ storeQueue[store_idx].canWB = true;
+
+ ++storesToWB;
+ }
+
+ if (!memDepViolator) {
+ while (load_idx != loadTail) {
+ // Really only need to check loads that have actually executed
+ // It's safe to check all loads because effAddr is set to
+ // InvalAddr when the dyn inst is created.
+
+ // @todo: For now this is extra conservative, detecting a
+ // violation if the addresses match assuming all accesses
+ // are quad word accesses.
+
+ // @todo: Fix this, magic number being used here
+ if ((loadQueue[load_idx]->effAddr >> 8) ==
+ (store_inst->effAddr >> 8)) {
+ // A load incorrectly passed this store. Squash and refetch.
+ // For now return a fault to show that it was unsuccessful.
+ memDepViolator = loadQueue[load_idx];
+
+ return genMachineCheckFault();
+ }
+
+ incrLdIdx(load_idx);
+ }
+
+ // If we've reached this point, there was no violation.
+ memDepViolator = NULL;
+ }
+
+ return store_fault;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::commitLoad()
+{
+ assert(loadQueue[loadHead]);
+
+ DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
+ loadQueue[loadHead]->readPC());
+
+ loadQueue[loadHead] = NULL;
+
+ incrLdIdx(loadHead);
+
+ --loads;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
+{
+ assert(loads == 0 || loadQueue[loadHead]);
+
+ while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
+ commitLoad();
+ }
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
+{
+ assert(stores == 0 || storeQueue[storeHead].inst);
+
+ int store_idx = storeHead;
+
+ while (store_idx != storeTail) {
+ assert(storeQueue[store_idx].inst);
+ // Mark any stores that are now committed and have not yet
+ // been marked as able to write back.
+ if (!storeQueue[store_idx].canWB) {
+ if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
+ break;
+ }
+ DPRINTF(LSQUnit, "Marking store as able to write back, PC "
+ "%#x [sn:%lli]\n",
+ storeQueue[store_idx].inst->readPC(),
+ storeQueue[store_idx].inst->seqNum);
+
+ storeQueue[store_idx].canWB = true;
+
+ ++storesToWB;
+ }
+
+ incrStIdx(store_idx);
+ }
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::writebackStores()
+{
+ while (storesToWB > 0 &&
+ storeWBIdx != storeTail &&
+ storeQueue[storeWBIdx].inst &&
+ storeQueue[storeWBIdx].canWB &&
+ usedPorts < cachePorts) {
+
+ if (isStoreBlocked) {
+ DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
+ " is blocked!\n");
+ break;
+ }
+
+ // Store didn't write any data so no need to write it back to
+ // memory.
+ if (storeQueue[storeWBIdx].size == 0) {
+ completeStore(storeWBIdx);
+
+ incrStIdx(storeWBIdx);
+
+ continue;
+ }
+
+ ++usedPorts;
+
+ if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
+ incrStIdx(storeWBIdx);
+
+ continue;
+ }
+
+ assert(storeQueue[storeWBIdx].req);
+ assert(!storeQueue[storeWBIdx].committed);
+
+ DynInstPtr inst = storeQueue[storeWBIdx].inst;
+
+ Request *req = storeQueue[storeWBIdx].req;
+ storeQueue[storeWBIdx].committed = true;
+
+ assert(!inst->memData);
+ inst->memData = new uint8_t[64];
+ memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data,
+ req->getSize());
+
+ PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
+ data_pkt->dataStatic(inst->memData);
+
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = false;
+ state->idx = storeWBIdx;
+ state->inst = inst;
+ data_pkt->senderState = state;
+
+ DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
+ "to Addr:%#x, data:%#x [sn:%lli]\n",
+ storeWBIdx, storeQueue[storeWBIdx].inst->readPC(),
+ req->getPaddr(), *(inst->memData),
+ storeQueue[storeWBIdx].inst->seqNum);
+
+ // @todo: Remove this SC hack once the memory system handles it.
+ if (req->getFlags() & LOCKED) {
+ if (req->getFlags() & UNCACHEABLE) {
+ req->setScResult(2);
+ } else {
+ if (cpu->lockFlag) {
+ req->setScResult(1);
+ } else {
+ req->setScResult(0);
+ // Hack: Instantly complete this store.
+ completeDataAccess(data_pkt);
+ incrStIdx(storeWBIdx);
+ continue;
+ }
+ }
+ } else {
+ // Non-store conditionals do not need a writeback.
+ state->noWB = true;
+ }
+
+ if (!dcachePort->sendTiming(data_pkt)) {
+ // Need to handle becoming blocked on a store.
+ isStoreBlocked = true;
+ ++lsqCacheBlocked;
+ assert(retryPkt == NULL);
+ retryPkt = data_pkt;
+ } else {
+ storePostSend(data_pkt);
+ }
+ }
+
+ // Not sure this should set it to 0.
+ usedPorts = 0;
+
+ assert(stores >= 0 && storesToWB >= 0);
+}
+
+/*template <class Impl>
+void
+LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
+{
+ list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
+ mshrSeqNums.end(),
+ seqNum);
+
+ if (mshr_it != mshrSeqNums.end()) {
+ mshrSeqNums.erase(mshr_it);
+ DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
+ }
+}*/
+
+template <class Impl>
+void
+LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
+{
+ DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
+ "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);
+
+ int load_idx = loadTail;
+ decrLdIdx(load_idx);
+
+ while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
+ DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
+ "[sn:%lli]\n",
+ loadQueue[load_idx]->readPC(),
+ loadQueue[load_idx]->seqNum);
+
+ if (isStalled() && load_idx == stallingLoadIdx) {
+ stalled = false;
+ stallingStoreIsn = 0;
+ stallingLoadIdx = 0;
+ }
+
+ // Clear the smart pointer to make sure it is decremented.
+ loadQueue[load_idx]->setSquashed();
+ loadQueue[load_idx] = NULL;
+ --loads;
+
+ // Inefficient!
+ loadTail = load_idx;
+
+ decrLdIdx(load_idx);
+ ++lsqSquashedLoads;
+ }
+
+ if (isLoadBlocked) {
+ if (squashed_num < blockedLoadSeqNum) {
+ isLoadBlocked = false;
+ loadBlockedHandled = false;
+ blockedLoadSeqNum = 0;
+ }
+ }
+
+ int store_idx = storeTail;
+ decrStIdx(store_idx);
+
+ while (stores != 0 &&
+ storeQueue[store_idx].inst->seqNum > squashed_num) {
+ // Instructions marked as can WB are already committed.
+ if (storeQueue[store_idx].canWB) {
+ break;
+ }
+
+ DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
+ "idx:%i [sn:%lli]\n",
+ storeQueue[store_idx].inst->readPC(),
+ store_idx, storeQueue[store_idx].inst->seqNum);
+
+ // I don't think this can happen. It should have been cleared
+ // by the stalling load.
+ if (isStalled() &&
+ storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
+ panic("Is stalled should have been cleared by stalling load!\n");
+ stalled = false;
+ stallingStoreIsn = 0;
+ }
+
+ // Clear the smart pointer to make sure it is decremented.
+ storeQueue[store_idx].inst->setSquashed();
+ storeQueue[store_idx].inst = NULL;
+ storeQueue[store_idx].canWB = 0;
+
+ storeQueue[store_idx].req = NULL;
+ --stores;
+
+ // Inefficient!
+ storeTail = store_idx;
+
+ decrStIdx(store_idx);
+ ++lsqSquashedStores;
+ }
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::storePostSend(Packet *pkt)
+{
+ if (isStalled() &&
+ storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
+ DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
+ "load idx:%i\n",
+ stallingStoreIsn, stallingLoadIdx);
+ stalled = false;
+ stallingStoreIsn = 0;
+ iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
+ }
+
+ if (!storeQueue[storeWBIdx].inst->isStoreConditional()) {
+ // The store is basically completed at this time. This
+ // only works so long as the checker doesn't try to
+ // verify the value in memory for stores.
+ storeQueue[storeWBIdx].inst->setCompleted();
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->verify(storeQueue[storeWBIdx].inst);
+ }
+#endif
+ }
+
+ if (pkt->result != Packet::Success) {
+ DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n",
+ storeWBIdx);
+
+ DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
+ storeQueue[storeWBIdx].inst->seqNum);
+
+ //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
+
+ //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
+
+ // @todo: Increment stat here.
+ } else {
+ DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
+ storeWBIdx);
+
+ DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
+ storeQueue[storeWBIdx].inst->seqNum);
+ }
+
+ incrStIdx(storeWBIdx);
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
+{
+ iewStage->wakeCPU();
+
+ // Squashed instructions do not need to complete their access.
+ if (inst->isSquashed()) {
+ assert(!inst->isStore());
+ ++lsqIgnoredResponses;
+ return;
+ }
+
+ if (!inst->isExecuted()) {
+ inst->setExecuted();
+
+ // Complete access to copy data to proper place.
+ inst->completeAcc(pkt);
+ }
+
+ // Need to insert instruction into queue to commit
+ iewStage->instToCommit(inst);
+
+ iewStage->activityThisCycle();
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::completeStore(int store_idx)
+{
+ assert(storeQueue[store_idx].inst);
+ storeQueue[store_idx].completed = true;
+ --storesToWB;
+ // A bit conservative because a store completion may not free up entries,
+ // but hopefully avoids two store completions in one cycle from making
+ // the CPU tick twice.
+ cpu->activityThisCycle();
+
+ if (store_idx == storeHead) {
+ do {
+ incrStIdx(storeHead);
+
+ --stores;
+ } while (storeQueue[storeHead].completed &&
+ storeHead != storeTail);
+
+ iewStage->updateLSQNextCycle = true;
+ }
+
+ DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "
+ "idx:%i\n",
+ storeQueue[store_idx].inst->seqNum, store_idx, storeHead);
+
+ if (isStalled() &&
+ storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
+ DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
+ "load idx:%i\n",
+ stallingStoreIsn, stallingLoadIdx);
+ stalled = false;
+ stallingStoreIsn = 0;
+ iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
+ }
+
+ storeQueue[store_idx].inst->setCompleted();
+
+ // Tell the checker we've completed this instruction. Some stores
+ // may get reported twice to the checker, but the checker can
+ // handle that case.
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->verify(storeQueue[store_idx].inst);
+ }
+#endif
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::recvRetry()
+{
+ if (isStoreBlocked) {
+ assert(retryPkt != NULL);
+
+ if (dcachePort->sendTiming(retryPkt)) {
+ storePostSend(retryPkt);
+ retryPkt = NULL;
+ isStoreBlocked = false;
+ } else {
+ // Still blocked!
+ ++lsqCacheBlocked;
+ }
+ } else if (isLoadBlocked) {
+ DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, "
+ "no need to resend packet.\n");
+ } else {
+ DPRINTF(LSQUnit, "Retry received but LSQ is no longer blocked.\n");
+ }
+}
+
+template <class Impl>
+inline void
+LSQUnit<Impl>::incrStIdx(int &store_idx)
+{
+ if (++store_idx >= SQEntries)
+ store_idx = 0;
+}
+
+template <class Impl>
+inline void
+LSQUnit<Impl>::decrStIdx(int &store_idx)
+{
+ if (--store_idx < 0)
+ store_idx += SQEntries;
+}
+
+template <class Impl>
+inline void
+LSQUnit<Impl>::incrLdIdx(int &load_idx)
+{
+ if (++load_idx >= LQEntries)
+ load_idx = 0;
+}
+
+template <class Impl>
+inline void
+LSQUnit<Impl>::decrLdIdx(int &load_idx)
+{
+ if (--load_idx < 0)
+ load_idx += LQEntries;
+}
+
+template <class Impl>
+void
+LSQUnit<Impl>::dumpInsts()
+{
+ cprintf("Load store queue: Dumping instructions.\n");
+ cprintf("Load queue size: %i\n", loads);
+ cprintf("Load queue: ");
+
+ int load_idx = loadHead;
+
+ while (load_idx != loadTail && loadQueue[load_idx]) {
+ cprintf("%#x ", loadQueue[load_idx]->readPC());
+
+ incrLdIdx(load_idx);
+ }
+
+ cprintf("Store queue size: %i\n", stores);
+ cprintf("Store queue: ");
+
+ int store_idx = storeHead;
+
+ while (store_idx != storeTail && storeQueue[store_idx].inst) {
+ cprintf("%#x ", storeQueue[store_idx].inst->readPC());
+
+ incrStIdx(store_idx);
+ }
+
+ cprintf("\n");
+}
diff --git a/src/cpu/o3/mem_dep_unit.cc b/src/cpu/o3/mem_dep_unit.cc
index 9c1e7f9d8..6a14dcbff 100644
--- a/src/cpu/o3/mem_dep_unit.cc
+++ b/src/cpu/o3/mem_dep_unit.cc
@@ -24,13 +24,26 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/store_set.hh"
#include "cpu/o3/mem_dep_unit_impl.hh"
// Force instantation of memory dependency unit using store sets and
-// AlphaSimpleImpl.
-template class MemDepUnit<StoreSet, AlphaSimpleImpl>;
+// O3CPUImpl.
+template class MemDepUnit<StoreSet, O3CPUImpl>;
+
+#ifdef DEBUG
+template <>
+int
+MemDepUnit<StoreSet, O3CPUImpl>::MemDepEntry::memdep_count = 0;
+template <>
+int
+MemDepUnit<StoreSet, O3CPUImpl>::MemDepEntry::memdep_insert = 0;
+template <>
+int
+MemDepUnit<StoreSet, O3CPUImpl>::MemDepEntry::memdep_erase = 0;
+#endif
diff --git a/src/cpu/o3/mem_dep_unit.hh b/src/cpu/o3/mem_dep_unit.hh
index ca63577a1..e399f0133 100644
--- a/src/cpu/o3/mem_dep_unit.hh
+++ b/src/cpu/o3/mem_dep_unit.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,17 +24,33 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_MEM_DEP_UNIT_HH__
-#define __CPU_O3_CPU_MEM_DEP_UNIT_HH__
+#ifndef __CPU_O3_MEM_DEP_UNIT_HH__
+#define __CPU_O3_MEM_DEP_UNIT_HH__
-#include <map>
+#include <list>
#include <set>
+#include "base/hashmap.hh"
+#include "base/refcnt.hh"
#include "base/statistics.hh"
#include "cpu/inst_seq.hh"
+struct SNHash {
+ size_t operator() (const InstSeqNum &seq_num) const {
+ unsigned a = (unsigned)seq_num;
+ unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+ return hash;
+ }
+};
+
+template <class Impl>
+class InstructionQueue;
+
/**
* Memory dependency unit class. This holds the memory dependence predictor.
* As memory operations are issued to the IQ, they are also issued to this
@@ -52,101 +68,166 @@ class MemDepUnit {
typedef typename Impl::Params Params;
typedef typename Impl::DynInstPtr DynInstPtr;
- public:
- MemDepUnit(Params &params);
+ /** Empty constructor. Must call init() prior to using in this case. */
+ MemDepUnit() {}
+
+ /** Constructs a MemDepUnit with given parameters. */
+ MemDepUnit(Params *params);
+
+ /** Frees up any memory allocated. */
+ ~MemDepUnit();
+
+ /** Returns the name of the memory dependence unit. */
+ std::string name() const;
+
+ /** Initializes the unit with parameters and a thread id. */
+ void init(Params *params, int tid);
+ /** Registers statistics. */
void regStats();
+ /** Switches out the memory dependence predictor. */
+ void switchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Sets the pointer to the IQ. */
+ void setIQ(InstructionQueue<Impl> *iq_ptr);
+
+ /** Inserts a memory instruction. */
void insert(DynInstPtr &inst);
+ /** Inserts a non-speculative memory instruction. */
void insertNonSpec(DynInstPtr &inst);
- // Will want to make this operation relatively fast. Right now it
- // is somewhat slow.
- DynInstPtr &top();
-
- void pop();
+ /** Inserts a barrier instruction. */
+ void insertBarrier(DynInstPtr &barr_inst);
+ /** Indicate that an instruction has its registers ready. */
void regsReady(DynInstPtr &inst);
+ /** Indicate that a non-speculative instruction is ready. */
void nonSpecInstReady(DynInstPtr &inst);
- void issue(DynInstPtr &inst);
+ /** Reschedules an instruction to be re-executed. */
+ void reschedule(DynInstPtr &inst);
+
+ /** Replays all instructions that have been rescheduled by moving them to
+ * the ready list.
+ */
+ void replay(DynInstPtr &inst);
+
+ /** Completes a memory instruction. */
+ void completed(DynInstPtr &inst);
+
+ /** Completes a barrier instruction. */
+ void completeBarrier(DynInstPtr &inst);
+ /** Wakes any dependents of a memory instruction. */
void wakeDependents(DynInstPtr &inst);
- void squash(const InstSeqNum &squashed_num);
+ /** Squashes all instructions up until a given sequence number for a
+ * specific thread.
+ */
+ void squash(const InstSeqNum &squashed_num, unsigned tid);
+ /** Indicates an ordering violation between a store and a younger load. */
void violation(DynInstPtr &store_inst, DynInstPtr &violating_load);
- inline bool empty()
- { return readyInsts.empty(); }
+ /** Issues the given instruction */
+ void issue(DynInstPtr &inst);
+
+ /** Debugging function to dump the lists of instructions. */
+ void dumpLists();
private:
- typedef typename std::set<InstSeqNum>::iterator sn_it_t;
- typedef typename std::map<InstSeqNum, DynInstPtr>::iterator dyn_it_t;
-
- // Forward declarations so that the following two typedefs work.
- class Dependency;
- class ltDependency;
-
- typedef typename std::set<Dependency, ltDependency>::iterator dep_it_t;
- typedef typename std::map<InstSeqNum, vector<dep_it_t> >::iterator
- sd_it_t;
-
- struct Dependency {
- Dependency(const InstSeqNum &_seqNum)
- : seqNum(_seqNum), regsReady(0), memDepReady(0)
- { }
-
- Dependency(const InstSeqNum &_seqNum, bool _regsReady,
- bool _memDepReady)
- : seqNum(_seqNum), regsReady(_regsReady),
- memDepReady(_memDepReady)
- { }
-
- InstSeqNum seqNum;
- mutable bool regsReady;
- mutable bool memDepReady;
- mutable sd_it_t storeDep;
- };
+ typedef typename std::list<DynInstPtr>::iterator ListIt;
+
+ class MemDepEntry;
- struct ltDependency {
- bool operator() (const Dependency &lhs, const Dependency &rhs)
+ typedef RefCountingPtr<MemDepEntry> MemDepEntryPtr;
+
+ /** Memory dependence entries that track memory operations, marking
+ * when the instruction is ready to execute and what instructions depend
+ * upon it.
+ */
+ class MemDepEntry : public RefCounted {
+ public:
+ /** Constructs a memory dependence entry. */
+ MemDepEntry(DynInstPtr &new_inst)
+ : inst(new_inst), regsReady(false), memDepReady(false),
+ completed(false), squashed(false)
{
- return lhs.seqNum < rhs.seqNum;
+#ifdef DEBUG
+ ++memdep_count;
+
+ DPRINTF(MemDepUnit, "Memory dependency entry created. "
+ "memdep_count=%i\n", memdep_count);
+#endif
}
+
+ /** Frees any pointers. */
+ ~MemDepEntry()
+ {
+ for (int i = 0; i < dependInsts.size(); ++i) {
+ dependInsts[i] = NULL;
+ }
+#ifdef DEBUG
+ --memdep_count;
+
+ DPRINTF(MemDepUnit, "Memory dependency entry deleted. "
+ "memdep_count=%i\n", memdep_count);
+#endif
+ }
+
+ /** Returns the name of the memory dependence entry. */
+ std::string name() const { return "memdepentry"; }
+
+ /** The instruction being tracked. */
+ DynInstPtr inst;
+
+ /** The iterator to the instruction's location inside the list. */
+ ListIt listIt;
+
+ /** A vector of any dependent instructions. */
+ std::vector<MemDepEntryPtr> dependInsts;
+
+ /** If the registers are ready or not. */
+ bool regsReady;
+ /** If all memory dependencies have been satisfied. */
+ bool memDepReady;
+ /** If the instruction is completed. */
+ bool completed;
+ /** If the instruction is squashed. */
+ bool squashed;
+
+ /** For debugging. */
+#ifdef DEBUG
+ static int memdep_count;
+ static int memdep_insert;
+ static int memdep_erase;
+#endif
};
- inline void moveToReady(dep_it_t &woken_inst);
+ /** Finds the memory dependence entry in the hash map. */
+ inline MemDepEntryPtr &findInHash(const DynInstPtr &inst);
- /** List of instructions that have passed through rename, yet are still
- * waiting on either a memory dependence to resolve or source registers to
- * become available before they can issue.
- */
- std::set<Dependency, ltDependency> waitingInsts;
+ /** Moves an entry to the ready list. */
+ inline void moveToReady(MemDepEntryPtr &ready_inst_entry);
- /** List of instructions that have all their predicted memory dependences
- * resolved and their source registers ready.
- */
- std::set<InstSeqNum> readyInsts;
+ typedef m5::hash_map<InstSeqNum, MemDepEntryPtr, SNHash> MemDepHash;
- // Change this to hold a vector of iterators, which will point to the
- // entry of the waiting instructions.
- /** List of stores' sequence numbers, each of which has a vector of
- * iterators. The iterators point to the appropriate node within
- * waitingInsts that has the depenendent instruction.
- */
- std::map<InstSeqNum, vector<dep_it_t> > storeDependents;
+ typedef typename MemDepHash::iterator MemDepHashIt;
- // For now will implement this as a map...hash table might not be too
- // bad, or could move to something that mimics the current dependency
- // graph.
- std::map<InstSeqNum, DynInstPtr> memInsts;
+ /** A hash map of all memory dependence entries. */
+ MemDepHash memDepHash;
- // Iterator pointer to the top instruction which has is ready.
- // Is set by the top() call.
- dyn_it_t topInst;
+ /** A list of all instructions in the memory dependence unit. */
+ std::list<DynInstPtr> instList[Impl::MaxThreads];
+
+ /** A list of all instructions that are going to be replayed. */
+ std::list<DynInstPtr> instsToReplay;
/** The memory dependence predictor. It is accessed upon new
* instructions being added to the IQ, and responds by telling
@@ -155,10 +236,29 @@ class MemDepUnit {
*/
MemDepPred depPred;
+ /** Is there an outstanding load barrier that loads must wait on. */
+ bool loadBarrier;
+ /** The sequence number of the load barrier. */
+ InstSeqNum loadBarrierSN;
+ /** Is there an outstanding store barrier that loads must wait on. */
+ bool storeBarrier;
+ /** The sequence number of the store barrier. */
+ InstSeqNum storeBarrierSN;
+
+ /** Pointer to the IQ. */
+ InstructionQueue<Impl> *iqPtr;
+
+ /** The thread id of this memory dependence unit. */
+ int id;
+
+ /** Stat for number of inserted loads. */
Stats::Scalar<> insertedLoads;
+ /** Stat for number of inserted stores. */
Stats::Scalar<> insertedStores;
+ /** Stat for number of conflicting loads that had to wait for a store. */
Stats::Scalar<> conflictingLoads;
+ /** Stat for number of conflicting stores that had to wait for a store. */
Stats::Scalar<> conflictingStores;
};
-#endif // __CPU_O3_CPU_MEM_DEP_UNIT_HH__
+#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 296db4c4e..16f67a4e0 100644
--- a/src/cpu/o3/mem_dep_unit_impl.hh
+++ b/src/cpu/o3/mem_dep_unit_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,17 +24,64 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <map>
+#include "cpu/o3/inst_queue.hh"
#include "cpu/o3/mem_dep_unit.hh"
template <class MemDepPred, class Impl>
-MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params &params)
- : depPred(params.SSITSize, params.LFSTSize)
+MemDepUnit<MemDepPred, Impl>::MemDepUnit(Params *params)
+ : depPred(params->SSITSize, params->LFSTSize), loadBarrier(false),
+ loadBarrierSN(0), storeBarrier(false), storeBarrierSN(0), iqPtr(NULL)
+{
+ DPRINTF(MemDepUnit, "Creating MemDepUnit object.\n");
+}
+
+template <class MemDepPred, class Impl>
+MemDepUnit<MemDepPred, Impl>::~MemDepUnit()
+{
+ for (int tid=0; tid < Impl::MaxThreads; tid++) {
+
+ ListIt inst_list_it = instList[tid].begin();
+
+ MemDepHashIt hash_it;
+
+ while (!instList[tid].empty()) {
+ hash_it = memDepHash.find((*inst_list_it)->seqNum);
+
+ assert(hash_it != memDepHash.end());
+
+ memDepHash.erase(hash_it);
+
+ instList[tid].erase(inst_list_it++);
+ }
+ }
+
+#ifdef DEBUG
+ assert(MemDepEntry::memdep_count == 0);
+#endif
+}
+
+template <class MemDepPred, class Impl>
+std::string
+MemDepUnit<MemDepPred, Impl>::name() const
{
- DPRINTF(MemDepUnit, "MemDepUnit: Creating MemDepUnit object.\n");
+ return "memdepunit";
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::init(Params *params, int tid)
+{
+ DPRINTF(MemDepUnit, "Creating MemDepUnit %i object.\n",tid);
+
+ id = tid;
+
+ depPred.init(params->SSITSize, params->LFSTSize);
}
template <class MemDepPred, class Impl>
@@ -60,56 +107,99 @@ MemDepUnit<MemDepPred, Impl>::regStats()
template <class MemDepPred, class Impl>
void
+MemDepUnit<MemDepPred, Impl>::switchOut()
+{
+ // Clear any state.
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ instList[i].clear();
+ }
+ instsToReplay.clear();
+ memDepHash.clear();
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::takeOverFrom()
+{
+ // Be sure to reset all state.
+ loadBarrier = storeBarrier = false;
+ loadBarrierSN = storeBarrierSN = 0;
+ depPred.clear();
+}
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::setIQ(InstructionQueue<Impl> *iq_ptr)
+{
+ iqPtr = iq_ptr;
+}
+
+template <class MemDepPred, class Impl>
+void
MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst)
{
- InstSeqNum inst_seq_num = inst->seqNum;
+ unsigned tid = inst->threadNumber;
+
+ MemDepEntryPtr inst_entry = new MemDepEntry(inst);
+
+ // Add the MemDepEntry to the hash.
+ memDepHash.insert(
+ std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry));
+#ifdef DEBUG
+ MemDepEntry::memdep_insert++;
+#endif
- Dependency unresolved_dependencies(inst_seq_num);
+ instList[tid].push_back(inst);
- InstSeqNum producing_store = depPred.checkInst(inst->readPC());
+ inst_entry->listIt = --(instList[tid].end());
- if (producing_store == 0 ||
- storeDependents.find(producing_store) == storeDependents.end()) {
+ // Check any barriers and the dependence predictor for any
+ // producing memrefs/stores.
+ InstSeqNum producing_store;
+ if (inst->isLoad() && loadBarrier) {
+ producing_store = loadBarrierSN;
+ } else if (inst->isStore() && storeBarrier) {
+ producing_store = storeBarrierSN;
+ } else {
+ producing_store = depPred.checkInst(inst->readPC());
+ }
- DPRINTF(MemDepUnit, "MemDepUnit: No dependency for inst PC "
- "%#x.\n", inst->readPC());
+ MemDepEntryPtr store_entry = NULL;
- unresolved_dependencies.storeDep = storeDependents.end();
+ // If there is a producing store, try to find the entry.
+ if (producing_store != 0) {
+ MemDepHashIt hash_it = memDepHash.find(producing_store);
+
+ if (hash_it != memDepHash.end()) {
+ store_entry = (*hash_it).second;
+ }
+ }
+
+ // If no store entry, then instruction can issue as soon as the registers
+ // are ready.
+ if (!store_entry) {
+ DPRINTF(MemDepUnit, "No dependency for inst PC "
+ "%#x [sn:%lli].\n", inst->readPC(), inst->seqNum);
+
+ inst_entry->memDepReady = true;
if (inst->readyToIssue()) {
- readyInsts.insert(inst_seq_num);
- } else {
- unresolved_dependencies.memDepReady = true;
+ inst_entry->regsReady = true;
- waitingInsts.insert(unresolved_dependencies);
+ moveToReady(inst_entry);
}
} else {
- DPRINTF(MemDepUnit, "MemDepUnit: Adding to dependency list; "
- "inst PC %#x is dependent on seq num %i.\n",
+ // Otherwise make the instruction dependent on the store/barrier.
+ DPRINTF(MemDepUnit, "Adding to dependency list; "
+ "inst PC %#x is dependent on [sn:%lli].\n",
inst->readPC(), producing_store);
if (inst->readyToIssue()) {
- unresolved_dependencies.regsReady = true;
+ inst_entry->regsReady = true;
}
- // Find the store that this instruction is dependent on.
- sd_it_t store_loc = storeDependents.find(producing_store);
-
- assert(store_loc != storeDependents.end());
-
- // Record the location of the store that this instruction is
- // dependent on.
- unresolved_dependencies.storeDep = store_loc;
-
- // If it's not already ready, then add it to the renamed
- // list and the dependencies.
- dep_it_t inst_loc =
- (waitingInsts.insert(unresolved_dependencies)).first;
-
// Add this instruction to the list of dependents.
- (*store_loc).second.push_back(inst_loc);
-
- assert(!(*store_loc).second.empty());
+ store_entry->dependInsts.push_back(inst_entry);
if (inst->isLoad()) {
++conflictingLoads;
@@ -119,277 +209,288 @@ MemDepUnit<MemDepPred, Impl>::insert(DynInstPtr &inst)
}
if (inst->isStore()) {
- DPRINTF(MemDepUnit, "MemDepUnit: Inserting store PC %#x.\n",
- inst->readPC());
-
- depPred.insertStore(inst->readPC(), inst_seq_num);
-
- // Make sure this store isn't already in this list.
- assert(storeDependents.find(inst_seq_num) == storeDependents.end());
-
- // Put a dependency entry in at the store's sequence number.
- // Uh, not sure how this works...I want to create an entry but
- // I don't have anything to put into the value yet.
- storeDependents[inst_seq_num];
+ DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
- assert(storeDependents.size() != 0);
+ depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber);
++insertedStores;
-
} else if (inst->isLoad()) {
++insertedLoads;
} else {
- panic("MemDepUnit: Unknown type! (most likely a barrier).");
+ panic("Unknown type! (most likely a barrier).");
}
-
- memInsts[inst_seq_num] = inst;
}
template <class MemDepPred, class Impl>
void
MemDepUnit<MemDepPred, Impl>::insertNonSpec(DynInstPtr &inst)
{
- InstSeqNum inst_seq_num = inst->seqNum;
+ unsigned tid = inst->threadNumber;
+
+ MemDepEntryPtr inst_entry = new MemDepEntry(inst);
- Dependency non_spec_inst(inst_seq_num);
+ // Insert the MemDepEntry into the hash.
+ memDepHash.insert(
+ std::pair<InstSeqNum, MemDepEntryPtr>(inst->seqNum, inst_entry));
+#ifdef DEBUG
+ MemDepEntry::memdep_insert++;
+#endif
- non_spec_inst.storeDep = storeDependents.end();
+ // Add the instruction to the list.
+ instList[tid].push_back(inst);
- waitingInsts.insert(non_spec_inst);
+ inst_entry->listIt = --(instList[tid].end());
// Might want to turn this part into an inline function or something.
// It's shared between both insert functions.
if (inst->isStore()) {
- DPRINTF(MemDepUnit, "MemDepUnit: Inserting store PC %#x.\n",
- inst->readPC());
-
- depPred.insertStore(inst->readPC(), inst_seq_num);
-
- // Make sure this store isn't already in this list.
- assert(storeDependents.find(inst_seq_num) == storeDependents.end());
-
- // Put a dependency entry in at the store's sequence number.
- // Uh, not sure how this works...I want to create an entry but
- // I don't have anything to put into the value yet.
- storeDependents[inst_seq_num];
+ DPRINTF(MemDepUnit, "Inserting store PC %#x [sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
- assert(storeDependents.size() != 0);
+ depPred.insertStore(inst->readPC(), inst->seqNum, inst->threadNumber);
++insertedStores;
-
} else if (inst->isLoad()) {
++insertedLoads;
} else {
- panic("MemDepUnit: Unknown type! (most likely a barrier).");
+ panic("Unknown type! (most likely a barrier).");
}
-
- memInsts[inst_seq_num] = inst;
}
template <class MemDepPred, class Impl>
-typename Impl::DynInstPtr &
-MemDepUnit<MemDepPred, Impl>::top()
+void
+MemDepUnit<MemDepPred, Impl>::insertBarrier(DynInstPtr &barr_inst)
{
- topInst = memInsts.find( (*readyInsts.begin()) );
+ InstSeqNum barr_sn = barr_inst->seqNum;
+ // Memory barriers block loads and stores, write barriers only stores.
+ if (barr_inst->isMemBarrier()) {
+ loadBarrier = true;
+ loadBarrierSN = barr_sn;
+ storeBarrier = true;
+ storeBarrierSN = barr_sn;
+ DPRINTF(MemDepUnit, "Inserted a memory barrier\n");
+ } else if (barr_inst->isWriteBarrier()) {
+ storeBarrier = true;
+ storeBarrierSN = barr_sn;
+ DPRINTF(MemDepUnit, "Inserted a write barrier\n");
+ }
+
+ unsigned tid = barr_inst->threadNumber;
+
+ MemDepEntryPtr inst_entry = new MemDepEntry(barr_inst);
+
+ // Add the MemDepEntry to the hash.
+ memDepHash.insert(
+ std::pair<InstSeqNum, MemDepEntryPtr>(barr_sn, inst_entry));
+#ifdef DEBUG
+ MemDepEntry::memdep_insert++;
+#endif
- DPRINTF(MemDepUnit, "MemDepUnit: Top instruction is PC %#x.\n",
- (*topInst).second->readPC());
+ // Add the instruction to the instruction list.
+ instList[tid].push_back(barr_inst);
- return (*topInst).second;
+ inst_entry->listIt = --(instList[tid].end());
}
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::pop()
+MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst)
{
- DPRINTF(MemDepUnit, "MemDepUnit: Removing instruction PC %#x.\n",
- (*topInst).second->readPC());
+ DPRINTF(MemDepUnit, "Marking registers as ready for "
+ "instruction PC %#x [sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
- wakeDependents((*topInst).second);
+ MemDepEntryPtr inst_entry = findInHash(inst);
- issue((*topInst).second);
+ inst_entry->regsReady = true;
- memInsts.erase(topInst);
+ if (inst_entry->memDepReady) {
+ DPRINTF(MemDepUnit, "Instruction has its memory "
+ "dependencies resolved, adding it to the ready list.\n");
- topInst = memInsts.end();
+ moveToReady(inst_entry);
+ } else {
+ DPRINTF(MemDepUnit, "Instruction still waiting on "
+ "memory dependency.\n");
+ }
}
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::regsReady(DynInstPtr &inst)
+MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst)
{
- DPRINTF(MemDepUnit, "MemDepUnit: Marking registers as ready for "
- "instruction PC %#x.\n",
- inst->readPC());
+ DPRINTF(MemDepUnit, "Marking non speculative "
+ "instruction PC %#x as ready [sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
- InstSeqNum inst_seq_num = inst->seqNum;
+ MemDepEntryPtr inst_entry = findInHash(inst);
+
+ moveToReady(inst_entry);
+}
- Dependency inst_to_find(inst_seq_num);
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::reschedule(DynInstPtr &inst)
+{
+ instsToReplay.push_back(inst);
+}
- dep_it_t waiting_inst = waitingInsts.find(inst_to_find);
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::replay(DynInstPtr &inst)
+{
+ DynInstPtr temp_inst;
+ bool found_inst = false;
- assert(waiting_inst != waitingInsts.end());
+ // For now this replay function replays all waiting memory ops.
+ while (!instsToReplay.empty()) {
+ temp_inst = instsToReplay.front();
- if ((*waiting_inst).memDepReady) {
- DPRINTF(MemDepUnit, "MemDepUnit: Instruction has its memory "
- "dependencies resolved, adding it to the ready list.\n");
+ MemDepEntryPtr inst_entry = findInHash(temp_inst);
- moveToReady(waiting_inst);
- } else {
- DPRINTF(MemDepUnit, "MemDepUnit: Instruction still waiting on "
- "memory dependency.\n");
+ DPRINTF(MemDepUnit, "Replaying mem instruction PC %#x "
+ "[sn:%lli].\n",
+ temp_inst->readPC(), temp_inst->seqNum);
- (*waiting_inst).regsReady = true;
+ moveToReady(inst_entry);
+
+ if (temp_inst == inst) {
+ found_inst = true;
+ }
+
+ instsToReplay.pop_front();
}
+
+ assert(found_inst);
}
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::nonSpecInstReady(DynInstPtr &inst)
+MemDepUnit<MemDepPred, Impl>::completed(DynInstPtr &inst)
{
- DPRINTF(MemDepUnit, "MemDepUnit: Marking non speculative "
- "instruction PC %#x as ready.\n",
- inst->readPC());
+ DPRINTF(MemDepUnit, "Completed mem instruction PC %#x "
+ "[sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
- InstSeqNum inst_seq_num = inst->seqNum;
+ unsigned tid = inst->threadNumber;
- Dependency inst_to_find(inst_seq_num);
+ // Remove the instruction from the hash and the list.
+ MemDepHashIt hash_it = memDepHash.find(inst->seqNum);
- dep_it_t waiting_inst = waitingInsts.find(inst_to_find);
+ assert(hash_it != memDepHash.end());
- assert(waiting_inst != waitingInsts.end());
+ instList[tid].erase((*hash_it).second->listIt);
- moveToReady(waiting_inst);
+ (*hash_it).second = NULL;
+
+ memDepHash.erase(hash_it);
+#ifdef DEBUG
+ MemDepEntry::memdep_erase++;
+#endif
}
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst)
+MemDepUnit<MemDepPred, Impl>::completeBarrier(DynInstPtr &inst)
{
- assert(readyInsts.find(inst->seqNum) != readyInsts.end());
-
- DPRINTF(MemDepUnit, "MemDepUnit: Issuing instruction PC %#x.\n",
- inst->readPC());
-
- // Remove the instruction from the ready list.
- readyInsts.erase(inst->seqNum);
-
- depPred.issued(inst->readPC(), inst->seqNum, inst->isStore());
+ wakeDependents(inst);
+ completed(inst);
+
+ InstSeqNum barr_sn = inst->seqNum;
+
+ if (inst->isMemBarrier()) {
+ assert(loadBarrier && storeBarrier);
+ if (loadBarrierSN == barr_sn)
+ loadBarrier = false;
+ if (storeBarrierSN == barr_sn)
+ storeBarrier = false;
+ } else if (inst->isWriteBarrier()) {
+ assert(storeBarrier);
+ if (storeBarrierSN == barr_sn)
+ storeBarrier = false;
+ }
}
template <class MemDepPred, class Impl>
void
MemDepUnit<MemDepPred, Impl>::wakeDependents(DynInstPtr &inst)
{
- // Only stores have dependents.
- if (!inst->isStore()) {
+ // Only stores and barriers have dependents.
+ if (!inst->isStore() && !inst->isMemBarrier() && !inst->isWriteBarrier()) {
return;
}
- // Wake any dependencies.
- sd_it_t sd_it = storeDependents.find(inst->seqNum);
+ MemDepEntryPtr inst_entry = findInHash(inst);
- // If there's no entry, then return. Really there should only be
- // no entry if the instruction is a load.
- if (sd_it == storeDependents.end()) {
- DPRINTF(MemDepUnit, "MemDepUnit: Instruction PC %#x, sequence "
- "number %i has no dependents.\n",
- inst->readPC(), inst->seqNum);
+ for (int i = 0; i < inst_entry->dependInsts.size(); ++i ) {
+ MemDepEntryPtr woken_inst = inst_entry->dependInsts[i];
- return;
- }
-
- for (int i = 0; i < (*sd_it).second.size(); ++i ) {
- dep_it_t woken_inst = (*sd_it).second[i];
-
- DPRINTF(MemDepUnit, "MemDepUnit: Waking up a dependent inst, "
- "sequence number %i.\n",
- (*woken_inst).seqNum);
-#if 0
- // Should we have reached instructions that are actually squashed,
- // there will be no more useful instructions in this dependency
- // list. Break out early.
- if (waitingInsts.find(woken_inst) == waitingInsts.end()) {
- DPRINTF(MemDepUnit, "MemDepUnit: Dependents on inst PC %#x "
- "are squashed, starting at SN %i. Breaking early.\n",
- inst->readPC(), woken_inst);
- break;
+ if (!woken_inst->inst) {
+ // Potentially removed mem dep entries could be on this list
+ continue;
}
-#endif
- if ((*woken_inst).regsReady) {
+ DPRINTF(MemDepUnit, "Waking up a dependent inst, "
+ "[sn:%lli].\n",
+ woken_inst->inst->seqNum);
+
+ if (woken_inst->regsReady && !woken_inst->squashed) {
moveToReady(woken_inst);
} else {
- (*woken_inst).memDepReady = true;
+ woken_inst->memDepReady = true;
}
}
- storeDependents.erase(sd_it);
+ inst_entry->dependInsts.clear();
}
template <class MemDepPred, class Impl>
void
-MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num)
+MemDepUnit<MemDepPred, Impl>::squash(const InstSeqNum &squashed_num,
+ unsigned tid)
{
-
- if (!waitingInsts.empty()) {
- dep_it_t waiting_it = waitingInsts.end();
-
- --waiting_it;
-
- // Remove entries from the renamed list as long as we haven't reached
- // the end and the entries continue to be younger than the squashed.
- while (!waitingInsts.empty() &&
- (*waiting_it).seqNum > squashed_num)
- {
- if (!(*waiting_it).memDepReady &&
- (*waiting_it).storeDep != storeDependents.end()) {
- sd_it_t sd_it = (*waiting_it).storeDep;
-
- // Make sure the iterator that the store has pointing
- // back is actually to this instruction.
- assert((*sd_it).second.back() == waiting_it);
-
- // Now remove this from the store's list of dependent
- // instructions.
- (*sd_it).second.pop_back();
+ if (!instsToReplay.empty()) {
+ ListIt replay_it = instsToReplay.begin();
+ while (replay_it != instsToReplay.end()) {
+ if ((*replay_it)->threadNumber == tid &&
+ (*replay_it)->seqNum > squashed_num) {
+ instsToReplay.erase(replay_it++);
+ } else {
+ ++replay_it;
}
-
- waitingInsts.erase(waiting_it--);
}
}
- if (!readyInsts.empty()) {
- sn_it_t ready_it = readyInsts.end();
+ ListIt squash_it = instList[tid].end();
+ --squash_it;
- --ready_it;
+ MemDepHashIt hash_it;
- // Same for the ready list.
- while (!readyInsts.empty() &&
- (*ready_it) > squashed_num)
- {
- readyInsts.erase(ready_it--);
- }
- }
+ while (!instList[tid].empty() &&
+ (*squash_it)->seqNum > squashed_num) {
- if (!storeDependents.empty()) {
- sd_it_t dep_it = storeDependents.end();
+ DPRINTF(MemDepUnit, "Squashing inst [sn:%lli]\n",
+ (*squash_it)->seqNum);
- --dep_it;
+ hash_it = memDepHash.find((*squash_it)->seqNum);
- // Same for the dependencies list.
- while (!storeDependents.empty() &&
- (*dep_it).first > squashed_num)
- {
- // This store's list of dependent instructions should be empty.
- assert((*dep_it).second.empty());
+ assert(hash_it != memDepHash.end());
- storeDependents.erase(dep_it--);
- }
+ (*hash_it).second->squashed = true;
+
+ (*hash_it).second = NULL;
+
+ memDepHash.erase(hash_it);
+#ifdef DEBUG
+ MemDepEntry::memdep_erase++;
+#endif
+
+ instList[tid].erase(squash_it--);
}
// Tell the dependency predictor to squash as well.
- depPred.squash(squashed_num);
+ depPred.squash(squashed_num, tid);
}
template <class MemDepPred, class Impl>
@@ -397,7 +498,7 @@ void
MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst,
DynInstPtr &violating_load)
{
- DPRINTF(MemDepUnit, "MemDepUnit: Passing violating PCs to store sets,"
+ DPRINTF(MemDepUnit, "Passing violating PCs to store sets,"
" load: %#x, store: %#x\n", violating_load->readPC(),
store_inst->readPC());
// Tell the memory dependence unit of the violation.
@@ -405,15 +506,66 @@ MemDepUnit<MemDepPred, Impl>::violation(DynInstPtr &store_inst,
}
template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::issue(DynInstPtr &inst)
+{
+ DPRINTF(MemDepUnit, "Issuing instruction PC %#x [sn:%lli].\n",
+ inst->readPC(), inst->seqNum);
+
+ depPred.issued(inst->readPC(), inst->seqNum, inst->isStore());
+}
+
+template <class MemDepPred, class Impl>
+inline typename MemDepUnit<MemDepPred,Impl>::MemDepEntryPtr &
+MemDepUnit<MemDepPred, Impl>::findInHash(const DynInstPtr &inst)
+{
+ MemDepHashIt hash_it = memDepHash.find(inst->seqNum);
+
+ assert(hash_it != memDepHash.end());
+
+ return (*hash_it).second;
+}
+
+template <class MemDepPred, class Impl>
inline void
-MemDepUnit<MemDepPred, Impl>::moveToReady(dep_it_t &woken_inst)
+MemDepUnit<MemDepPred, Impl>::moveToReady(MemDepEntryPtr &woken_inst_entry)
{
- DPRINTF(MemDepUnit, "MemDepUnit: Adding instruction sequence number %i "
- "to the ready list.\n", (*woken_inst).seqNum);
+ DPRINTF(MemDepUnit, "Adding instruction [sn:%lli] "
+ "to the ready list.\n", woken_inst_entry->inst->seqNum);
- // Add it to the ready list.
- readyInsts.insert((*woken_inst).seqNum);
+ assert(!woken_inst_entry->squashed);
+
+ iqPtr->addReadyMemInst(woken_inst_entry->inst);
+}
- // Remove it from the waiting instructions.
- waitingInsts.erase(woken_inst);
+
+template <class MemDepPred, class Impl>
+void
+MemDepUnit<MemDepPred, Impl>::dumpLists()
+{
+ for (unsigned tid=0; tid < Impl::MaxThreads; tid++) {
+ cprintf("Instruction list %i size: %i\n",
+ tid, instList[tid].size());
+
+ ListIt inst_list_it = instList[tid].begin();
+ int num = 0;
+
+ while (inst_list_it != instList[tid].end()) {
+ cprintf("Instruction:%i\nPC:%#x\n[sn:%i]\n[tid:%i]\nIssued:%i\n"
+ "Squashed:%i\n\n",
+ num, (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+ inst_list_it++;
+ ++num;
+ }
+ }
+
+ cprintf("Memory dependence hash size: %i\n", memDepHash.size());
+
+#ifdef DEBUG
+ cprintf("Memory dependence entries: %i\n", MemDepEntry::memdep_count);
+#endif
}
diff --git a/src/cpu/o3/alpha_params.hh b/src/cpu/o3/params.hh
index 79b0937e3..69a1bb937 100644..100755
--- a/src/cpu/o3/alpha_params.hh
+++ b/src/cpu/o3/params.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,45 +24,35 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_ALPHA_SIMPLE_PARAMS_HH__
-#define __CPU_O3_CPU_ALPHA_SIMPLE_PARAMS_HH__
+#ifndef __CPU_O3_PARAMS_HH__
+#define __CPU_O3_PARAMS_HH__
#include "cpu/o3/cpu.hh"
//Forward declarations
-class System;
-class AlphaITB;
-class AlphaDTB;
-class FunctionalMemory;
-class Process;
-class MemInterface;
+class FUPool;
/**
- * This file defines the parameters that will be used for the AlphaFullCPU.
+ * This file defines the parameters that will be used for the O3CPU.
* 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 AlphaSimpleParams : public BaseFullCPU::Params
+class O3Params : public BaseO3CPU::Params
{
public:
-
-#if FULL_SYSTEM
- AlphaITB *itb; AlphaDTB *dtb;
-#else
- std::vector<Process *> workload;
- Process *process;
-#endif // FULL_SYSTEM
-
- FunctionalMemory *mem;
+ unsigned activity;
//
// Caches
//
- MemInterface *icacheInterface;
- MemInterface *dcacheInterface;
+ // MemInterface *icacheInterface;
+ // MemInterface *dcacheInterface;
+
+ unsigned cachePorts;
//
// Fetch
@@ -97,11 +87,7 @@ class AlphaSimpleParams : public BaseFullCPU::Params
unsigned renameToIEWDelay;
unsigned issueToExecuteDelay;
unsigned issueWidth;
- unsigned executeWidth;
- unsigned executeIntWidth;
- unsigned executeFloatWidth;
- unsigned executeBranchWidth;
- unsigned executeMemoryWidth;
+ FUPool *fuPool;
//
// Commit
@@ -110,24 +96,22 @@ class AlphaSimpleParams : public BaseFullCPU::Params
unsigned renameToROBDelay;
unsigned commitWidth;
unsigned squashWidth;
+ Tick trapLatency;
+ Tick fetchTrapLatency;
//
- // Branch predictor (BP & BTB)
+ // Branch predictor (BP, BTB, RAS)
//
-/*
+ std::string predType;
unsigned localPredictorSize;
- unsigned localPredictorCtrBits;
-*/
-
- unsigned local_predictor_size;
- unsigned local_ctr_bits;
- unsigned local_history_table_size;
- unsigned local_history_bits;
- unsigned global_predictor_size;
- unsigned global_ctr_bits;
- unsigned global_history_bits;
- unsigned choice_predictor_size;
- unsigned choice_ctr_bits;
+ unsigned localCtrBits;
+ unsigned localHistoryTableSize;
+ unsigned localHistoryBits;
+ unsigned globalPredictorSize;
+ unsigned globalCtrBits;
+ unsigned globalHistoryBits;
+ unsigned choicePredictorSize;
+ unsigned choiceCtrBits;
unsigned BTBEntries;
unsigned BTBTagSize;
@@ -154,10 +138,24 @@ class AlphaSimpleParams : public BaseFullCPU::Params
unsigned numIQEntries;
unsigned numROBEntries;
+ //SMT Parameters
+ unsigned smtNumFetchingThreads;
+
+ std::string smtFetchPolicy;
+
+ std::string smtIQPolicy;
+ unsigned smtIQThreshold;
+
+ std::string smtLSQPolicy;
+ unsigned smtLSQThreshold;
+
+ std::string smtCommitPolicy;
+
+ std::string smtROBPolicy;
+ unsigned smtROBThreshold;
+
// Probably can get this from somewhere.
unsigned instShiftAmt;
-
- bool defReg;
};
-#endif // __CPU_O3_CPU_ALPHA_PARAMS_HH__
+#endif // __CPU_O3_ALPHA_PARAMS_HH__
diff --git a/src/cpu/o3/ras.cc b/src/cpu/o3/ras.cc
index 0a7d6ca63..f9939259a 100644
--- a/src/cpu/o3/ras.cc
+++ b/src/cpu/o3/ras.cc
@@ -24,16 +24,30 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/ras.hh"
-ReturnAddrStack::ReturnAddrStack(unsigned _numEntries)
- : numEntries(_numEntries), usedEntries(0),
- tos(0)
+void
+ReturnAddrStack::init(unsigned _numEntries)
{
- addrStack = new Addr[numEntries];
+ numEntries = _numEntries;
+ usedEntries = 0;
+ tos = 0;
+
+ addrStack.resize(numEntries);
+
+ for (int i = 0; i < numEntries; ++i)
+ addrStack[i] = 0;
+}
+void
+ReturnAddrStack::reset()
+{
+ usedEntries = 0;
+ tos = 0;
for (int i = 0; i < numEntries; ++i)
addrStack[i] = 0;
}
@@ -53,9 +67,6 @@ ReturnAddrStack::push(const Addr &return_addr)
void
ReturnAddrStack::pop()
{
- // Not sure it's possible to really track usedEntries properly.
-// assert(usedEntries > 0);
-
if (usedEntries > 0) {
--usedEntries;
}
diff --git a/src/cpu/o3/ras.hh b/src/cpu/o3/ras.hh
index 46d98181e..5c8a93285 100644
--- a/src/cpu/o3/ras.hh
+++ b/src/cpu/o3/ras.hh
@@ -24,45 +24,74 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_RAS_HH__
-#define __CPU_O3_CPU_RAS_HH__
+#ifndef __CPU_O3_RAS_HH__
+#define __CPU_O3_RAS_HH__
// For Addr type.
#include "arch/isa_traits.hh"
+#include <vector>
+/** Return address stack class, implements a simple RAS. */
class ReturnAddrStack
{
public:
- ReturnAddrStack(unsigned numEntries);
+ /** Creates a return address stack, but init() must be called prior to
+ * use.
+ */
+ ReturnAddrStack() {}
+
+ /** Initializes RAS with a specified number of entries.
+ * @param numEntries Number of entries in the RAS.
+ */
+ void init(unsigned numEntries);
+
+ void reset();
+ /** Returns the top address on the RAS. */
Addr top()
{ return addrStack[tos]; }
+ /** Returns the index of the top of the RAS. */
unsigned topIdx()
{ return tos; }
+ /** Pushes an address onto the RAS. */
void push(const Addr &return_addr);
+ /** Pops the top address from the RAS. */
void pop();
+ /** Changes index to the top of the RAS, and replaces the top address with
+ * a new target.
+ * @param top_entry_idx The index of the RAS that will now be the top.
+ * @param restored_target The new target address of the new top of the RAS.
+ */
void restore(unsigned top_entry_idx, const Addr &restored_target);
private:
+ /** Increments the top of stack index. */
inline void incrTos()
{ if (++tos == numEntries) tos = 0; }
+ /** Decrements the top of stack index. */
inline void decrTos()
{ tos = (tos == 0 ? numEntries - 1 : tos - 1); }
- Addr *addrStack;
+ /** The RAS itself. */
+ std::vector<Addr> addrStack;
+ /** The number of entries in the RAS. */
unsigned numEntries;
+ /** The number of used entries in the RAS. */
unsigned usedEntries;
+ /** The top of stack index. */
unsigned tos;
};
-#endif // __CPU_O3_CPU_RAS_HH__
+#endif // __CPU_O3_RAS_HH__
diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh
index a5cfa8f3c..6972f055f 100644
--- a/src/cpu/o3/regfile.hh
+++ b/src/cpu/o3/regfile.hh
@@ -24,15 +24,17 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Gabe Black
*/
-#ifndef __CPU_O3_CPU_REGFILE_HH__
-#define __CPU_O3_CPU_REGFILE_HH__
-
-// @todo: Destructor
+#ifndef __CPU_O3_REGFILE_HH__
+#define __CPU_O3_REGFILE_HH__
#include "arch/isa_traits.hh"
#include "arch/faults.hh"
+#include "arch/types.hh"
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/o3/comm.hh"
@@ -42,32 +44,40 @@
#endif
-// This really only depends on the ISA, and not the Impl. It might be nicer
-// to see if I can make it depend on nothing...
-// Things that are in the ifdef FULL_SYSTEM are pretty dependent on the ISA,
-// and should go in the AlphaFullCPU.
+#include <vector>
+/**
+ * Simple physical register file class.
+ * Right now this is specific to Alpha until we decide if/how to make things
+ * generic enough to support other ISAs.
+ */
template <class Impl>
class PhysRegFile
{
protected:
typedef TheISA::IntReg IntReg;
typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
typedef TheISA::MiscRegFile MiscRegFile;
typedef TheISA::MiscReg MiscReg;
- //Note that most of the definitions of the IntReg, FloatReg, etc. exist
- //within the Impl/ISA class and not within this PhysRegFile class.
+ typedef union {
+ FloatReg d;
+ FloatRegBits q;
+ } PhysFloatReg;
- //Will need some way to allow stuff like swap_palshadow to access the
- //correct registers. Might require code changes to swap_palshadow and
- //other execution contexts.
+ // Note that most of the definitions of the IntReg, FloatReg, etc. exist
+ // within the Impl/ISA class and not within this PhysRegFile class.
- //Will make these registers public for now, but they probably should
- //be private eventually with some accessor functions.
+ // Will make these registers public for now, but they probably should
+ // be private eventually with some accessor functions.
public:
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
+ /**
+ * Constructs a physical register file with the specified amount of
+ * integer and floating point registers.
+ */
PhysRegFile(unsigned _numPhysicalIntRegs,
unsigned _numPhysicalFloatRegs);
@@ -80,12 +90,13 @@ class PhysRegFile
// void serialize(std::ostream &os);
// void unserialize(Checkpoint *cp, const std::string &section);
+ /** Reads an integer register. */
uint64_t readIntReg(PhysRegIndex reg_idx)
{
assert(reg_idx < numPhysicalIntRegs);
DPRINTF(IEW, "RegFile: Access to int register %i, has data "
- "%i\n", int(reg_idx), intRegFile[reg_idx]);
+ "%#x\n", int(reg_idx), intRegFile[reg_idx]);
return intRegFile[reg_idx];
}
@@ -96,14 +107,15 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- FloatReg floatReg = floatRegFile.readReg(reg_idx, width);
+ FloatReg floatReg = floatRegFile[reg_idx].d;
DPRINTF(IEW, "RegFile: Access to %d byte float register %i, has "
- "data %8.8d\n", int(reg_idx), (double)floatReg);
+ "data %#x\n", int(reg_idx), floatRegFile[reg_idx].q);
return floatReg;
}
+ /** Reads a floating point register (double precision). */
FloatReg readFloatReg(PhysRegIndex reg_idx)
{
// Remove the base Float reg dependency.
@@ -111,14 +123,15 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- FloatReg floatReg = floatRegFile.readReg(reg_idx);
+ FloatReg floatReg = floatRegFile[reg_idx].d;
DPRINTF(IEW, "RegFile: Access to float register %i, has "
- "data %8.8d\n", int(reg_idx), (double)floatReg);
+ "data %#x\n", int(reg_idx), floatRegFile[reg_idx].q);
return floatReg;
}
+ /** Reads a floating point register as an integer. */
FloatRegBits readFloatRegBits(PhysRegIndex reg_idx, int width)
{
// Remove the base Float reg dependency.
@@ -126,10 +139,10 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx, width);
+ FloatRegBits floatRegBits = floatRegFile[reg_idx].q;
- DPRINTF(IEW, "RegFile: Access to %d byte float register %i as int, "
- "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits);
+ DPRINTF(IEW, "RegFile: Access to float register %i as int, "
+ "has data %#x\n", int(reg_idx), (uint64_t)floatRegBits);
return floatRegBits;
}
@@ -141,24 +154,27 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- FloatRegBits floatRegBits = floatRegFile.readRegBits(reg_idx);
+ FloatRegBits floatRegBits = floatRegFile[reg_idx].q;
DPRINTF(IEW, "RegFile: Access to float register %i as int, "
- "has data %lli\n", int(reg_idx), (uint64_t)floatRegBits);
+ "has data %#x\n", int(reg_idx), (uint64_t)floatRegBits);
return floatRegBits;
}
+ /** Sets an integer register to the given value. */
void setIntReg(PhysRegIndex reg_idx, uint64_t val)
{
assert(reg_idx < numPhysicalIntRegs);
- DPRINTF(IEW, "RegFile: Setting int register %i to %lli\n",
+ DPRINTF(IEW, "RegFile: Setting int register %i to %#x\n",
int(reg_idx), val);
- intRegFile[reg_idx] = val;
+ if (reg_idx != TheISA::ZeroReg)
+ intRegFile[reg_idx] = val;
}
+ /** Sets a single precision floating point register to the given value. */
void setFloatReg(PhysRegIndex reg_idx, FloatReg val, int width)
{
// Remove the base Float reg dependency.
@@ -166,12 +182,14 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n",
- int(reg_idx), (double)val);
+ DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n",
+ int(reg_idx), (uint64_t)val);
- floatRegFile.setReg(reg_idx, val, width);
+ if (reg_idx != TheISA::ZeroReg)
+ floatRegFile[reg_idx].d = val;
}
+ /** Sets a double precision floating point register to the given value. */
void setFloatReg(PhysRegIndex reg_idx, FloatReg val)
{
// Remove the base Float reg dependency.
@@ -179,12 +197,14 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- DPRINTF(IEW, "RegFile: Setting float register %i to %8.8d\n",
- int(reg_idx), (double)val);
+ DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n",
+ int(reg_idx), (uint64_t)val);
- floatRegFile.setReg(reg_idx, val);
+ if (reg_idx != TheISA::ZeroReg)
+ floatRegFile[reg_idx].d = val;
}
+ /** Sets a floating point register to the given integer value. */
void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val, int width)
{
// Remove the base Float reg dependency.
@@ -192,10 +212,10 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n",
+ DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n",
int(reg_idx), (uint64_t)val);
- floatRegFile.setRegBits(reg_idx, val, width);
+ floatRegFile[reg_idx].q = val;
}
void setFloatRegBits(PhysRegIndex reg_idx, FloatRegBits val)
@@ -205,81 +225,68 @@ class PhysRegFile
assert(reg_idx < numPhysicalFloatRegs + numPhysicalIntRegs);
- DPRINTF(IEW, "RegFile: Setting float register %i to %lli\n",
+ DPRINTF(IEW, "RegFile: Setting float register %i to %#x\n",
int(reg_idx), (uint64_t)val);
- floatRegFile.setRegBits(reg_idx, val);
- }
-
- uint64_t readPC()
- {
- return pc;
+ floatRegFile[reg_idx].q = val;
}
- void setPC(uint64_t val)
+ MiscReg readMiscReg(int misc_reg, unsigned thread_id)
{
- pc = val;
+ return miscRegs[thread_id].readReg(misc_reg);
}
- void setNextPC(uint64_t val)
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault,
+ unsigned thread_id)
{
- npc = val;
+ return miscRegs[thread_id].readRegWithEffect(misc_reg, fault,
+ cpu->tcBase(thread_id));
}
- //Consider leaving this stuff and below in some implementation specific
- //file as opposed to the general register file. Or have a derived class.
- MiscReg readMiscReg(int misc_reg)
+ Fault setMiscReg(int misc_reg, const MiscReg &val, unsigned thread_id)
{
- // Dummy function for now.
- // @todo: Fix this once proxy XC is used.
- return 0;
+ return miscRegs[thread_id].setReg(misc_reg, val);
}
- Fault setMiscReg(int misc_reg, const MiscReg &val)
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val,
+ unsigned thread_id)
{
- // Dummy function for now.
- // @todo: Fix this once proxy XC is used.
- return NoFault;
+ return miscRegs[thread_id].setRegWithEffect(misc_reg, val,
+ cpu->tcBase(thread_id));
}
#if FULL_SYSTEM
int readIntrFlag() { return intrflag; }
+ /** Sets an interrupt flag. */
void setIntrFlag(int val) { intrflag = val; }
#endif
- // These should be private eventually, but will be public for now
- // so that I can hack around the initregs issue.
public:
/** (signed) integer register file. */
IntReg *intRegFile;
/** Floating point register file. */
- FloatReg *floatRegFile;
+ PhysFloatReg *floatRegFile;
/** Miscellaneous register file. */
- MiscRegFile miscRegs;
-
- /** Program counter. */
- Addr pc;
-
- /** Next-cycle program counter. */
- Addr npc;
+ MiscRegFile miscRegs[Impl::MaxThreads];
#if FULL_SYSTEM
private:
- // This is ISA specifc stuff; remove it eventually once ISAImpl is used
-// IntReg palregs[NumIntRegs]; // PAL shadow registers
int intrflag; // interrupt flag
- bool pal_shadow; // using pal_shadow registers
#endif
private:
- FullCPU *cpu;
+ /** CPU pointer. */
+ O3CPU *cpu;
public:
- void setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; }
+ /** Sets the CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr) { cpu = cpu_ptr; }
+ /** Number of physical integer registers. */
unsigned numPhysicalIntRegs;
+ /** Number of physical floating point registers. */
unsigned numPhysicalFloatRegs;
};
@@ -290,10 +297,14 @@ PhysRegFile<Impl>::PhysRegFile(unsigned _numPhysicalIntRegs,
numPhysicalFloatRegs(_numPhysicalFloatRegs)
{
intRegFile = new IntReg[numPhysicalIntRegs];
- floatRegFile = new FloatReg[numPhysicalFloatRegs];
+ floatRegFile = new PhysFloatReg[numPhysicalFloatRegs];
- memset(intRegFile, 0, sizeof(*intRegFile));
- memset(floatRegFile, 0, sizeof(*floatRegFile));
+ for (int i = 0; i < Impl::MaxThreads; ++i) {
+ miscRegs[i].clear();
+ }
+
+ memset(intRegFile, 0, sizeof(IntReg) * numPhysicalIntRegs);
+ memset(floatRegFile, 0, sizeof(PhysFloatReg) * numPhysicalFloatRegs);
}
-#endif // __CPU_O3_CPU_REGFILE_HH__
+#endif
diff --git a/src/cpu/o3/rename.cc b/src/cpu/o3/rename.cc
index 6e9ee23da..443ada0cb 100644
--- a/src/cpu/o3/rename.cc
+++ b/src/cpu/o3/rename.cc
@@ -24,10 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/rename_impl.hh"
-template class SimpleRename<AlphaSimpleImpl>;
+template class DefaultRename<O3CPUImpl>;
diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh
index 07b442964..581fc8f81 100644
--- a/src/cpu/o3/rename.hh
+++ b/src/cpu/o3/rename.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,139 +24,276 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Todo:
-// Fix up trap and barrier handling.
-// May want to have different statuses to differentiate the different stall
-// conditions.
-
-#ifndef __CPU_O3_CPU_SIMPLE_RENAME_HH__
-#define __CPU_O3_CPU_SIMPLE_RENAME_HH__
+#ifndef __CPU_O3_RENAME_HH__
+#define __CPU_O3_RENAME_HH__
#include <list>
#include "base/statistics.hh"
#include "base/timebuf.hh"
-// Will need rename maps for both the int reg file and fp reg file.
-// Or change rename map class to handle both. (RegFile handles both.)
+/**
+ * DefaultRename handles both single threaded and SMT rename. Its
+ * width is specified by the parameters; each cycle it tries to rename
+ * that many instructions. It holds onto the rename history of all
+ * instructions with destination registers, storing the
+ * arch. register, the new physical register, and the old physical
+ * register, to allow for undoing of mappings if squashing happens, or
+ * freeing up registers upon commit. Rename handles blocking if the
+ * ROB, IQ, or LSQ is going to be full. Rename also handles barriers,
+ * and does so by stalling on the instruction until the ROB is empty
+ * and there are no instructions in flight to the ROB.
+ */
template<class Impl>
-class SimpleRename
+class DefaultRename
{
public:
// Typedefs from the Impl.
typedef typename Impl::CPUPol CPUPol;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::Params Params;
- typedef typename CPUPol::FetchStruct FetchStruct;
+ // Typedefs from the CPUPol
typedef typename CPUPol::DecodeStruct DecodeStruct;
typedef typename CPUPol::RenameStruct RenameStruct;
typedef typename CPUPol::TimeStruct TimeStruct;
-
- // Typedefs from the CPUPol
typedef typename CPUPol::FreeList FreeList;
typedef typename CPUPol::RenameMap RenameMap;
+ // These are used only for initialization.
+ typedef typename CPUPol::IEW IEW;
+ typedef typename CPUPol::Commit Commit;
// Typedefs from the ISA.
typedef TheISA::RegIndex RegIndex;
+ // A list is used to queue the instructions. Barrier insts must
+ // be added to the front of the list, which is the only reason for
+ // using a list instead of a queue. (Most other stages use a
+ // queue)
+ typedef std::list<DynInstPtr> InstQueue;
+
public:
- // Rename will block if ROB becomes full or issue queue becomes full,
- // or there are no free registers to rename to.
- // Only case where rename squashes is if IEW squashes.
- enum Status {
+ /** Overall rename status. Used to determine if the CPU can
+ * deschedule itself due to a lack of activity.
+ */
+ enum RenameStatus {
+ Active,
+ Inactive
+ };
+
+ /** Individual thread status. */
+ enum ThreadStatus {
Running,
Idle,
+ StartSquash,
Squashing,
Blocked,
Unblocking,
- BarrierStall
+ SerializeStall
};
private:
- Status _status;
+ /** Rename status. */
+ RenameStatus _status;
+
+ /** Per-thread status. */
+ ThreadStatus renameStatus[Impl::MaxThreads];
public:
- SimpleRename(Params &params);
+ /** DefaultRename constructor. */
+ DefaultRename(Params *params);
+
+ /** Returns the name of rename. */
+ std::string name() const;
+ /** Registers statistics. */
void regStats();
- void setCPU(FullCPU *cpu_ptr);
+ /** Sets CPU pointer. */
+ void setCPU(O3CPU *cpu_ptr);
+ /** Sets the main backwards communication time buffer pointer. */
void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+ /** Sets pointer to time buffer used to communicate to the next stage. */
void setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr);
+ /** Sets pointer to time buffer coming from decode. */
void setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr);
- void setRenameMap(RenameMap *rm_ptr);
+ /** Sets pointer to IEW stage. Used only for initialization. */
+ void setIEWStage(IEW *iew_stage)
+ { iew_ptr = iew_stage; }
+
+ /** Sets pointer to commit stage. Used only for initialization. */
+ void setCommitStage(Commit *commit_stage)
+ { commit_ptr = commit_stage; }
+
+ private:
+ /** Pointer to IEW stage. Used only for initialization. */
+ IEW *iew_ptr;
+
+ /** Pointer to commit stage. Used only for initialization. */
+ Commit *commit_ptr;
+
+ public:
+ /** Initializes variables for the stage. */
+ void initStage();
+
+ /** Sets pointer to list of active threads. */
+ void setActiveThreads(std::list<unsigned> *at_ptr);
+
+ /** Sets pointer to rename maps (per-thread structures). */
+ void setRenameMap(RenameMap rm_ptr[Impl::MaxThreads]);
+ /** Sets pointer to the free list. */
void setFreeList(FreeList *fl_ptr);
- void dumpHistory();
+ /** Sets pointer to the scoreboard. */
+ void setScoreboard(Scoreboard *_scoreboard);
- void tick();
+ /** Switches out the rename stage. */
+ void switchOut();
+
+ /** Completes the switch out. */
+ void doSwitchOut();
+
+ /** Takes over from another CPU's thread. */
+ void takeOverFrom();
+
+ /** Squashes all instructions in a thread. */
+ void squash(unsigned tid);
- void rename();
+ /** Ticks rename, which processes all input signals and attempts to rename
+ * as many instructions as possible.
+ */
+ void tick();
- void squash();
+ /** Debugging function used to dump history buffer of renamings. */
+ void dumpHistory();
private:
- void block();
+ /** Determines what to do based on rename's current status.
+ * @param status_change rename() sets this variable if there was a status
+ * change (ie switching from blocking to unblocking).
+ * @param tid Thread id to rename instructions from.
+ */
+ void rename(bool &status_change, unsigned tid);
+
+ /** Renames instructions for the given thread. Also handles serializing
+ * instructions.
+ */
+ void renameInsts(unsigned tid);
+
+ /** Inserts unused instructions from a given thread into the skid buffer,
+ * to be renamed once rename unblocks.
+ */
+ void skidInsert(unsigned tid);
+
+ /** Separates instructions from decode into individual lists of instructions
+ * sorted by thread.
+ */
+ void sortInsts();
+
+ /** Returns if all of the skid buffers are empty. */
+ bool skidsEmpty();
+
+ /** Updates overall rename status based on all of the threads' statuses. */
+ void updateStatus();
+
+ /** Switches rename to blocking, and signals back that rename has become
+ * blocked.
+ * @return Returns true if there is a status change.
+ */
+ bool block(unsigned tid);
+
+ /** Switches rename to unblocking if the skid buffer is empty, and signals
+ * back that rename has unblocked.
+ * @return Returns true if there is a status change.
+ */
+ bool unblock(unsigned tid);
+
+ /** Executes actual squash, removing squashed instructions. */
+ void doSquash(unsigned tid);
+
+ /** Removes a committed instruction's rename history. */
+ void removeFromHistory(InstSeqNum inst_seq_num, unsigned tid);
+
+ /** Renames the source registers of an instruction. */
+ inline void renameSrcRegs(DynInstPtr &inst, unsigned tid);
+
+ /** Renames the destination registers of an instruction. */
+ inline void renameDestRegs(DynInstPtr &inst, unsigned tid);
- inline void unblock();
+ /** Calculates the number of free ROB entries for a specific thread. */
+ inline int calcFreeROBEntries(unsigned tid);
- void doSquash();
+ /** Calculates the number of free IQ entries for a specific thread. */
+ inline int calcFreeIQEntries(unsigned tid);
- void removeFromHistory(InstSeqNum inst_seq_num);
+ /** Calculates the number of free LSQ entries for a specific thread. */
+ inline int calcFreeLSQEntries(unsigned tid);
- inline void renameSrcRegs(DynInstPtr &inst);
+ /** Returns the number of valid instructions coming from decode. */
+ unsigned validInsts();
- inline void renameDestRegs(DynInstPtr &inst);
+ /** Reads signals telling rename to block/unblock. */
+ void readStallSignals(unsigned tid);
- inline int calcFreeROBEntries();
+ /** Checks if any stages are telling rename to block. */
+ bool checkStall(unsigned tid);
- inline int calcFreeIQEntries();
+ /** Gets the number of free entries for a specific thread. */
+ void readFreeEntries(unsigned tid);
- /** Holds the previous information for each rename.
- * Note that often times the inst may have been deleted, so only access
- * the pointer for the address and do not dereference it.
+ /** Checks the signals and updates the status. */
+ bool checkSignalsAndUpdate(unsigned tid);
+
+ /** Either serializes on the next instruction available in the InstQueue,
+ * or records that it must serialize on the next instruction to enter
+ * rename.
+ * @param inst_list The list of younger, unprocessed instructions for the
+ * thread that has the serializeAfter instruction.
+ * @param tid The thread id.
+ */
+ void serializeAfter(InstQueue &inst_list, unsigned tid);
+
+ /** Holds the information for each destination register rename. It holds
+ * the instruction's sequence number, the arch register, the old physical
+ * register for that arch. register, and the new physical register.
*/
struct RenameHistory {
RenameHistory(InstSeqNum _instSeqNum, RegIndex _archReg,
PhysRegIndex _newPhysReg, PhysRegIndex _prevPhysReg)
: instSeqNum(_instSeqNum), archReg(_archReg),
- newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg),
- placeHolder(false)
- {
- }
-
- /** Constructor used specifically for cases where a place holder
- * rename history entry is being made.
- */
- RenameHistory(InstSeqNum _instSeqNum)
- : instSeqNum(_instSeqNum), archReg(0), newPhysReg(0),
- prevPhysReg(0), placeHolder(true)
+ newPhysReg(_newPhysReg), prevPhysReg(_prevPhysReg)
{
}
+ /** The sequence number of the instruction that renamed. */
InstSeqNum instSeqNum;
+ /** The architectural register index that was renamed. */
RegIndex archReg;
+ /** The new physical register that the arch. register is renamed to. */
PhysRegIndex newPhysReg;
+ /** The old physical register that the arch. register was renamed to. */
PhysRegIndex prevPhysReg;
- bool placeHolder;
};
- std::list<RenameHistory> historyBuffer;
+ /** A per-thread list of all destination register renames, used to either
+ * undo rename mappings or free old physical registers.
+ */
+ std::list<RenameHistory> historyBuffer[Impl::MaxThreads];
- /** CPU interface. */
- FullCPU *cpu;
+ /** Pointer to CPU. */
+ O3CPU *cpu;
- // Interfaces to objects outside of rename.
- /** Time buffer interface. */
+ /** Pointer to main time buffer used for backwards communication. */
TimeBuffer<TimeStruct> *timeBuffer;
/** Wire to get IEW's output from backwards time buffer. */
@@ -166,7 +303,6 @@ class SimpleRename
typename TimeBuffer<TimeStruct>::wire fromCommit;
/** Wire to write infromation heading to previous stages. */
- // Might not be the best name as not only decode will read it.
typename TimeBuffer<TimeStruct>::wire toDecode;
/** Rename instruction queue. */
@@ -181,15 +317,71 @@ class SimpleRename
/** Wire to get decode's output from decode queue. */
typename TimeBuffer<DecodeStruct>::wire fromDecode;
+ /** Queue of all instructions coming from decode this cycle. */
+ InstQueue insts[Impl::MaxThreads];
+
/** Skid buffer between rename and decode. */
- std::queue<DecodeStruct> skidBuffer;
+ InstQueue skidBuffer[Impl::MaxThreads];
/** Rename map interface. */
- SimpleRenameMap *renameMap;
+ RenameMap *renameMap[Impl::MaxThreads];
/** Free list interface. */
FreeList *freeList;
+ /** Pointer to the list of active threads. */
+ std::list<unsigned> *activeThreads;
+
+ /** Pointer to the scoreboard. */
+ Scoreboard *scoreboard;
+
+ /** Count of instructions in progress that have been sent off to the IQ
+ * and ROB, but are not yet included in their occupancy counts.
+ */
+ int instsInProgress[Impl::MaxThreads];
+
+ /** Variable that tracks if decode has written to the time buffer this
+ * cycle. Used to tell CPU if there is activity this cycle.
+ */
+ bool wroteToTimeBuffer;
+
+ /** Structures whose free entries impact the amount of instructions that
+ * can be renamed.
+ */
+ struct FreeEntries {
+ unsigned iqEntries;
+ unsigned lsqEntries;
+ unsigned robEntries;
+ };
+
+ /** Per-thread tracking of the number of free entries of back-end
+ * structures.
+ */
+ FreeEntries freeEntries[Impl::MaxThreads];
+
+ /** Records if the ROB is empty. In SMT mode the ROB may be dynamically
+ * partitioned between threads, so the ROB must tell rename when it is
+ * empty.
+ */
+ bool emptyROB[Impl::MaxThreads];
+
+ /** Source of possible stalls. */
+ struct Stalls {
+ bool iew;
+ bool commit;
+ };
+
+ /** Tracks which stages are telling decode to stall. */
+ Stalls stalls[Impl::MaxThreads];
+
+ /** The serialize instruction that rename has stalled on. */
+ DynInstPtr serializeInst[Impl::MaxThreads];
+
+ /** Records if rename needs to serialize on the next instruction for any
+ * thread.
+ */
+ bool serializeOnNextInst[Impl::MaxThreads];
+
/** Delay between iew and rename, in ticks. */
int iewToRenameDelay;
@@ -207,27 +399,74 @@ class SimpleRename
*/
unsigned commitWidth;
- /** The instruction that rename is currently on. It needs to have
- * persistent state so that when a stall occurs in the middle of a
- * group of instructions, it can restart at the proper instruction.
+ /** The index of the instruction in the time buffer to IEW that rename is
+ * currently using.
+ */
+ unsigned toIEWIndex;
+
+ /** Whether or not rename needs to block this cycle. */
+ bool blockThisCycle;
+
+ /** The number of threads active in rename. */
+ unsigned numThreads;
+
+ /** The maximum skid buffer size. */
+ unsigned skidBufferMax;
+
+ /** Enum to record the source of a structure full stall. Can come from
+ * either ROB, IQ, LSQ, and it is priortized in that order.
+ */
+ enum FullSource {
+ ROB,
+ IQ,
+ LSQ,
+ NONE
+ };
+
+ /** Function used to increment the stat that corresponds to the source of
+ * the stall.
*/
- unsigned numInst;
+ inline void incrFullStat(const FullSource &source);
+ /** Stat for total number of cycles spent squashing. */
Stats::Scalar<> renameSquashCycles;
+ /** Stat for total number of cycles spent idle. */
Stats::Scalar<> renameIdleCycles;
+ /** Stat for total number of cycles spent blocking. */
Stats::Scalar<> renameBlockCycles;
+ /** Stat for total number of cycles spent stalling for a serializing inst. */
+ Stats::Scalar<> renameSerializeStallCycles;
+ /** Stat for total number of cycles spent running normally. */
+ Stats::Scalar<> renameRunCycles;
+ /** Stat for total number of cycles spent unblocking. */
Stats::Scalar<> renameUnblockCycles;
+ /** Stat for total number of renamed instructions. */
Stats::Scalar<> renameRenamedInsts;
+ /** Stat for total number of squashed instructions that rename discards. */
Stats::Scalar<> renameSquashedInsts;
+ /** Stat for total number of times that the ROB starts a stall in rename. */
Stats::Scalar<> renameROBFullEvents;
+ /** Stat for total number of times that the IQ starts a stall in rename. */
Stats::Scalar<> renameIQFullEvents;
+ /** Stat for total number of times that the LSQ starts a stall in rename. */
+ Stats::Scalar<> renameLSQFullEvents;
+ /** Stat for total number of times that rename runs out of free registers
+ * to use to rename. */
Stats::Scalar<> renameFullRegistersEvents;
+ /** Stat for total number of renamed destination registers. */
Stats::Scalar<> renameRenamedOperands;
+ /** Stat for total number of source register rename lookups. */
Stats::Scalar<> renameRenameLookups;
- Stats::Scalar<> renameHBPlaceHolders;
+ /** Stat for total number of committed renaming mappings. */
Stats::Scalar<> renameCommittedMaps;
+ /** Stat for total number of mappings that were undone due to a squash. */
Stats::Scalar<> renameUndoneMaps;
- Stats::Scalar<> renameValidUndoneMaps;
+ /** Number of serialize instructions handled. */
+ Stats::Scalar<> renamedSerializing;
+ /** Number of instructions marked as temporarily serializing. */
+ Stats::Scalar<> renamedTempSerializing;
+ /** Number of instructions inserted into skid buffers. */
+ Stats::Scalar<> renameSkidInsts;
};
-#endif // __CPU_O3_CPU_SIMPLE_RENAME_HH__
+#endif // __CPU_O3_RENAME_HH__
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh
index 2068b36ab..df8b7f9da 100644
--- a/src/cpu/o3/rename_impl.hh
+++ b/src/cpu/o3/rename_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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>
@@ -31,97 +33,146 @@
#include "config/full_system.hh"
#include "cpu/o3/rename.hh"
+using namespace std;
+
+template <class Impl>
+DefaultRename<Impl>::DefaultRename(Params *params)
+ : iewToRenameDelay(params->iewToRenameDelay),
+ decodeToRenameDelay(params->decodeToRenameDelay),
+ commitToRenameDelay(params->commitToRenameDelay),
+ renameWidth(params->renameWidth),
+ commitWidth(params->commitWidth),
+ numThreads(params->numberOfThreads)
+{
+ _status = Inactive;
+
+ for (int i=0; i< numThreads; i++) {
+ renameStatus[i] = Idle;
+
+ freeEntries[i].iqEntries = 0;
+ freeEntries[i].lsqEntries = 0;
+ freeEntries[i].robEntries = 0;
+
+ stalls[i].iew = false;
+ stalls[i].commit = false;
+ serializeInst[i] = NULL;
+
+ instsInProgress[i] = 0;
+
+ emptyROB[i] = true;
+
+ serializeOnNextInst[i] = false;
+ }
+
+ // @todo: Make into a parameter.
+ skidBufferMax = (2 * (iewToRenameDelay * params->decodeWidth)) + renameWidth;
+}
+
template <class Impl>
-SimpleRename<Impl>::SimpleRename(Params &params)
- : iewToRenameDelay(params.iewToRenameDelay),
- decodeToRenameDelay(params.decodeToRenameDelay),
- commitToRenameDelay(params.commitToRenameDelay),
- renameWidth(params.renameWidth),
- commitWidth(params.commitWidth),
- numInst(0)
+std::string
+DefaultRename<Impl>::name() const
{
- _status = Idle;
+ return cpu->name() + ".rename";
}
template <class Impl>
void
-SimpleRename<Impl>::regStats()
+DefaultRename<Impl>::regStats()
{
renameSquashCycles
- .name(name() + ".renameSquashCycles")
+ .name(name() + ".RENAME:SquashCycles")
.desc("Number of cycles rename is squashing")
.prereq(renameSquashCycles);
renameIdleCycles
- .name(name() + ".renameIdleCycles")
+ .name(name() + ".RENAME:IdleCycles")
.desc("Number of cycles rename is idle")
.prereq(renameIdleCycles);
renameBlockCycles
- .name(name() + ".renameBlockCycles")
+ .name(name() + ".RENAME:BlockCycles")
.desc("Number of cycles rename is blocking")
.prereq(renameBlockCycles);
+ renameSerializeStallCycles
+ .name(name() + ".RENAME:serializeStallCycles")
+ .desc("count of cycles rename stalled for serializing inst")
+ .flags(Stats::total);
+ renameRunCycles
+ .name(name() + ".RENAME:RunCycles")
+ .desc("Number of cycles rename is running")
+ .prereq(renameIdleCycles);
renameUnblockCycles
- .name(name() + ".renameUnblockCycles")
+ .name(name() + ".RENAME:UnblockCycles")
.desc("Number of cycles rename is unblocking")
.prereq(renameUnblockCycles);
renameRenamedInsts
- .name(name() + ".renameRenamedInsts")
+ .name(name() + ".RENAME:RenamedInsts")
.desc("Number of instructions processed by rename")
.prereq(renameRenamedInsts);
renameSquashedInsts
- .name(name() + ".renameSquashedInsts")
+ .name(name() + ".RENAME:SquashedInsts")
.desc("Number of squashed instructions processed by rename")
.prereq(renameSquashedInsts);
renameROBFullEvents
- .name(name() + ".renameROBFullEvents")
- .desc("Number of times rename has considered the ROB 'full'")
+ .name(name() + ".RENAME:ROBFullEvents")
+ .desc("Number of times rename has blocked due to ROB full")
.prereq(renameROBFullEvents);
renameIQFullEvents
- .name(name() + ".renameIQFullEvents")
- .desc("Number of times rename has considered the IQ 'full'")
+ .name(name() + ".RENAME:IQFullEvents")
+ .desc("Number of times rename has blocked due to IQ full")
.prereq(renameIQFullEvents);
+ renameLSQFullEvents
+ .name(name() + ".RENAME:LSQFullEvents")
+ .desc("Number of times rename has blocked due to LSQ full")
+ .prereq(renameLSQFullEvents);
renameFullRegistersEvents
- .name(name() + ".renameFullRegisterEvents")
+ .name(name() + ".RENAME:FullRegisterEvents")
.desc("Number of times there has been no free registers")
.prereq(renameFullRegistersEvents);
renameRenamedOperands
- .name(name() + ".renameRenamedOperands")
+ .name(name() + ".RENAME:RenamedOperands")
.desc("Number of destination operands rename has renamed")
.prereq(renameRenamedOperands);
renameRenameLookups
- .name(name() + ".renameRenameLookups")
+ .name(name() + ".RENAME:RenameLookups")
.desc("Number of register rename lookups that rename has made")
.prereq(renameRenameLookups);
- renameHBPlaceHolders
- .name(name() + ".renameHBPlaceHolders")
- .desc("Number of place holders added to the history buffer")
- .prereq(renameHBPlaceHolders);
renameCommittedMaps
- .name(name() + ".renameCommittedMaps")
+ .name(name() + ".RENAME:CommittedMaps")
.desc("Number of HB maps that are committed")
.prereq(renameCommittedMaps);
renameUndoneMaps
- .name(name() + ".renameUndoneMaps")
+ .name(name() + ".RENAME:UndoneMaps")
.desc("Number of HB maps that are undone due to squashing")
.prereq(renameUndoneMaps);
- renameValidUndoneMaps
- .name(name() + ".renameValidUndoneMaps")
- .desc("Number of HB maps that are undone, and are not place holders")
- .prereq(renameValidUndoneMaps);
+ renamedSerializing
+ .name(name() + ".RENAME:serializingInsts")
+ .desc("count of serializing insts renamed")
+ .flags(Stats::total)
+ ;
+ renamedTempSerializing
+ .name(name() + ".RENAME:tempSerializingInsts")
+ .desc("count of temporary serializing insts renamed")
+ .flags(Stats::total)
+ ;
+ renameSkidInsts
+ .name(name() + ".RENAME:skidInsts")
+ .desc("count of insts added to the skid buffer")
+ .flags(Stats::total)
+ ;
}
template <class Impl>
void
-SimpleRename<Impl>::setCPU(FullCPU *cpu_ptr)
+DefaultRename<Impl>::setCPU(O3CPU *cpu_ptr)
{
- DPRINTF(Rename, "Rename: Setting CPU pointer.\n");
+ DPRINTF(Rename, "Setting CPU pointer.\n");
cpu = cpu_ptr;
}
template <class Impl>
void
-SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+DefaultRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
{
- DPRINTF(Rename, "Rename: Setting time buffer pointer.\n");
+ DPRINTF(Rename, "Setting time buffer pointer.\n");
timeBuffer = tb_ptr;
// Setup wire to read information from time buffer, from IEW stage.
@@ -136,9 +187,9 @@ SimpleRename<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
template <class Impl>
void
-SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
+DefaultRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
{
- DPRINTF(Rename, "Rename: Setting rename queue pointer.\n");
+ DPRINTF(Rename, "Setting rename queue pointer.\n");
renameQueue = rq_ptr;
// Setup wire to write information to future stages.
@@ -147,9 +198,9 @@ SimpleRename<Impl>::setRenameQueue(TimeBuffer<RenameStruct> *rq_ptr)
template <class Impl>
void
-SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
+DefaultRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
{
- DPRINTF(Rename, "Rename: Setting decode queue pointer.\n");
+ DPRINTF(Rename, "Setting decode queue pointer.\n");
decodeQueue = dq_ptr;
// Setup wire to get information from decode.
@@ -158,214 +209,721 @@ SimpleRename<Impl>::setDecodeQueue(TimeBuffer<DecodeStruct> *dq_ptr)
template <class Impl>
void
-SimpleRename<Impl>::setRenameMap(RenameMap *rm_ptr)
+DefaultRename<Impl>::initStage()
{
- DPRINTF(Rename, "Rename: Setting rename map pointer.\n");
- renameMap = rm_ptr;
+ // Grab the number of free entries directly from the stages.
+ for (int tid=0; tid < numThreads; tid++) {
+ freeEntries[tid].iqEntries = iew_ptr->instQueue.numFreeEntries(tid);
+ freeEntries[tid].lsqEntries = iew_ptr->ldstQueue.numFreeEntries(tid);
+ freeEntries[tid].robEntries = commit_ptr->numROBFreeEntries(tid);
+ emptyROB[tid] = true;
+ }
}
+template<class Impl>
+void
+DefaultRename<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(Rename, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+
+
template <class Impl>
void
-SimpleRename<Impl>::setFreeList(FreeList *fl_ptr)
+DefaultRename<Impl>::setRenameMap(RenameMap rm_ptr[])
{
- DPRINTF(Rename, "Rename: Setting free list pointer.\n");
+ DPRINTF(Rename, "Setting rename map pointers.\n");
+
+ for (int i=0; i<numThreads; i++) {
+ renameMap[i] = &rm_ptr[i];
+ }
+}
+
+template <class Impl>
+void
+DefaultRename<Impl>::setFreeList(FreeList *fl_ptr)
+{
+ DPRINTF(Rename, "Setting free list pointer.\n");
freeList = fl_ptr;
}
+template<class Impl>
+void
+DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
+{
+ DPRINTF(Rename, "Setting scoreboard pointer.\n");
+ scoreboard = _scoreboard;
+}
+
+template <class Impl>
+void
+DefaultRename<Impl>::switchOut()
+{
+ // Rename is ready to switch out at any time.
+ cpu->signalSwitched();
+}
+
template <class Impl>
void
-SimpleRename<Impl>::dumpHistory()
+DefaultRename<Impl>::doSwitchOut()
{
- typename list<RenameHistory>::iterator buf_it = historyBuffer.begin();
+ // Clear any state, fix up the rename map.
+ for (int i = 0; i < numThreads; i++) {
+ typename list<RenameHistory>::iterator hb_it = historyBuffer[i].begin();
- while (buf_it != historyBuffer.end())
- {
- cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys "
- "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg,
- (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg);
+ while (!historyBuffer[i].empty()) {
+ assert(hb_it != historyBuffer[i].end());
- buf_it++;
+ DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence "
+ "number %i.\n", i, (*hb_it).instSeqNum);
+
+ // Tell the rename map to set the architected register to the
+ // previous physical register that it was renamed to.
+ renameMap[i]->setEntry(hb_it->archReg, hb_it->prevPhysReg);
+
+ // Put the renamed physical register back on the free list.
+ freeList->addReg(hb_it->newPhysReg);
+
+ historyBuffer[i].erase(hb_it++);
+ }
+ insts[i].clear();
+ skidBuffer[i].clear();
}
}
template <class Impl>
void
-SimpleRename<Impl>::block()
+DefaultRename<Impl>::takeOverFrom()
{
- DPRINTF(Rename, "Rename: Blocking.\n");
- // Set status to Blocked.
- _status = Blocked;
+ _status = Inactive;
+ initStage();
- // Add the current inputs onto the skid buffer, so they can be
- // reprocessed when this stage unblocks.
- skidBuffer.push(*fromDecode);
+ // Reset all state prior to taking over from the other CPU.
+ for (int i=0; i< numThreads; i++) {
+ renameStatus[i] = Idle;
+
+ stalls[i].iew = false;
+ stalls[i].commit = false;
+ serializeInst[i] = NULL;
+
+ instsInProgress[i] = 0;
- // Note that this stage only signals previous stages to stall when
- // it is the cause of the stall originates at this stage. Otherwise
- // the previous stages are expected to check all possible stall signals.
+ emptyROB[i] = true;
+
+ serializeOnNextInst[i] = false;
+ }
}
template <class Impl>
-inline void
-SimpleRename<Impl>::unblock()
-{
- DPRINTF(Rename, "Rename: Read instructions out of skid buffer this "
- "cycle.\n");
- // Remove the now processed instructions from the skid buffer.
- skidBuffer.pop();
-
- // If there's still information in the skid buffer, then
- // continue to tell previous stages to stall. They will be
- // able to restart once the skid buffer is empty.
- if (!skidBuffer.empty()) {
- toDecode->renameInfo.stall = true;
- } else {
- DPRINTF(Rename, "Rename: Done unblocking.\n");
- _status = Running;
+void
+DefaultRename<Impl>::squash(unsigned tid)
+{
+ DPRINTF(Rename, "[tid:%u]: Squashing instructions.\n",tid);
+
+ // Clear the stall signal if rename was blocked or unblocking before.
+ // If it still needs to block, the blocking should happen the next
+ // cycle and there should be space to hold everything due to the squash.
+ if (renameStatus[tid] == Blocked ||
+ renameStatus[tid] == Unblocking ||
+ renameStatus[tid] == SerializeStall) {
+
+ toDecode->renameUnblock[tid] = 1;
+
+ serializeInst[tid] = NULL;
}
+
+ // Set the status to Squashing.
+ renameStatus[tid] = Squashing;
+
+ // Squash any instructions from decode.
+ unsigned squashCount = 0;
+
+ for (int i=0; i<fromDecode->size; i++) {
+ if (fromDecode->insts[i]->threadNumber == tid) {
+ fromDecode->insts[i]->setSquashed();
+ wroteToTimeBuffer = true;
+ squashCount++;
+ }
+ }
+
+ insts[tid].clear();
+
+ // Clear the skid buffer in case it has any data in it.
+ skidBuffer[tid].clear();
+
+ doSquash(tid);
}
template <class Impl>
void
-SimpleRename<Impl>::doSquash()
+DefaultRename<Impl>::tick()
{
- typename list<RenameHistory>::iterator hb_it = historyBuffer.begin();
+ wroteToTimeBuffer = false;
- InstSeqNum squashed_seq_num = fromCommit->commitInfo.doneSeqNum;
+ blockThisCycle = false;
-#if FULL_SYSTEM
- assert(!historyBuffer.empty());
-#else
- // After a syscall squashes everything, the history buffer may be empty
- // but the ROB may still be squashing instructions.
- if (historyBuffer.empty()) {
+ bool status_change = false;
+
+ toIEWIndex = 0;
+
+ sortInsts();
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ // Check stall and squash signals.
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ DPRINTF(Rename, "Processing [tid:%i]\n", tid);
+
+ status_change = checkSignalsAndUpdate(tid) || status_change;
+
+ rename(status_change, tid);
+ }
+
+ if (status_change) {
+ updateStatus();
+ }
+
+ if (wroteToTimeBuffer) {
+ DPRINTF(Activity, "Activity this cycle.\n");
+ cpu->activityThisCycle();
+ }
+
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ // If we committed this cycle then doneSeqNum will be > 0
+ if (fromCommit->commitInfo[tid].doneSeqNum != 0 &&
+ !fromCommit->commitInfo[tid].squash &&
+ renameStatus[tid] != Squashing) {
+
+ removeFromHistory(fromCommit->commitInfo[tid].doneSeqNum,
+ tid);
+ }
+ }
+
+ // @todo: make into updateProgress function
+ for (int tid=0; tid < numThreads; tid++) {
+ instsInProgress[tid] -= fromIEW->iewInfo[tid].dispatched;
+
+ assert(instsInProgress[tid] >=0);
+ }
+
+}
+
+template<class Impl>
+void
+DefaultRename<Impl>::rename(bool &status_change, unsigned tid)
+{
+ // If status is Running or idle,
+ // call renameInsts()
+ // If status is Unblocking,
+ // buffer any instructions coming from decode
+ // continue trying to empty skid buffer
+ // check if stall conditions have passed
+
+ if (renameStatus[tid] == Blocked) {
+ ++renameBlockCycles;
+ } else if (renameStatus[tid] == Squashing) {
+ ++renameSquashCycles;
+ } else if (renameStatus[tid] == SerializeStall) {
+ ++renameSerializeStallCycles;
+ }
+
+ if (renameStatus[tid] == Running ||
+ renameStatus[tid] == Idle) {
+ DPRINTF(Rename, "[tid:%u]: Not blocked, so attempting to run "
+ "stage.\n", tid);
+
+ renameInsts(tid);
+ } else if (renameStatus[tid] == Unblocking) {
+ renameInsts(tid);
+
+ if (validInsts()) {
+ // Add the current inputs to the skid buffer so they can be
+ // reprocessed when this stage unblocks.
+ skidInsert(tid);
+ }
+
+ // If we switched over to blocking, then there's a potential for
+ // an overall status change.
+ status_change = unblock(tid) || status_change || blockThisCycle;
+ }
+}
+
+template <class Impl>
+void
+DefaultRename<Impl>::renameInsts(unsigned tid)
+{
+ // Instructions can be either in the skid buffer or the queue of
+ // instructions coming from decode, depending on the status.
+ int insts_available = renameStatus[tid] == Unblocking ?
+ skidBuffer[tid].size() : insts[tid].size();
+
+ // Check the decode queue to see if instructions are available.
+ // If there are no available instructions to rename, then do nothing.
+ if (insts_available == 0) {
+ DPRINTF(Rename, "[tid:%u]: Nothing to do, breaking out early.\n",
+ tid);
+ // Should I change status to idle?
+ ++renameIdleCycles;
return;
+ } else if (renameStatus[tid] == Unblocking) {
+ ++renameUnblockCycles;
+ } else if (renameStatus[tid] == Running) {
+ ++renameRunCycles;
}
-#endif // FULL_SYSTEM
- // Go through the most recent instructions, undoing the mappings
- // they did and freeing up the registers.
- while ((*hb_it).instSeqNum > squashed_seq_num)
- {
- assert(hb_it != historyBuffer.end());
+ DynInstPtr inst;
- DPRINTF(Rename, "Rename: Removing history entry with sequence "
- "number %i.\n", (*hb_it).instSeqNum);
+ // Will have to do a different calculation for the number of free
+ // entries.
+ int free_rob_entries = calcFreeROBEntries(tid);
+ int free_iq_entries = calcFreeIQEntries(tid);
+ int free_lsq_entries = calcFreeLSQEntries(tid);
+ int min_free_entries = free_rob_entries;
- // If it's not simply a place holder, then add the registers.
- if (!(*hb_it).placeHolder) {
- // Tell the rename map to set the architected register to the
- // previous physical register that it was renamed to.
- renameMap->setEntry(hb_it->archReg, hb_it->prevPhysReg);
+ FullSource source = ROB;
- // Put the renamed physical register back on the free list.
- freeList->addReg(hb_it->newPhysReg);
+ if (free_iq_entries < min_free_entries) {
+ min_free_entries = free_iq_entries;
+ source = IQ;
+ }
- ++renameValidUndoneMaps;
+ if (free_lsq_entries < min_free_entries) {
+ min_free_entries = free_lsq_entries;
+ source = LSQ;
+ }
+
+ // Check if there's any space left.
+ if (min_free_entries <= 0) {
+ DPRINTF(Rename, "[tid:%u]: Blocking due to no free ROB/IQ/LSQ "
+ "entries.\n"
+ "ROB has %i free entries.\n"
+ "IQ has %i free entries.\n"
+ "LSQ has %i free entries.\n",
+ tid,
+ free_rob_entries,
+ free_iq_entries,
+ free_lsq_entries);
+
+ blockThisCycle = true;
+
+ block(tid);
+
+ incrFullStat(source);
+
+ return;
+ } else if (min_free_entries < insts_available) {
+ DPRINTF(Rename, "[tid:%u]: Will have to block this cycle."
+ "%i insts available, but only %i insts can be "
+ "renamed due to ROB/IQ/LSQ limits.\n",
+ tid, insts_available, min_free_entries);
+
+ insts_available = min_free_entries;
+
+ blockThisCycle = true;
+
+ incrFullStat(source);
+ }
+
+ InstQueue &insts_to_rename = renameStatus[tid] == Unblocking ?
+ skidBuffer[tid] : insts[tid];
+
+ DPRINTF(Rename, "[tid:%u]: %i available instructions to "
+ "send iew.\n", tid, insts_available);
+
+ DPRINTF(Rename, "[tid:%u]: %i insts pipelining from Rename | %i insts "
+ "dispatched to IQ last cycle.\n",
+ tid, instsInProgress[tid], fromIEW->iewInfo[tid].dispatched);
+
+ // Handle serializing the next instruction if necessary.
+ if (serializeOnNextInst[tid]) {
+ if (emptyROB[tid] && instsInProgress[tid] == 0) {
+ // ROB already empty; no need to serialize.
+ serializeOnNextInst[tid] = false;
+ } else if (!insts_to_rename.empty()) {
+ insts_to_rename.front()->setSerializeBefore();
}
+ }
- historyBuffer.erase(hb_it++);
+ int renamed_insts = 0;
- ++renameUndoneMaps;
+ while (insts_available > 0 && toIEWIndex < renameWidth) {
+ DPRINTF(Rename, "[tid:%u]: Sending instructions to IEW.\n", tid);
+
+ assert(!insts_to_rename.empty());
+
+ inst = insts_to_rename.front();
+
+ insts_to_rename.pop_front();
+
+ if (renameStatus[tid] == Unblocking) {
+ DPRINTF(Rename,"[tid:%u]: Removing [sn:%lli] PC:%#x from rename "
+ "skidBuffer\n",
+ tid, inst->seqNum, inst->readPC());
+ }
+
+ if (inst->isSquashed()) {
+ DPRINTF(Rename, "[tid:%u]: instruction %i with PC %#x is "
+ "squashed, skipping.\n",
+ tid, inst->seqNum, inst->threadNumber,inst->readPC());
+
+ ++renameSquashedInsts;
+
+ // Decrement how many instructions are available.
+ --insts_available;
+
+ continue;
+ }
+
+ DPRINTF(Rename, "[tid:%u]: Processing instruction [sn:%lli] with "
+ "PC %#x.\n",
+ tid, inst->seqNum, inst->readPC());
+
+ // Handle serializeAfter/serializeBefore instructions.
+ // serializeAfter marks the next instruction as serializeBefore.
+ // serializeBefore makes the instruction wait in rename until the ROB
+ // is empty.
+
+ // In this model, IPR accesses are serialize before
+ // instructions, and store conditionals are serialize after
+ // instructions. This is mainly due to lack of support for
+ // out-of-order operations of either of those classes of
+ // instructions.
+ if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
+ !inst->isSerializeHandled()) {
+ DPRINTF(Rename, "Serialize before instruction encountered.\n");
+
+ if (!inst->isTempSerializeBefore()) {
+ renamedSerializing++;
+ inst->setSerializeHandled();
+ } else {
+ renamedTempSerializing++;
+ }
+
+ // Change status over to SerializeStall so that other stages know
+ // what this is blocked on.
+ renameStatus[tid] = SerializeStall;
+
+ serializeInst[tid] = inst;
+
+ blockThisCycle = true;
+
+ break;
+ } else if ((inst->isStoreConditional() || inst->isSerializeAfter()) &&
+ !inst->isSerializeHandled()) {
+ DPRINTF(Rename, "Serialize after instruction encountered.\n");
+
+ renamedSerializing++;
+
+ inst->setSerializeHandled();
+
+ serializeAfter(insts_to_rename, tid);
+ }
+
+ // Check here to make sure there are enough destination registers
+ // to rename to. Otherwise block.
+ if (renameMap[tid]->numFreeEntries() < inst->numDestRegs()) {
+ DPRINTF(Rename, "Blocking due to lack of free "
+ "physical registers to rename to.\n");
+ blockThisCycle = true;
+
+ ++renameFullRegistersEvents;
+
+ break;
+ }
+
+ renameSrcRegs(inst, inst->threadNumber);
+
+ renameDestRegs(inst, inst->threadNumber);
+
+ ++renamed_insts;
+
+ // Put instruction in rename queue.
+ toIEW->insts[toIEWIndex] = inst;
+ ++(toIEW->size);
+
+ // Increment which instruction we're on.
+ ++toIEWIndex;
+
+ // Decrement how many instructions are available.
+ --insts_available;
+ }
+
+ instsInProgress[tid] += renamed_insts;
+ renameRenamedInsts += renamed_insts;
+
+ // If we wrote to the time buffer, record this.
+ if (toIEWIndex) {
+ wroteToTimeBuffer = true;
+ }
+
+ // Check if there's any instructions left that haven't yet been renamed.
+ // If so then block.
+ if (insts_available) {
+ blockThisCycle = true;
+ }
+
+ if (blockThisCycle) {
+ block(tid);
+ toDecode->renameUnblock[tid] = false;
}
}
+template<class Impl>
+void
+DefaultRename<Impl>::skidInsert(unsigned tid)
+{
+ DynInstPtr inst = NULL;
+
+ while (!insts[tid].empty()) {
+ inst = insts[tid].front();
+
+ insts[tid].pop_front();
+
+ assert(tid == inst->threadNumber);
+
+ DPRINTF(Rename, "[tid:%u]: Inserting [sn:%lli] PC:%#x into Rename "
+ "skidBuffer\n", tid, inst->seqNum, inst->readPC());
+
+ ++renameSkidInsts;
+
+ skidBuffer[tid].push_back(inst);
+ }
+
+ if (skidBuffer[tid].size() > skidBufferMax)
+ panic("Skidbuffer Exceeded Max Size");
+}
+
template <class Impl>
void
-SimpleRename<Impl>::squash()
+DefaultRename<Impl>::sortInsts()
{
- DPRINTF(Rename, "Rename: Squashing instructions.\n");
- // Set the status to Squashing.
- _status = Squashing;
+ int insts_from_decode = fromDecode->size;
+#ifdef DEBUG
+ for (int i=0; i < numThreads; i++)
+ assert(insts[i].empty());
+#endif
+ for (int i = 0; i < insts_from_decode; ++i) {
+ DynInstPtr inst = fromDecode->insts[i];
+ insts[inst->threadNumber].push_back(inst);
+ }
+}
- numInst = 0;
+template<class Impl>
+bool
+DefaultRename<Impl>::skidsEmpty()
+{
+ list<unsigned>::iterator threads = (*activeThreads).begin();
- // Clear the skid buffer in case it has any data in it.
- while (!skidBuffer.empty())
- {
- skidBuffer.pop();
+ while (threads != (*activeThreads).end()) {
+ if (!skidBuffer[*threads++].empty())
+ return false;
}
- doSquash();
+ return true;
}
template<class Impl>
void
-SimpleRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num)
+DefaultRename<Impl>::updateStatus()
{
- DPRINTF(Rename, "Rename: Removing a committed instruction from the "
- "history buffer, until sequence number %lli.\n", inst_seq_num);
- typename list<RenameHistory>::iterator hb_it = historyBuffer.end();
+ bool any_unblocking = false;
- --hb_it;
+ list<unsigned>::iterator threads = (*activeThreads).begin();
- if (hb_it->instSeqNum > inst_seq_num) {
- DPRINTF(Rename, "Rename: Old sequence number encountered. Ensure "
- "that a syscall happened recently.\n");
- return;
+ threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (renameStatus[tid] == Unblocking) {
+ any_unblocking = true;
+ break;
+ }
}
- while ((*hb_it).instSeqNum != inst_seq_num)
- {
- // Make sure we haven't gone off the end of the list.
- assert(hb_it != historyBuffer.end());
-
- // In theory instructions at the end of the history buffer
- // should be older than the instruction being removed, which
- // means they will have a lower sequence number. Also the
- // instruction being removed from the history really should
- // be the last instruction in the list, as it is the instruction
- // that was just committed that is being removed.
- assert(hb_it->instSeqNum < inst_seq_num);
- DPRINTF(Rename, "Rename: Freeing up older rename of reg %i, sequence"
- " number %i.\n",
- (*hb_it).prevPhysReg, (*hb_it).instSeqNum);
-
- if (!(*hb_it).placeHolder) {
- freeList->addReg((*hb_it).prevPhysReg);
- ++renameCommittedMaps;
+ // Rename will have activity if it's unblocking.
+ if (any_unblocking) {
+ if (_status == Inactive) {
+ _status = Active;
+
+ DPRINTF(Activity, "Activating stage.\n");
+
+ cpu->activateStage(O3CPU::RenameIdx);
}
+ } else {
+ // If it's not unblocking, then rename will not have any internal
+ // activity. Switch it to inactive.
+ if (_status == Active) {
+ _status = Inactive;
+ DPRINTF(Activity, "Deactivating stage.\n");
- historyBuffer.erase(hb_it--);
+ cpu->deactivateStage(O3CPU::RenameIdx);
+ }
}
+}
- // Finally free up the previous register of the finished instruction
- // itself.
- if (!(*hb_it).placeHolder) {
- freeList->addReg(hb_it->prevPhysReg);
- ++renameCommittedMaps;
+template <class Impl>
+bool
+DefaultRename<Impl>::block(unsigned tid)
+{
+ DPRINTF(Rename, "[tid:%u]: Blocking.\n", tid);
+
+ // Add the current inputs onto the skid buffer, so they can be
+ // reprocessed when this stage unblocks.
+ skidInsert(tid);
+
+ // Only signal backwards to block if the previous stages do not think
+ // rename is already blocked.
+ if (renameStatus[tid] != Blocked) {
+ if (renameStatus[tid] != Unblocking) {
+ toDecode->renameBlock[tid] = true;
+ toDecode->renameUnblock[tid] = false;
+ wroteToTimeBuffer = true;
+ }
+
+ // Rename can not go from SerializeStall to Blocked, otherwise
+ // it would not know to complete the serialize stall.
+ if (renameStatus[tid] != SerializeStall) {
+ // Set status to Blocked.
+ renameStatus[tid] = Blocked;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+template <class Impl>
+bool
+DefaultRename<Impl>::unblock(unsigned tid)
+{
+ DPRINTF(Rename, "[tid:%u]: Trying to unblock.\n", tid);
+
+ // Rename is done unblocking if the skid buffer is empty.
+ if (skidBuffer[tid].empty() && renameStatus[tid] != SerializeStall) {
+
+ DPRINTF(Rename, "[tid:%u]: Done unblocking.\n", tid);
+
+ toDecode->renameUnblock[tid] = true;
+ wroteToTimeBuffer = true;
+
+ renameStatus[tid] = Running;
+ return true;
}
- historyBuffer.erase(hb_it);
+ return false;
+}
+
+template <class Impl>
+void
+DefaultRename<Impl>::doSquash(unsigned tid)
+{
+ typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].begin();
+
+ InstSeqNum squashed_seq_num = fromCommit->commitInfo[tid].doneSeqNum;
+
+ // After a syscall squashes everything, the history buffer may be empty
+ // but the ROB may still be squashing instructions.
+ if (historyBuffer[tid].empty()) {
+ return;
+ }
+
+ // Go through the most recent instructions, undoing the mappings
+ // they did and freeing up the registers.
+ while (!historyBuffer[tid].empty() &&
+ (*hb_it).instSeqNum > squashed_seq_num) {
+ assert(hb_it != historyBuffer[tid].end());
+
+ DPRINTF(Rename, "[tid:%u]: Removing history entry with sequence "
+ "number %i.\n", tid, (*hb_it).instSeqNum);
+
+ // Tell the rename map to set the architected register to the
+ // previous physical register that it was renamed to.
+ renameMap[tid]->setEntry(hb_it->archReg, hb_it->prevPhysReg);
+
+ // Put the renamed physical register back on the free list.
+ freeList->addReg(hb_it->newPhysReg);
+
+ historyBuffer[tid].erase(hb_it++);
+
+ ++renameUndoneMaps;
+ }
+}
+
+template<class Impl>
+void
+DefaultRename<Impl>::removeFromHistory(InstSeqNum inst_seq_num, unsigned tid)
+{
+ DPRINTF(Rename, "[tid:%u]: Removing a committed instruction from the "
+ "history buffer %u (size=%i), until [sn:%lli].\n",
+ tid, tid, historyBuffer[tid].size(), inst_seq_num);
+
+ typename list<RenameHistory>::iterator hb_it = historyBuffer[tid].end();
+
+ --hb_it;
+
+ if (historyBuffer[tid].empty()) {
+ DPRINTF(Rename, "[tid:%u]: History buffer is empty.\n", tid);
+ return;
+ } else if (hb_it->instSeqNum > inst_seq_num) {
+ DPRINTF(Rename, "[tid:%u]: Old sequence number encountered. Ensure "
+ "that a syscall happened recently.\n", tid);
+ return;
+ }
+
+ // Commit all the renames up until (and including) the committed sequence
+ // number. Some or even all of the committed instructions may not have
+ // rename histories if they did not have destination registers that were
+ // renamed.
+ while (!historyBuffer[tid].empty() &&
+ hb_it != historyBuffer[tid].end() &&
+ (*hb_it).instSeqNum <= inst_seq_num) {
+
+ DPRINTF(Rename, "[tid:%u]: Freeing up older rename of reg %i, "
+ "[sn:%lli].\n",
+ tid, (*hb_it).prevPhysReg, (*hb_it).instSeqNum);
+
+ freeList->addReg((*hb_it).prevPhysReg);
+ ++renameCommittedMaps;
+
+ historyBuffer[tid].erase(hb_it--);
+ }
}
template <class Impl>
inline void
-SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst)
+DefaultRename<Impl>::renameSrcRegs(DynInstPtr &inst,unsigned tid)
{
+ assert(renameMap[tid] != 0);
+
unsigned num_src_regs = inst->numSrcRegs();
// Get the architectual register numbers from the source and
// destination operands, and redirect them to the right register.
// Will need to mark dependencies though.
- for (int src_idx = 0; src_idx < num_src_regs; src_idx++)
- {
+ for (int src_idx = 0; src_idx < num_src_regs; src_idx++) {
RegIndex src_reg = inst->srcRegIdx(src_idx);
// Look up the source registers to get the phys. register they've
// been renamed to, and set the sources to those registers.
- PhysRegIndex renamed_reg = renameMap->lookup(src_reg);
+ PhysRegIndex renamed_reg = renameMap[tid]->lookup(src_reg);
- DPRINTF(Rename, "Rename: Looking up arch reg %i, got "
- "physical reg %i.\n", (int)src_reg, (int)renamed_reg);
+ DPRINTF(Rename, "[tid:%u]: Looking up arch reg %i, got "
+ "physical reg %i.\n", tid, (int)src_reg,
+ (int)renamed_reg);
inst->renameSrcReg(src_idx, renamed_reg);
- // Either incorporate it into the info passed back,
- // or make another function call to see if that register is
- // ready or not.
- if (renameMap->isReady(renamed_reg)) {
- DPRINTF(Rename, "Rename: Register is ready.\n");
+ // See if the register is ready or not.
+ if (scoreboard->getReg(renamed_reg) == true) {
+ DPRINTF(Rename, "[tid:%u]: Register is ready.\n", tid);
inst->markSrcRegReady(src_idx);
}
@@ -376,379 +934,341 @@ SimpleRename<Impl>::renameSrcRegs(DynInstPtr &inst)
template <class Impl>
inline void
-SimpleRename<Impl>::renameDestRegs(DynInstPtr &inst)
+DefaultRename<Impl>::renameDestRegs(DynInstPtr &inst,unsigned tid)
{
- typename SimpleRenameMap::RenameInfo rename_result;
+ typename RenameMap::RenameInfo rename_result;
unsigned num_dest_regs = inst->numDestRegs();
- // If it's an instruction with no destination registers, then put
- // a placeholder within the history buffer. It might be better
- // to not put it in the history buffer at all (other than branches,
- // which always need at least a place holder), and differentiate
- // between instructions with and without destination registers
- // when getting from commit the instructions that committed.
- if (num_dest_regs == 0) {
- RenameHistory hb_entry(inst->seqNum);
+ // Rename the destination registers.
+ for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++) {
+ RegIndex dest_reg = inst->destRegIdx(dest_idx);
- historyBuffer.push_front(hb_entry);
+ // Get the physical register that the destination will be
+ // renamed to.
+ rename_result = renameMap[tid]->rename(dest_reg);
- DPRINTF(Rename, "Rename: Adding placeholder instruction to "
- "history buffer, sequence number %lli.\n",
- inst->seqNum);
+ //Mark Scoreboard entry as not ready
+ scoreboard->unsetReg(rename_result.first);
- ++renameHBPlaceHolders;
- } else {
+ DPRINTF(Rename, "[tid:%u]: Renaming arch reg %i to physical "
+ "reg %i.\n", tid, (int)dest_reg,
+ (int)rename_result.first);
- // Rename the destination registers.
- for (int dest_idx = 0; dest_idx < num_dest_regs; dest_idx++)
- {
- RegIndex dest_reg = inst->destRegIdx(dest_idx);
+ // Record the rename information so that a history can be kept.
+ RenameHistory hb_entry(inst->seqNum, dest_reg,
+ rename_result.first,
+ rename_result.second);
- // Get the physical register that the destination will be
- // renamed to.
- rename_result = renameMap->rename(dest_reg);
+ historyBuffer[tid].push_front(hb_entry);
- DPRINTF(Rename, "Rename: Renaming arch reg %i to physical "
- "reg %i.\n", (int)dest_reg,
- (int)rename_result.first);
+ DPRINTF(Rename, "[tid:%u]: Adding instruction to history buffer, "
+ "[sn:%lli].\n",tid,
+ (*historyBuffer[tid].begin()).instSeqNum);
- // Record the rename information so that a history can be kept.
- RenameHistory hb_entry(inst->seqNum, dest_reg,
- rename_result.first,
- rename_result.second);
+ // Tell the instruction to rename the appropriate destination
+ // register (dest_idx) to the new physical register
+ // (rename_result.first), and record the previous physical
+ // register that the same logical register was renamed to
+ // (rename_result.second).
+ inst->renameDestReg(dest_idx,
+ rename_result.first,
+ rename_result.second);
- historyBuffer.push_front(hb_entry);
+ ++renameRenamedOperands;
+ }
+}
- DPRINTF(Rename, "Rename: Adding instruction to history buffer, "
- "sequence number %lli.\n",
- (*historyBuffer.begin()).instSeqNum);
+template <class Impl>
+inline int
+DefaultRename<Impl>::calcFreeROBEntries(unsigned tid)
+{
+ int num_free = freeEntries[tid].robEntries -
+ (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched);
- // Tell the instruction to rename the appropriate destination
- // register (dest_idx) to the new physical register
- // (rename_result.first), and record the previous physical
- // register that the same logical register was renamed to
- // (rename_result.second).
- inst->renameDestReg(dest_idx,
- rename_result.first,
- rename_result.second);
+ //DPRINTF(Rename,"[tid:%i]: %i rob free\n",tid,num_free);
- ++renameRenamedOperands;
- }
- }
+ return num_free;
}
template <class Impl>
inline int
-SimpleRename<Impl>::calcFreeROBEntries()
+DefaultRename<Impl>::calcFreeIQEntries(unsigned tid)
{
- return fromCommit->commitInfo.freeROBEntries -
- renameWidth * iewToRenameDelay;
+ int num_free = freeEntries[tid].iqEntries -
+ (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatched);
+
+ //DPRINTF(Rename,"[tid:%i]: %i iq free\n",tid,num_free);
+
+ return num_free;
}
template <class Impl>
inline int
-SimpleRename<Impl>::calcFreeIQEntries()
+DefaultRename<Impl>::calcFreeLSQEntries(unsigned tid)
{
- return fromIEW->iewInfo.freeIQEntries - renameWidth * iewToRenameDelay;
-}
+ int num_free = freeEntries[tid].lsqEntries -
+ (instsInProgress[tid] - fromIEW->iewInfo[tid].dispatchedToLSQ);
-template<class Impl>
-void
-SimpleRename<Impl>::tick()
-{
- // Rename will need to try to rename as many instructions as it
- // has bandwidth, unless it is blocked.
-
- // Check if _status is BarrierStall. If so, then check if the number
- // of free ROB entries is equal to the number of total ROB entries.
- // Once equal then wake this stage up. Set status to unblocking maybe.
-
- if (_status != Blocked && _status != Squashing) {
- DPRINTF(Rename, "Rename: Status is not blocked, will attempt to "
- "run stage.\n");
- // Make sure that the skid buffer has something in it if the
- // status is unblocking.
- assert(_status == Unblocking ? !skidBuffer.empty() : 1);
-
- rename();
-
- // If the status was unblocking, then instructions from the skid
- // buffer were used. Remove those instructions and handle
- // the rest of unblocking.
- if (_status == Unblocking) {
- ++renameUnblockCycles;
-
- if (fromDecode->size > 0) {
- // Add the current inputs onto the skid buffer, so they can be
- // reprocessed when this stage unblocks.
- skidBuffer.push(*fromDecode);
- }
+ //DPRINTF(Rename,"[tid:%i]: %i lsq free\n",tid,num_free);
- unblock();
- }
- } else if (_status == Blocked) {
- ++renameBlockCycles;
+ return num_free;
+}
- // If stage is blocked and still receiving valid instructions,
- // make sure to store them in the skid buffer.
- if (fromDecode->size > 0) {
+template <class Impl>
+unsigned
+DefaultRename<Impl>::validInsts()
+{
+ unsigned inst_count = 0;
- block();
+ for (int i=0; i<fromDecode->size; i++) {
+ if (!fromDecode->insts[i]->isSquashed())
+ inst_count++;
+ }
- // Continue to tell previous stage to stall.
- toDecode->renameInfo.stall = true;
- }
+ return inst_count;
+}
- if (!fromIEW->iewInfo.stall &&
- !fromCommit->commitInfo.stall &&
- calcFreeROBEntries() > 0 &&
- calcFreeIQEntries() > 0 &&
- renameMap->numFreeEntries() > 0) {
-
- // Need to be sure to check all blocking conditions above.
- // If they have cleared, then start unblocking.
- DPRINTF(Rename, "Rename: Stall signals cleared, going to "
- "unblock.\n");
- _status = Unblocking;
-
- // Continue to tell previous stage to block until this stage
- // is done unblocking.
- toDecode->renameInfo.stall = true;
- } else {
- // Otherwise no conditions have changed. Tell previous
- // stage to continue blocking.
- toDecode->renameInfo.stall = true;
- }
+template <class Impl>
+void
+DefaultRename<Impl>::readStallSignals(unsigned tid)
+{
+ if (fromIEW->iewBlock[tid]) {
+ stalls[tid].iew = true;
+ }
- if (fromCommit->commitInfo.squash ||
- fromCommit->commitInfo.robSquashing) {
- squash();
- return;
- }
- } else if (_status == Squashing) {
- ++renameSquashCycles;
+ if (fromIEW->iewUnblock[tid]) {
+ assert(stalls[tid].iew);
+ stalls[tid].iew = false;
+ }
- if (fromCommit->commitInfo.squash) {
- squash();
- } else if (!fromCommit->commitInfo.squash &&
- !fromCommit->commitInfo.robSquashing) {
+ if (fromCommit->commitBlock[tid]) {
+ stalls[tid].commit = true;
+ }
- DPRINTF(Rename, "Rename: Done squashing, going to running.\n");
- _status = Running;
- rename();
- } else {
- doSquash();
- }
+ if (fromCommit->commitUnblock[tid]) {
+ assert(stalls[tid].commit);
+ stalls[tid].commit = false;
}
+}
- // Ugly code, revamp all of the tick() functions eventually.
- if (fromCommit->commitInfo.doneSeqNum != 0 && _status != Squashing) {
-#if !FULL_SYSTEM
- if (!fromCommit->commitInfo.squash) {
- removeFromHistory(fromCommit->commitInfo.doneSeqNum);
- }
-#else
- removeFromHistory(fromCommit->commitInfo.doneSeqNum);
-#endif
+template <class Impl>
+bool
+DefaultRename<Impl>::checkStall(unsigned tid)
+{
+ bool ret_val = false;
+
+ if (stalls[tid].iew) {
+ DPRINTF(Rename,"[tid:%i]: Stall from IEW stage detected.\n", tid);
+ ret_val = true;
+ } else if (stalls[tid].commit) {
+ DPRINTF(Rename,"[tid:%i]: Stall from Commit stage detected.\n", tid);
+ ret_val = true;
+ } else if (calcFreeROBEntries(tid) <= 0) {
+ DPRINTF(Rename,"[tid:%i]: Stall: ROB has 0 free entries.\n", tid);
+ ret_val = true;
+ } else if (calcFreeIQEntries(tid) <= 0) {
+ DPRINTF(Rename,"[tid:%i]: Stall: IQ has 0 free entries.\n", tid);
+ ret_val = true;
+ } else if (calcFreeLSQEntries(tid) <= 0) {
+ DPRINTF(Rename,"[tid:%i]: Stall: LSQ has 0 free entries.\n", tid);
+ ret_val = true;
+ } else if (renameMap[tid]->numFreeEntries() <= 0) {
+ DPRINTF(Rename,"[tid:%i]: Stall: RenameMap has 0 free entries.\n", tid);
+ ret_val = true;
+ } else if (renameStatus[tid] == SerializeStall &&
+ (!emptyROB[tid] || instsInProgress[tid])) {
+ DPRINTF(Rename,"[tid:%i]: Stall: Serialize stall and ROB is not "
+ "empty.\n",
+ tid);
+ ret_val = true;
}
+ return ret_val;
}
-template<class Impl>
+template <class Impl>
void
-SimpleRename<Impl>::rename()
-{
- // Check if any of the stages ahead of rename are telling rename
- // to squash. The squash() function will also take care of fixing up
- // the rename map and the free list.
- if (fromCommit->commitInfo.squash ||
- fromCommit->commitInfo.robSquashing) {
- DPRINTF(Rename, "Rename: Receiving signal from Commit to squash.\n");
- squash();
- return;
+DefaultRename<Impl>::readFreeEntries(unsigned tid)
+{
+ bool updated = false;
+ if (fromIEW->iewInfo[tid].usedIQ) {
+ freeEntries[tid].iqEntries =
+ fromIEW->iewInfo[tid].freeIQEntries;
+ updated = true;
}
- // Check if time buffer is telling this stage to stall.
- if (fromIEW->iewInfo.stall ||
- fromCommit->commitInfo.stall) {
- DPRINTF(Rename, "Rename: Receiving signal from IEW/Commit to "
- "stall.\n");
- block();
- return;
+ if (fromIEW->iewInfo[tid].usedLSQ) {
+ freeEntries[tid].lsqEntries =
+ fromIEW->iewInfo[tid].freeLSQEntries;
+ updated = true;
}
- // Check if the current status is squashing. If so, set its status
- // to running and resume execution the next cycle.
- if (_status == Squashing) {
- DPRINTF(Rename, "Rename: Done squashing.\n");
- _status = Running;
- return;
+ if (fromCommit->commitInfo[tid].usedROB) {
+ freeEntries[tid].robEntries =
+ fromCommit->commitInfo[tid].freeROBEntries;
+ emptyROB[tid] = fromCommit->commitInfo[tid].emptyROB;
+ updated = true;
}
- // Check the decode queue to see if instructions are available.
- // If there are no available instructions to rename, then do nothing.
- // Or, if the stage is currently unblocking, then go ahead and run it.
- if (fromDecode->size == 0 && _status != Unblocking) {
- DPRINTF(Rename, "Rename: Nothing to do, breaking out early.\n");
- // Should I change status to idle?
- return;
- }
-
- ////////////////////////////////////
- // Actual rename part.
- ////////////////////////////////////
-
- DynInstPtr inst;
+ DPRINTF(Rename, "[tid:%i]: Free IQ: %i, Free ROB: %i, Free LSQ: %i\n",
+ tid,
+ freeEntries[tid].iqEntries,
+ freeEntries[tid].robEntries,
+ freeEntries[tid].lsqEntries);
- // If we're unblocking, then we may be in the middle of an instruction
- // group. Subtract off numInst to get the proper number of instructions
- // left.
- int insts_available = _status == Unblocking ?
- skidBuffer.front().size - numInst :
- fromDecode->size;
+ DPRINTF(Rename, "[tid:%i]: %i instructions not yet in ROB\n",
+ tid, instsInProgress[tid]);
+}
- bool block_this_cycle = false;
+template <class Impl>
+bool
+DefaultRename<Impl>::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.
+ // If status was serialize stall
+ // check if ROB is empty and no insts are in flight to the ROB
+
+ readFreeEntries(tid);
+ readStallSignals(tid);
+
+ if (fromCommit->commitInfo[tid].squash) {
+ DPRINTF(Rename, "[tid:%u]: Squashing instructions due to squash from "
+ "commit.\n", tid);
+
+ squash(tid);
+
+ return true;
+ }
- // Will have to do a different calculation for the number of free
- // entries. Number of free entries recorded on this cycle -
- // renameWidth * renameToDecodeDelay
- int free_rob_entries = calcFreeROBEntries();
- int free_iq_entries = calcFreeIQEntries();
- int min_iq_rob = min(free_rob_entries, free_iq_entries);
+ if (fromCommit->commitInfo[tid].robSquashing) {
+ DPRINTF(Rename, "[tid:%u]: ROB is still squashing.\n", tid);
- unsigned to_iew_index = 0;
+ renameStatus[tid] = Squashing;
- // Check if there's any space left.
- if (min_iq_rob <= 0) {
- DPRINTF(Rename, "Rename: Blocking due to no free ROB or IQ "
- "entries.\n"
- "Rename: ROB has %d free entries.\n"
- "Rename: IQ has %d free entries.\n",
- free_rob_entries,
- free_iq_entries);
- block();
- // Tell previous stage to stall.
- toDecode->renameInfo.stall = true;
+ return true;
+ }
- if (free_rob_entries <= 0) {
- ++renameROBFullEvents;
- } else {
- ++renameIQFullEvents;
- }
+ if (checkStall(tid)) {
+ return block(tid);
+ }
- return;
- } else if (min_iq_rob < insts_available) {
- DPRINTF(Rename, "Rename: Will have to block this cycle. Only "
- "%i insts can be renamed due to IQ/ROB limits.\n",
- min_iq_rob);
+ if (renameStatus[tid] == Blocked) {
+ DPRINTF(Rename, "[tid:%u]: Done blocking, switching to unblocking.\n",
+ tid);
- insts_available = min_iq_rob;
+ renameStatus[tid] = Unblocking;
- block_this_cycle = true;
+ unblock(tid);
- if (free_rob_entries < free_iq_entries) {
- ++renameROBFullEvents;
- } else {
- ++renameIQFullEvents;
- }
+ return true;
}
- while (insts_available > 0) {
- DPRINTF(Rename, "Rename: Sending instructions to iew.\n");
+ if (renameStatus[tid] == Squashing) {
+ // Switch status to running if rename isn't being told to block or
+ // squash this cycle.
+ DPRINTF(Rename, "[tid:%u]: Done squashing, switching to running.\n",
+ tid);
- // Get the next instruction either from the skid buffer or the
- // decode queue.
- inst = _status == Unblocking ? skidBuffer.front().insts[numInst] :
- fromDecode->insts[numInst];
+ renameStatus[tid] = Running;
- if (inst->isSquashed()) {
- DPRINTF(Rename, "Rename: instruction %i with PC %#x is "
- "squashed, skipping.\n",
- inst->seqNum, inst->readPC());
+ return false;
+ }
- // Go to the next instruction.
- ++numInst;
+ if (renameStatus[tid] == SerializeStall) {
+ // Stall ends once the ROB is free.
+ DPRINTF(Rename, "[tid:%u]: Done with serialize stall, switching to "
+ "unblocking.\n", tid);
- ++renameSquashedInsts;
+ DynInstPtr serial_inst = serializeInst[tid];
- // Decrement how many instructions are available.
- --insts_available;
+ renameStatus[tid] = Unblocking;
- continue;
- }
+ unblock(tid);
- DPRINTF(Rename, "Rename: Processing instruction %i with PC %#x.\n",
- inst->seqNum, inst->readPC());
-
- // If it's a trap instruction, then it needs to wait here within
- // rename until the ROB is empty. Needs a way to detect that the
- // ROB is empty. Maybe an event?
- // Would be nice if it could be avoided putting this into a
- // specific stage and instead just put it into the AlphaFullCPU.
- // Might not really be feasible though...
- // (EXCB, TRAPB)
- if (inst->isSerializing()) {
- panic("Rename: Serializing instruction encountered.\n");
- DPRINTF(Rename, "Rename: Serializing instruction "
- "encountered.\n");
-
- // Change status over to BarrierStall so that other stages know
- // what this is blocked on.
- _status = BarrierStall;
+ DPRINTF(Rename, "[tid:%u]: Processing instruction [%lli] with "
+ "PC %#x.\n",
+ tid, serial_inst->seqNum, serial_inst->readPC());
- block_this_cycle = true;
+ // Put instruction into queue here.
+ serial_inst->clearSerializeBefore();
- break;
+ if (!skidBuffer[tid].empty()) {
+ skidBuffer[tid].push_front(serial_inst);
+ } else {
+ insts[tid].push_front(serial_inst);
}
- // Check here to make sure there are enough destination registers
- // to rename to. Otherwise block.
- if (renameMap->numFreeEntries() < inst->numDestRegs())
- {
- DPRINTF(Rename, "Rename: Blocking due to lack of free "
- "physical registers to rename to.\n");
- // Need some sort of event based on a register being freed.
-
- block_this_cycle = true;
+ DPRINTF(Rename, "[tid:%u]: Instruction must be processed by rename."
+ " Adding to front of list.\n", tid);
- ++renameFullRegistersEvents;
+ serializeInst[tid] = NULL;
- break;
- }
+ return true;
+ }
- renameSrcRegs(inst);
+ // If we've reached this point, we have not gotten any signals that
+ // cause rename to change its status. Rename remains the same as before.
+ return false;
+}
- renameDestRegs(inst);
+template<class Impl>
+void
+DefaultRename<Impl>::serializeAfter(InstQueue &inst_list,
+ unsigned tid)
+{
+ if (inst_list.empty()) {
+ // Mark a bit to say that I must serialize on the next instruction.
+ serializeOnNextInst[tid] = true;
+ return;
+ }
- // Put instruction in rename queue.
- toIEW->insts[to_iew_index] = inst;
- ++(toIEW->size);
+ // Set the next instruction as serializing.
+ inst_list.front()->setSerializeBefore();
+}
- // Decrease the number of free ROB and IQ entries.
- --free_rob_entries;
- --free_iq_entries;
+template <class Impl>
+inline void
+DefaultRename<Impl>::incrFullStat(const FullSource &source)
+{
+ switch (source) {
+ case ROB:
+ ++renameROBFullEvents;
+ break;
+ case IQ:
+ ++renameIQFullEvents;
+ break;
+ case LSQ:
+ ++renameLSQFullEvents;
+ break;
+ default:
+ panic("Rename full stall stat should be incremented for a reason!");
+ break;
+ }
+}
- // Increment which instruction we're on.
- ++to_iew_index;
- ++numInst;
+template <class Impl>
+void
+DefaultRename<Impl>::dumpHistory()
+{
+ typename list<RenameHistory>::iterator buf_it;
- ++renameRenamedInsts;
+ for (int i = 0; i < numThreads; i++) {
- // Decrement how many instructions are available.
- --insts_available;
- }
+ buf_it = historyBuffer[i].begin();
- // Check if there's any instructions left that haven't yet been renamed.
- // If so then block.
- if (block_this_cycle) {
- block();
+ while (buf_it != historyBuffer[i].end()) {
+ cprintf("Seq num: %i\nArch reg: %i New phys reg: %i Old phys "
+ "reg: %i\n", (*buf_it).instSeqNum, (int)(*buf_it).archReg,
+ (int)(*buf_it).newPhysReg, (int)(*buf_it).prevPhysReg);
- toDecode->renameInfo.stall = true;
- } else {
- // If we had a successful rename and didn't have to exit early, then
- // reset numInst so it will refer to the correct instruction on next
- // run.
- numInst = 0;
+ buf_it++;
+ }
}
}
diff --git a/src/cpu/o3/rename_map.cc b/src/cpu/o3/rename_map.cc
index 10963f7de..befbc3e8a 100644
--- a/src/cpu/o3/rename_map.cc
+++ b/src/cpu/o3/rename_map.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <vector>
@@ -32,118 +34,105 @@
using namespace std;
-// Todo: Consider making functions inline. Avoid having things that are
-// using the zero register or misc registers from adding on the registers
-// to the free list. Possibly remove the direct communication between
-// this and the freelist. Considering making inline bool functions that
-// determine if the register is a logical int, logical fp, physical int,
-// physical fp, etc.
-
-SimpleRenameMap::SimpleRenameMap(unsigned _numLogicalIntRegs,
- unsigned _numPhysicalIntRegs,
- unsigned _numLogicalFloatRegs,
- unsigned _numPhysicalFloatRegs,
- unsigned _numMiscRegs,
- RegIndex _intZeroReg,
- RegIndex _floatZeroReg)
- : numLogicalIntRegs(_numLogicalIntRegs),
- numPhysicalIntRegs(_numPhysicalIntRegs),
- numLogicalFloatRegs(_numLogicalFloatRegs),
- numPhysicalFloatRegs(_numPhysicalFloatRegs),
- numMiscRegs(_numMiscRegs),
- intZeroReg(_intZeroReg),
- floatZeroReg(_floatZeroReg)
+// @todo: Consider making inline bool functions that determine if the
+// register is a logical int, logical fp, physical int, physical fp,
+// etc.
+
+SimpleRenameMap::~SimpleRenameMap()
+{
+}
+
+void
+SimpleRenameMap::init(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ PhysRegIndex &ireg_idx,
+
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ PhysRegIndex &freg_idx,
+
+ unsigned _numMiscRegs,
+
+ RegIndex _intZeroReg,
+ RegIndex _floatZeroReg,
+
+ int map_id,
+ bool bindRegs)
{
- DPRINTF(Rename, "Rename: Creating rename map. Phys: %i / %i, Float: "
- "%i / %i.\n", numLogicalIntRegs, numPhysicalIntRegs,
+ id = map_id;
+
+ numLogicalIntRegs = _numLogicalIntRegs;
+
+ numLogicalFloatRegs = _numLogicalFloatRegs;
+
+ numPhysicalIntRegs = _numPhysicalIntRegs;
+
+ numPhysicalFloatRegs = _numPhysicalFloatRegs;
+
+ numMiscRegs = _numMiscRegs;
+
+ intZeroReg = _intZeroReg;
+ floatZeroReg = _floatZeroReg;
+
+ DPRINTF(Rename, "Creating rename map %i. Phys: %i / %i, Float: "
+ "%i / %i.\n", id, numLogicalIntRegs, numPhysicalIntRegs,
numLogicalFloatRegs, numPhysicalFloatRegs);
numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs;
numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs;
- //Create the rename maps, and their scoreboards.
- intRenameMap = new RenameEntry[numLogicalIntRegs];
- floatRenameMap = new RenameEntry[numLogicalRegs];
-
- // Should combine this into one scoreboard.
- intScoreboard.resize(numPhysicalIntRegs);
- floatScoreboard.resize(numPhysicalRegs);
- miscScoreboard.resize(numPhysicalRegs + numMiscRegs);
-
- // Initialize the entries in the integer rename map to point to the
- // physical registers of the same index, and consider each register
- // ready until the first rename occurs.
- for (RegIndex index = 0; index < numLogicalIntRegs; ++index)
- {
- intRenameMap[index].physical_reg = index;
- intScoreboard[index] = 1;
- }
+ //Create the rename maps
+ intRenameMap.resize(numLogicalIntRegs);
+ floatRenameMap.resize(numLogicalRegs);
- // Initialize the rest of the physical registers (the ones that don't
- // directly map to a logical register) as unready.
- for (PhysRegIndex index = numLogicalIntRegs;
- index < numPhysicalIntRegs;
- ++index)
- {
- intScoreboard[index] = 0;
- }
+ if (bindRegs) {
+ DPRINTF(Rename, "Binding registers into rename map %i",id);
- int float_reg_idx = numPhysicalIntRegs;
-
- // Initialize the entries in the floating point rename map to point to
- // the physical registers of the same index, and consider each register
- // ready until the first rename occurs.
- // Although the index refers purely to architected registers, because
- // the floating reg indices come after the integer reg indices, they
- // may exceed the size of a normal RegIndex (short).
- for (PhysRegIndex index = numLogicalIntRegs;
- index < numLogicalRegs; ++index)
- {
- floatRenameMap[index].physical_reg = float_reg_idx++;
- }
+ // Initialize the entries in the integer rename map to point to the
+ // physical registers of the same index
+ for (RegIndex index = 0; index < numLogicalIntRegs; ++index)
+ {
+ intRenameMap[index].physical_reg = ireg_idx++;
+ }
- for (PhysRegIndex index = numPhysicalIntRegs;
- index < numPhysicalIntRegs + numLogicalFloatRegs; ++index)
- {
- floatScoreboard[index] = 1;
- }
+ // Initialize the entries in the floating point rename map to point to
+ // the physical registers of the same index
+ // Although the index refers purely to architected registers, because
+ // the floating reg indices come after the integer reg indices, they
+ // may exceed the size of a normal RegIndex (short).
+ for (PhysRegIndex index = numLogicalIntRegs;
+ index < numLogicalRegs; ++index)
+ {
+ floatRenameMap[index].physical_reg = freg_idx++;
+ }
+ } else {
+ DPRINTF(Rename, "Binding registers into rename map %i",id);
- // Initialize the rest of the physical registers (the ones that don't
- // directly map to a logical register) as unready.
- for (PhysRegIndex index = numPhysicalIntRegs + numLogicalFloatRegs;
- index < numPhysicalRegs;
- ++index)
- {
- floatScoreboard[index] = 0;
- }
+ PhysRegIndex temp_ireg = ireg_idx;
- // Initialize the entries in the misc register scoreboard to be ready.
- for (PhysRegIndex index = numPhysicalRegs;
- index < numPhysicalRegs + numMiscRegs; ++index)
- {
- miscScoreboard[index] = 1;
- }
-}
+ for (RegIndex index = 0; index < numLogicalIntRegs; ++index)
+ {
+ intRenameMap[index].physical_reg = temp_ireg++;
+ }
-SimpleRenameMap::~SimpleRenameMap()
-{
- // Delete the rename maps as they were allocated with new.
- delete [] intRenameMap;
- delete [] floatRenameMap;
+ PhysRegIndex temp_freg = freg_idx;
+
+ for (PhysRegIndex index = numLogicalIntRegs;
+ index < numLogicalRegs; ++index)
+ {
+ floatRenameMap[index].physical_reg = temp_freg++;
+ }
+ }
}
void
SimpleRenameMap::setFreeList(SimpleFreeList *fl_ptr)
{
- //Setup the interface to the freelist.
freeList = fl_ptr;
}
-// Don't allow this stage to fault; force that check to the rename stage.
-// Simply ask to rename a logical register and get back a new physical
-// register index.
SimpleRenameMap::RenameInfo
SimpleRenameMap::rename(RegIndex arch_reg)
{
@@ -156,45 +145,33 @@ SimpleRenameMap::rename(RegIndex arch_reg)
// requested architected register.
prev_reg = intRenameMap[arch_reg].physical_reg;
- // If it's not referencing the zero register, then mark the register
- // as not ready.
+ // If it's not referencing the zero register, then rename the
+ // register.
if (arch_reg != intZeroReg) {
- // Get a free physical register to rename to.
renamed_reg = freeList->getIntReg();
- // Update the integer rename map.
intRenameMap[arch_reg].physical_reg = renamed_reg;
assert(renamed_reg >= 0 && renamed_reg < numPhysicalIntRegs);
- // Mark register as not ready.
- intScoreboard[renamed_reg] = false;
} else {
// Otherwise return the zero register so nothing bad happens.
renamed_reg = intZeroReg;
}
} else if (arch_reg < numLogicalRegs) {
- // Subtract off the base offset for floating point registers.
-// arch_reg = arch_reg - numLogicalIntRegs;
-
// Record the current physical register that is renamed to the
// requested architected register.
prev_reg = floatRenameMap[arch_reg].physical_reg;
- // If it's not referencing the zero register, then mark the register
- // as not ready.
+ // If it's not referencing the zero register, then rename the
+ // register.
if (arch_reg != floatZeroReg) {
- // Get a free floating point register to rename to.
renamed_reg = freeList->getFloatReg();
- // Update the floating point rename map.
floatRenameMap[arch_reg].physical_reg = renamed_reg;
assert(renamed_reg < numPhysicalRegs &&
renamed_reg >= numPhysicalIntRegs);
-
- // Mark register as not ready.
- floatScoreboard[renamed_reg] = false;
} else {
// Otherwise return the zero register so nothing bad happens.
renamed_reg = floatZeroReg;
@@ -203,10 +180,10 @@ SimpleRenameMap::rename(RegIndex arch_reg)
// Subtract off the base offset for miscellaneous registers.
arch_reg = arch_reg - numLogicalRegs;
- // No renaming happens to the misc. registers. They are simply the
- // registers that come after all the physical registers; thus
- // take the base architected register and add the physical registers
- // to it.
+ // No renaming happens to the misc. registers. They are
+ // simply the registers that come after all the physical
+ // registers; thus take the base architected register and add
+ // the physical registers to it.
renamed_reg = arch_reg + numPhysicalRegs;
// Set the previous register to the same register; mainly it must be
@@ -215,24 +192,17 @@ SimpleRenameMap::rename(RegIndex arch_reg)
prev_reg = renamed_reg;
assert(renamed_reg < numPhysicalRegs + numMiscRegs);
-
- miscScoreboard[renamed_reg] = false;
}
return RenameInfo(renamed_reg, prev_reg);
}
-//Perhaps give this a pair as a return value, of the physical register
-//and whether or not it's ready.
PhysRegIndex
SimpleRenameMap::lookup(RegIndex arch_reg)
{
if (arch_reg < numLogicalIntRegs) {
return intRenameMap[arch_reg].physical_reg;
} else if (arch_reg < numLogicalRegs) {
- // Subtract off the base FP offset.
-// arch_reg = arch_reg - numLogicalIntRegs;
-
return floatRenameMap[arch_reg].physical_reg;
} else {
// Subtract off the misc registers offset.
@@ -244,38 +214,18 @@ SimpleRenameMap::lookup(RegIndex arch_reg)
}
}
-bool
-SimpleRenameMap::isReady(PhysRegIndex phys_reg)
-{
- if (phys_reg < numPhysicalIntRegs) {
- return intScoreboard[phys_reg];
- } else if (phys_reg < numPhysicalRegs) {
-
- // Subtract off the base FP offset.
-// phys_reg = phys_reg - numPhysicalIntRegs;
-
- return floatScoreboard[phys_reg];
- } else {
- // Subtract off the misc registers offset.
-// phys_reg = phys_reg - numPhysicalRegs;
-
- return miscScoreboard[phys_reg];
- }
-}
-
-// In this implementation the miscellaneous registers do not actually rename,
-// so this function does not allow you to try to change their mappings.
void
SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg)
{
+ // In this implementation the miscellaneous registers do not
+ // actually rename, so this function does not allow you to try to
+ // change their mappings.
if (arch_reg < numLogicalIntRegs) {
DPRINTF(Rename, "Rename Map: Integer register %i being set to %i.\n",
(int)arch_reg, renamed_reg);
intRenameMap[arch_reg].physical_reg = renamed_reg;
- } else {
- assert(arch_reg < (numLogicalIntRegs + numLogicalFloatRegs));
-
+ } else if (arch_reg < numLogicalIntRegs + numLogicalFloatRegs) {
DPRINTF(Rename, "Rename Map: Float register %i being set to %i.\n",
(int)arch_reg - numLogicalIntRegs, renamed_reg);
@@ -283,55 +233,6 @@ SimpleRenameMap::setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg)
}
}
-void
-SimpleRenameMap::squash(vector<RegIndex> freed_regs,
- vector<UnmapInfo> unmaps)
-{
- panic("Not sure this function should be called.");
-
- // Not sure the rename map should be able to access the free list
- // like this.
- while (!freed_regs.empty()) {
- RegIndex free_register = freed_regs.back();
-
- if (free_register < numPhysicalIntRegs) {
- freeList->addIntReg(free_register);
- } else {
- // Subtract off the base FP dependence tag.
- free_register = free_register - numPhysicalIntRegs;
- freeList->addFloatReg(free_register);
- }
-
- freed_regs.pop_back();
- }
-
- // Take unmap info and roll back the rename map.
-}
-
-void
-SimpleRenameMap::markAsReady(PhysRegIndex ready_reg)
-{
- DPRINTF(Rename, "Rename map: Marking register %i as ready.\n",
- (int)ready_reg);
-
- if (ready_reg < numPhysicalIntRegs) {
- assert(ready_reg >= 0);
-
- intScoreboard[ready_reg] = 1;
- } else if (ready_reg < numPhysicalRegs) {
-
- // Subtract off the base FP offset.
-// ready_reg = ready_reg - numPhysicalIntRegs;
-
- floatScoreboard[ready_reg] = 1;
- } else {
- //Subtract off the misc registers offset.
-// ready_reg = ready_reg - numPhysicalRegs;
-
- miscScoreboard[ready_reg] = 1;
- }
-}
-
int
SimpleRenameMap::numFreeEntries()
{
diff --git a/src/cpu/o3/rename_map.hh b/src/cpu/o3/rename_map.hh
index 57be4a64a..c4c90c99a 100644
--- a/src/cpu/o3/rename_map.hh
+++ b/src/cpu/o3/rename_map.hh
@@ -24,14 +24,16 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
// Todo: Create destructor.
// Have it so that there's a more meaningful name given to the variable
// that marks the beginning of the FP registers.
-#ifndef __CPU_O3_CPU_RENAME_MAP_HH__
-#define __CPU_O3_CPU_RENAME_MAP_HH__
+#ifndef __CPU_O3_RENAME_MAP_HH__
+#define __CPU_O3_RENAME_MAP_HH__
#include <iostream>
#include <utility>
@@ -62,18 +64,30 @@ class SimpleRenameMap
typedef std::pair<PhysRegIndex, PhysRegIndex> RenameInfo;
public:
- //Constructor
- SimpleRenameMap(unsigned _numLogicalIntRegs,
- unsigned _numPhysicalIntRegs,
- unsigned _numLogicalFloatRegs,
- unsigned _numPhysicalFloatRegs,
- unsigned _numMiscRegs,
- RegIndex _intZeroReg,
- RegIndex _floatZeroReg);
+ /** Default constructor. init() must be called prior to use. */
+ SimpleRenameMap() {};
/** Destructor. */
~SimpleRenameMap();
+ /** Initializes rename map with given parameters. */
+ void init(unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ PhysRegIndex &_int_reg_start,
+
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ PhysRegIndex &_float_reg_start,
+
+ unsigned _numMiscRegs,
+
+ RegIndex _intZeroReg,
+ RegIndex _floatZeroReg,
+
+ int id,
+ bool bindRegs);
+
+ /** Sets the free list used with this rename map. */
void setFreeList(SimpleFreeList *fl_ptr);
//Tell rename map to get a free physical register for a given
@@ -84,23 +98,19 @@ class SimpleRenameMap
PhysRegIndex lookup(RegIndex phys_reg);
- bool isReady(PhysRegIndex arch_reg);
-
/**
* Marks the given register as ready, meaning that its value has been
* calculated and written to the register file.
* @param ready_reg The index of the physical register that is now ready.
*/
- void markAsReady(PhysRegIndex ready_reg);
-
void setEntry(RegIndex arch_reg, PhysRegIndex renamed_reg);
- void squash(std::vector<RegIndex> freed_regs,
- std::vector<UnmapInfo> unmaps);
-
int numFreeEntries();
private:
+ /** Rename Map ID */
+ int id;
+
/** Number of logical integer registers. */
int numLogicalIntRegs;
@@ -143,31 +153,16 @@ class SimpleRenameMap
{ }
};
+ private:
/** Integer rename map. */
- RenameEntry *intRenameMap;
+ std::vector<RenameEntry> intRenameMap;
/** Floating point rename map. */
- RenameEntry *floatRenameMap;
+ std::vector<RenameEntry> floatRenameMap;
+ private:
/** Free list interface. */
SimpleFreeList *freeList;
-
- // Might want to make all these scoreboards into one large scoreboard.
-
- /** Scoreboard of physical integer registers, saying whether or not they
- * are ready.
- */
- std::vector<bool> intScoreboard;
-
- /** Scoreboard of physical floating registers, saying whether or not they
- * are ready.
- */
- std::vector<bool> floatScoreboard;
-
- /** Scoreboard of miscellaneous registers, saying whether or not they
- * are ready.
- */
- std::vector<bool> miscScoreboard;
};
-#endif //__CPU_O3_CPU_RENAME_MAP_HH__
+#endif //__CPU_O3_RENAME_MAP_HH__
diff --git a/src/cpu/o3/rob.cc b/src/cpu/o3/rob.cc
index c10f782fd..9976049cd 100644
--- a/src/cpu/o3/rob.cc
+++ b/src/cpu/o3/rob.cc
@@ -24,11 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
-#include "cpu/o3/alpha_dyn_inst.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/rob_impl.hh"
// Force instantiation of InstructionQueue.
-template class ROB<AlphaSimpleImpl>;
+template class ROB<O3CPUImpl>;
diff --git a/src/cpu/o3/rob.hh b/src/cpu/o3/rob.hh
index 1185564ad..6f8080ef4 100644
--- a/src/cpu/o3/rob.hh
+++ b/src/cpu/o3/rob.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,25 +24,20 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-// Todo: Probably add in support for scheduling events (more than one as
-// well) on the case of the ROB being empty or full. Considering tracking
-// free entries instead of insts in ROB. Differentiate between squashing
-// all instructions after the instruction, and all instructions after *and*
-// including that instruction.
-
-#ifndef __CPU_O3_CPU_ROB_HH__
-#define __CPU_O3_CPU_ROB_HH__
+#ifndef __CPU_O3_ROB_HH__
+#define __CPU_O3_ROB_HH__
+#include <string>
#include <utility>
#include <vector>
/**
- * ROB class. Uses the instruction list that exists within the CPU to
- * represent the ROB. This class doesn't contain that list, but instead
- * a pointer to the CPU to get access to the list. The ROB, in this first
- * implementation, is largely what drives squashing.
+ * ROB class. The ROB is largely what drives squashing.
*/
template <class Impl>
class ROB
@@ -51,32 +46,68 @@ class ROB
typedef TheISA::RegIndex RegIndex;
public:
//Typedefs from the Impl.
- typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::O3CPU O3CPU;
typedef typename Impl::DynInstPtr DynInstPtr;
- typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo_t;
- typedef typename list<DynInstPtr>::iterator InstIt_t;
+ typedef std::pair<RegIndex, PhysRegIndex> UnmapInfo;
+ typedef typename std::list<DynInstPtr>::iterator InstIt;
+
+ /** Possible ROB statuses. */
+ enum Status {
+ Running,
+ Idle,
+ ROBSquashing
+ };
+
+ /** SMT ROB Sharing Policy */
+ enum ROBPolicy{
+ Dynamic,
+ Partitioned,
+ Threshold
+ };
+
+ private:
+ /** Per-thread ROB status. */
+ Status robStatus[Impl::MaxThreads];
+
+ /** ROB resource sharing policy for SMT mode. */
+ ROBPolicy robPolicy;
public:
/** ROB constructor.
- * @param _numEntries Number of entries in ROB.
- * @param _squashWidth Number of instructions that can be squashed in a
- * single cycle.
+ * @param _numEntries Number of entries in ROB.
+ * @param _squashWidth Number of instructions that can be squashed in a
+ * single cycle.
+ * @param _smtROBPolicy ROB Partitioning Scheme for SMT.
+ * @param _smtROBThreshold Max Resources(by %) a thread can have in the ROB.
+ * @param _numThreads The number of active threads.
*/
- ROB(unsigned _numEntries, unsigned _squashWidth);
+ ROB(unsigned _numEntries, unsigned _squashWidth, std::string smtROBPolicy,
+ unsigned _smtROBThreshold, unsigned _numThreads);
+
+ std::string name() const;
/** Function to set the CPU pointer, necessary due to which object the ROB
* is created within.
* @param cpu_ptr Pointer to the implementation specific full CPU object.
*/
- void setCPU(FullCPU *cpu_ptr);
+ void setCPU(O3CPU *cpu_ptr);
+
+ /** Sets pointer to the list of active threads.
+ * @param at_ptr Pointer to the list of active threads.
+ */
+ void setActiveThreads(std::list<unsigned>* at_ptr);
+
+ /** Switches out the ROB. */
+ void switchOut();
- /** Function to insert an instruction into the ROB. The parameter inst is
- * not truly required, but is useful for checking correctness. Note
- * that whatever calls this function must ensure that there is enough
- * space within the ROB for the new instruction.
+ /** Takes over another CPU's thread. */
+ void takeOverFrom();
+
+ /** Function to insert an instruction into the ROB. Note that whatever
+ * calls this function must ensure that there is enough space within the
+ * ROB for the new instruction.
* @param inst The instruction being inserted into the ROB.
- * @todo Remove the parameter once correctness is ensured.
*/
void insertInst(DynInstPtr &inst);
@@ -84,40 +115,134 @@ class ROB
* no guarantee as to the return value if the ROB is empty.
* @retval Pointer to the DynInst that is at the head of the ROB.
*/
- DynInstPtr readHeadInst() { return cpu->instList.front(); }
+// DynInstPtr readHeadInst();
+
+ /** Returns a pointer to the head instruction of a specific thread within
+ * the ROB.
+ * @return Pointer to the DynInst that is at the head of the ROB.
+ */
+ DynInstPtr readHeadInst(unsigned tid);
- DynInstPtr readTailInst() { return (*tail); }
+ /** Returns pointer to the tail instruction within the ROB. There is
+ * no guarantee as to the return value if the ROB is empty.
+ * @retval Pointer to the DynInst that is at the tail of the ROB.
+ */
+// DynInstPtr readTailInst();
+
+ /** Returns a pointer to the tail instruction of a specific thread within
+ * the ROB.
+ * @return Pointer to the DynInst that is at the tail of the ROB.
+ */
+ DynInstPtr readTailInst(unsigned tid);
+
+ /** Retires the head instruction, removing it from the ROB. */
+// void retireHead();
+
+ /** Retires the head instruction of a specific thread, removing it from the
+ * ROB.
+ */
+ void retireHead(unsigned tid);
- void retireHead();
+ /** Is the oldest instruction across all threads ready. */
+// bool isHeadReady();
- bool isHeadReady();
+ /** Is the oldest instruction across a particular thread ready. */
+ bool isHeadReady(unsigned tid);
+ /** Is there any commitable head instruction across all threads ready. */
+ bool canCommit();
+
+ /** Re-adjust ROB partitioning. */
+ void resetEntries();
+
+ /** Number of entries needed For 'num_threads' amount of threads. */
+ int entryAmount(int num_threads);
+
+ /** Returns the number of total free entries in the ROB. */
unsigned numFreeEntries();
+ /** Returns the number of free entries in a specific ROB paritition. */
+ unsigned numFreeEntries(unsigned tid);
+
+ /** Returns the maximum number of entries for a specific thread. */
+ unsigned getMaxEntries(unsigned tid)
+ { return maxEntries[tid]; }
+
+ /** Returns the number of entries being used by a specific thread. */
+ unsigned getThreadEntries(unsigned tid)
+ { return threadEntries[tid]; }
+
+ /** Returns if the ROB is full. */
bool isFull()
{ return numInstsInROB == numEntries; }
+ /** Returns if a specific thread's partition is full. */
+ bool isFull(unsigned tid)
+ { return threadEntries[tid] == numEntries; }
+
+ /** Returns if the ROB is empty. */
bool isEmpty()
{ return numInstsInROB == 0; }
- void doSquash();
+ /** Returns if a specific thread's partition is empty. */
+ bool isEmpty(unsigned tid)
+ { return threadEntries[tid] == 0; }
- void squash(InstSeqNum squash_num);
+ /** Executes the squash, marking squashed instructions. */
+ void doSquash(unsigned tid);
- uint64_t readHeadPC();
+ /** Squashes all instructions younger than the given sequence number for
+ * the specific thread.
+ */
+ void squash(InstSeqNum squash_num, unsigned tid);
+
+ /** Updates the head instruction with the new oldest instruction. */
+ void updateHead();
+
+ /** Updates the tail instruction with the new youngest instruction. */
+ void updateTail();
+
+ /** Reads the PC of the oldest head instruction. */
+// uint64_t readHeadPC();
+
+ /** Reads the PC of the head instruction of a specific thread. */
+// uint64_t readHeadPC(unsigned tid);
+
+ /** Reads the next PC of the oldest head instruction. */
+// uint64_t readHeadNextPC();
+
+ /** Reads the next PC of the head instruction of a specific thread. */
+// uint64_t readHeadNextPC(unsigned tid);
- uint64_t readHeadNextPC();
+ /** Reads the sequence number of the oldest head instruction. */
+// InstSeqNum readHeadSeqNum();
- InstSeqNum readHeadSeqNum();
+ /** Reads the sequence number of the head instruction of a specific thread.
+ */
+// InstSeqNum readHeadSeqNum(unsigned tid);
+
+ /** Reads the PC of the youngest tail instruction. */
+// uint64_t readTailPC();
- uint64_t readTailPC();
+ /** Reads the PC of the tail instruction of a specific thread. */
+// uint64_t readTailPC(unsigned tid);
- InstSeqNum readTailSeqNum();
+ /** Reads the sequence number of the youngest tail instruction. */
+// InstSeqNum readTailSeqNum();
+
+ /** Reads the sequence number of tail instruction of a specific thread. */
+// InstSeqNum readTailSeqNum(unsigned tid);
/** Checks if the ROB is still in the process of squashing instructions.
* @retval Whether or not the ROB is done squashing.
*/
- bool isDoneSquashing() const { return doneSquashing; }
+ bool isDoneSquashing(unsigned tid) const
+ { return doneSquashing[tid]; }
+
+ /** Checks if the ROB is still in the process of squashing instructions for
+ * any thread.
+ */
+ bool isDoneSquashing();
/** This is more of a debugging function than anything. Use
* numInstsInROB to get the instructions in the ROB unless you are
@@ -125,23 +250,46 @@ class ROB
*/
int countInsts();
- private:
+ /** This is more of a debugging function than anything. Use
+ * threadEntries to get the instructions in the ROB unless you are
+ * double checking that variable.
+ */
+ int countInsts(unsigned tid);
+ private:
/** Pointer to the CPU. */
- FullCPU *cpu;
+ O3CPU *cpu;
+
+ /** Active Threads in CPU */
+ std::list<unsigned>* activeThreads;
/** Number of instructions in the ROB. */
unsigned numEntries;
+ /** Entries Per Thread */
+ unsigned threadEntries[Impl::MaxThreads];
+
+ /** Max Insts a Thread Can Have in the ROB */
+ unsigned maxEntries[Impl::MaxThreads];
+
+ /** ROB List of Instructions */
+ std::list<DynInstPtr> instList[Impl::MaxThreads];
+
/** Number of instructions that can be squashed in a single cycle. */
unsigned squashWidth;
+ public:
/** Iterator pointing to the instruction which is the last instruction
* in the ROB. This may at times be invalid (ie when the ROB is empty),
* however it should never be incorrect.
*/
- InstIt_t tail;
+ InstIt tail;
+
+ /** Iterator pointing to the instruction which is the first instruction in
+ * in the ROB*/
+ InstIt head;
+ private:
/** Iterator used for walking through the list of instructions when
* squashing. Used so that there is persistent state between cycles;
* when squashing, the instructions are marked as squashed but not
@@ -149,16 +297,24 @@ class ROB
* and after a squash.
* This will always be set to cpu->instList.end() if it is invalid.
*/
- InstIt_t squashIt;
+ InstIt squashIt[Impl::MaxThreads];
+ public:
/** Number of instructions in the ROB. */
int numInstsInROB;
+ /** Dummy instruction returned if there are no insts left. */
+ DynInstPtr dummyInst;
+
+ private:
/** The sequence number of the squashed instruction. */
InstSeqNum squashedSeqNum;
/** Is the ROB done squashing. */
- bool doneSquashing;
+ bool doneSquashing[Impl::MaxThreads];
+
+ /** Number of active threads. */
+ unsigned numThreads;
};
-#endif //__CPU_O3_CPU_ROB_HH__
+#endif //__CPU_O3_ROB_HH__
diff --git a/src/cpu/o3/rob_impl.hh b/src/cpu/o3/rob_impl.hh
index e7a5671d9..d9978b17f 100644
--- a/src/cpu/o3/rob_impl.hh
+++ b/src/cpu/o3/rob_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,148 +24,308 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_ROB_IMPL_HH__
-#define __CPU_O3_CPU_ROB_IMPL_HH__
-
#include "config/full_system.hh"
#include "cpu/o3/rob.hh"
+using namespace std;
+
template <class Impl>
-ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth)
+ROB<Impl>::ROB(unsigned _numEntries, unsigned _squashWidth,
+ string _smtROBPolicy, unsigned _smtROBThreshold,
+ unsigned _numThreads)
: numEntries(_numEntries),
squashWidth(_squashWidth),
numInstsInROB(0),
- squashedSeqNum(0)
+ squashedSeqNum(0),
+ numThreads(_numThreads)
+{
+ for (int tid=0; tid < numThreads; tid++) {
+ doneSquashing[tid] = true;
+ threadEntries[tid] = 0;
+ }
+
+ string policy = _smtROBPolicy;
+
+ //Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ //Figure out rob policy
+ if (policy == "dynamic") {
+ robPolicy = Dynamic;
+
+ //Set Max Entries to Total ROB Capacity
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i]=numEntries;
+ }
+
+ } else if (policy == "partitioned") {
+ robPolicy = Partitioned;
+ DPRINTF(Fetch, "ROB sharing policy set to Partitioned\n");
+
+ //@todo:make work if part_amt doesnt divide evenly.
+ int part_amt = numEntries / numThreads;
+
+ //Divide ROB up evenly
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i]=part_amt;
+ }
+
+ } else if (policy == "threshold") {
+ robPolicy = Threshold;
+ DPRINTF(Fetch, "ROB sharing policy set to Threshold\n");
+
+ int threshold = _smtROBThreshold;;
+
+ //Divide up by threshold amount
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i]=threshold;
+ }
+ } else {
+ assert(0 && "Invalid ROB Sharing Policy.Options Are:{Dynamic,"
+ "Partitioned, Threshold}");
+ }
+}
+
+template <class Impl>
+std::string
+ROB<Impl>::name() const
{
- doneSquashing = true;
+ return cpu->name() + ".rob";
}
template <class Impl>
void
-ROB<Impl>::setCPU(FullCPU *cpu_ptr)
+ROB<Impl>::setCPU(O3CPU *cpu_ptr)
{
cpu = cpu_ptr;
- // Set the tail to the beginning of the CPU instruction list so that
- // upon the first instruction being inserted into the ROB, the tail
- // iterator can simply be incremented.
- tail = cpu->instList.begin();
+ // Set the per-thread iterators to the end of the instruction list.
+ for (int i=0; i < numThreads;i++) {
+ squashIt[i] = instList[i].end();
+ }
- // Set the squash iterator to the end of the instruction list.
- squashIt = cpu->instList.end();
+ // Initialize the "universal" ROB head & tail point to invalid
+ // pointers
+ head = instList[0].end();
+ tail = instList[0].end();
}
template <class Impl>
-int
-ROB<Impl>::countInsts()
+void
+ROB<Impl>::setActiveThreads(list<unsigned> *at_ptr)
{
- // Start at 1; if the tail matches cpu->instList.begin(), then there is
- // one inst in the ROB.
- int return_val = 1;
+ DPRINTF(ROB, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
- // There are quite a few special cases. Do not use this function other
- // than for debugging purposes.
- if (cpu->instList.begin() == cpu->instList.end()) {
- // In this case there are no instructions in the list. The ROB
- // must be empty.
- return 0;
- } else if (tail == cpu->instList.end()) {
- // In this case, the tail is not yet pointing to anything valid.
- // The ROB must be empty.
- return 0;
+template <class Impl>
+void
+ROB<Impl>::switchOut()
+{
+ for (int tid = 0; tid < numThreads; tid++) {
+ instList[tid].clear();
}
+}
- // Iterate through the ROB from the head to the tail, counting the
- // entries.
- for (InstIt_t i = cpu->instList.begin(); i != tail; ++i)
- {
- assert(i != cpu->instList.end());
- ++return_val;
+template <class Impl>
+void
+ROB<Impl>::takeOverFrom()
+{
+ for (int tid=0; tid < numThreads; tid++) {
+ doneSquashing[tid] = true;
+ threadEntries[tid] = 0;
+ squashIt[tid] = instList[tid].end();
}
+ numInstsInROB = 0;
- return return_val;
+ // Initialize the "universal" ROB head & tail point to invalid
+ // pointers
+ head = instList[0].end();
+ tail = instList[0].end();
+}
- // Because the head won't be tracked properly until the ROB gets the
- // first instruction, and any time that the ROB is empty and has not
- // yet gotten the instruction, this function doesn't work.
-// return numInstsInROB;
+template <class Impl>
+void
+ROB<Impl>::resetEntries()
+{
+ if (robPolicy != Dynamic || numThreads > 1) {
+ int active_threads = (*activeThreads).size();
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<unsigned>::iterator list_end = (*activeThreads).end();
+
+ while (threads != list_end) {
+ if (robPolicy == Partitioned) {
+ maxEntries[*threads++] = numEntries / active_threads;
+ } else if (robPolicy == Threshold && active_threads == 1) {
+ maxEntries[*threads++] = numEntries;
+ }
+ }
+ }
+}
+
+template <class Impl>
+int
+ROB<Impl>::entryAmount(int num_threads)
+{
+ if (robPolicy == Partitioned) {
+ return numEntries / num_threads;
+ } else {
+ return 0;
+ }
+}
+
+template <class Impl>
+int
+ROB<Impl>::countInsts()
+{
+ int total=0;
+
+ for (int i=0;i < numThreads;i++)
+ total += countInsts(i);
+
+ return total;
+}
+
+template <class Impl>
+int
+ROB<Impl>::countInsts(unsigned tid)
+{
+ return instList[tid].size();
}
template <class Impl>
void
ROB<Impl>::insertInst(DynInstPtr &inst)
{
- // Make sure we have the right number of instructions.
- assert(numInstsInROB == countInsts());
- // Make sure the instruction is valid.
+ //assert(numInstsInROB == countInsts());
assert(inst);
- DPRINTF(ROB, "ROB: Adding inst PC %#x to the ROB.\n", inst->readPC());
+ DPRINTF(ROB, "Adding inst PC %#x to the ROB.\n", inst->readPC());
- // If the ROB is full then exit.
assert(numInstsInROB != numEntries);
- ++numInstsInROB;
+ int tid = inst->threadNumber;
- // Increment the tail iterator, moving it one instruction back.
- // There is a special case if the ROB was empty prior to this insertion,
- // in which case the tail will be pointing at instList.end(). If that
- // happens, then reset the tail to the beginning of the list.
- if (tail != cpu->instList.end()) {
- ++tail;
- } else {
- tail = cpu->instList.begin();
+ instList[tid].push_back(inst);
+
+ //Set Up head iterator if this is the 1st instruction in the ROB
+ if (numInstsInROB == 0) {
+ head = instList[tid].begin();
+ assert((*head) == inst);
}
- // Make sure the tail iterator is actually pointing at the instruction
- // added.
- assert((*tail) == inst);
+ //Must Decrement for iterator to actually be valid since __.end()
+ //actually points to 1 after the last inst
+ tail = instList[tid].end();
+ tail--;
+
+ inst->setInROB();
- DPRINTF(ROB, "ROB: Now has %d instructions.\n", numInstsInROB);
+ ++numInstsInROB;
+ ++threadEntries[tid];
+
+ assert((*tail) == inst);
+ DPRINTF(ROB, "[tid:%i] Now has %d instructions.\n", tid, threadEntries[tid]);
}
// Whatever calls this function needs to ensure that it properly frees up
// registers prior to this function.
+/*
template <class Impl>
void
ROB<Impl>::retireHead()
{
- assert(numInstsInROB == countInsts());
+ //assert(numInstsInROB == countInsts());
+ assert(numInstsInROB > 0);
+
+ int tid = (*head)->threadNumber;
+
+ retireHead(tid);
+
+ if (numInstsInROB == 0) {
+ tail = instList[tid].end();
+ }
+}
+*/
+
+template <class Impl>
+void
+ROB<Impl>::retireHead(unsigned tid)
+{
+ //assert(numInstsInROB == countInsts());
assert(numInstsInROB > 0);
// Get the head ROB instruction.
- DynInstPtr head_inst = cpu->instList.front();
+ InstIt head_it = instList[tid].begin();
+
+ DynInstPtr head_inst = (*head_it);
- // Make certain this can retire.
assert(head_inst->readyToCommit());
- DPRINTF(ROB, "ROB: Retiring head instruction of the ROB, "
- "instruction PC %#x, seq num %i\n", head_inst->readPC(),
+ DPRINTF(ROB, "[tid:%u]: Retiring head instruction, "
+ "instruction PC %#x,[sn:%lli]\n", tid, head_inst->readPC(),
head_inst->seqNum);
- // Keep track of how many instructions are in the ROB.
--numInstsInROB;
+ --threadEntries[tid];
+
+ head_inst->clearInROB();
+ head_inst->setCommitted();
- // Tell CPU to remove the instruction from the list of instructions.
- // A special case is needed if the instruction being retired is the
- // only instruction in the ROB; otherwise the tail iterator will become
- // invalidated.
+ instList[tid].erase(head_it);
+
+ //Update "Global" Head of ROB
+ updateHead();
+
+ // @todo: A special case is needed if the instruction being
+ // retired is the only instruction in the ROB; otherwise the tail
+ // iterator will become invalidated.
cpu->removeFrontInst(head_inst);
+}
+/*
+template <class Impl>
+bool
+ROB<Impl>::isHeadReady()
+{
+ if (numInstsInROB != 0) {
+ return (*head)->readyToCommit();
+ }
- if (numInstsInROB == 0) {
- tail = cpu->instList.end();
+ return false;
+}
+*/
+template <class Impl>
+bool
+ROB<Impl>::isHeadReady(unsigned tid)
+{
+ if (threadEntries[tid] != 0) {
+ return instList[tid].front()->readyToCommit();
}
+
+ return false;
}
template <class Impl>
bool
-ROB<Impl>::isHeadReady()
+ROB<Impl>::canCommit()
{
- if (numInstsInROB != 0) {
- return cpu->instList.front()->readyToCommit();
+ //@todo: set ActiveThreads through ROB or CPU
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (isHeadReady(tid)) {
+ return true;
+ }
}
return false;
@@ -175,131 +335,339 @@ template <class Impl>
unsigned
ROB<Impl>::numFreeEntries()
{
- assert(numInstsInROB == countInsts());
+ //assert(numInstsInROB == countInsts());
return numEntries - numInstsInROB;
}
template <class Impl>
+unsigned
+ROB<Impl>::numFreeEntries(unsigned tid)
+{
+ return maxEntries[tid] - threadEntries[tid];
+}
+
+template <class Impl>
void
-ROB<Impl>::doSquash()
+ROB<Impl>::doSquash(unsigned tid)
{
- DPRINTF(ROB, "ROB: Squashing instructions.\n");
+ DPRINTF(ROB, "[tid:%u]: Squashing instructions until [sn:%i].\n",
+ tid, squashedSeqNum);
+
+ assert(squashIt[tid] != instList[tid].end());
- assert(squashIt != cpu->instList.end());
+ if ((*squashIt[tid])->seqNum < squashedSeqNum) {
+ DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
+ tid);
+
+ squashIt[tid] = instList[tid].end();
+
+ doneSquashing[tid] = true;
+ return;
+ }
+
+ bool robTailUpdate = false;
for (int numSquashed = 0;
- numSquashed < squashWidth && (*squashIt)->seqNum != squashedSeqNum;
+ numSquashed < squashWidth &&
+ squashIt[tid] != instList[tid].end() &&
+ (*squashIt[tid])->seqNum > squashedSeqNum;
++numSquashed)
{
- // Ensure that the instruction is younger.
- assert((*squashIt)->seqNum > squashedSeqNum);
-
- DPRINTF(ROB, "ROB: Squashing instruction PC %#x, seq num %i.\n",
- (*squashIt)->readPC(), (*squashIt)->seqNum);
+ DPRINTF(ROB, "[tid:%u]: Squashing instruction PC %#x, seq num %i.\n",
+ (*squashIt[tid])->threadNumber,
+ (*squashIt[tid])->readPC(),
+ (*squashIt[tid])->seqNum);
// Mark the instruction as squashed, and ready to commit so that
// it can drain out of the pipeline.
- (*squashIt)->setSquashed();
-
- (*squashIt)->setCanCommit();
-
- // Special case for when squashing due to a syscall. It's possible
- // that the squash happened after the head instruction was already
- // committed, meaning that (*squashIt)->seqNum != squashedSeqNum
- // will never be false. Normally the squash would never be able
- // to go past the head of the ROB; in this case it might, so it
- // must be handled otherwise it will segfault.
-#if !FULL_SYSTEM
- if (squashIt == cpu->instList.begin()) {
- DPRINTF(ROB, "ROB: Reached head of instruction list while "
+ (*squashIt[tid])->setSquashed();
+
+ (*squashIt[tid])->setCanCommit();
+
+
+ if (squashIt[tid] == instList[tid].begin()) {
+ DPRINTF(ROB, "Reached head of instruction list while "
"squashing.\n");
- squashIt = cpu->instList.end();
+ squashIt[tid] = instList[tid].end();
- doneSquashing = true;
+ doneSquashing[tid] = true;
return;
}
-#endif
- // Move the tail iterator to the next instruction.
- squashIt--;
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
+
+ if ((*squashIt[tid]) == (*tail_thread))
+ robTailUpdate = true;
+
+ squashIt[tid]--;
}
// Check if ROB is done squashing.
- if ((*squashIt)->seqNum == squashedSeqNum) {
- DPRINTF(ROB, "ROB: Done squashing instructions.\n");
+ if ((*squashIt[tid])->seqNum <= squashedSeqNum) {
+ DPRINTF(ROB, "[tid:%u]: Done squashing instructions.\n",
+ tid);
- squashIt = cpu->instList.end();
+ squashIt[tid] = instList[tid].end();
+
+ doneSquashing[tid] = true;
+ }
- doneSquashing = true;
+ if (robTailUpdate) {
+ updateTail();
}
}
+
template <class Impl>
void
-ROB<Impl>::squash(InstSeqNum squash_num)
+ROB<Impl>::updateHead()
{
- DPRINTF(ROB, "ROB: Starting to squash within the ROB.\n");
- doneSquashing = false;
+ DynInstPtr head_inst;
+ InstSeqNum lowest_num = 0;
+ bool first_valid = true;
+
+ // @todo: set ActiveThreads through ROB or CPU
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned thread_num = *threads++;
+
+ if (instList[thread_num].empty())
+ continue;
+
+ if (first_valid) {
+ head = instList[thread_num].begin();
+ lowest_num = (*head)->seqNum;
+ first_valid = false;
+ continue;
+ }
+
+ InstIt head_thread = instList[thread_num].begin();
+
+ DynInstPtr head_inst = (*head_thread);
+
+ assert(head_inst != 0);
+
+ if (head_inst->seqNum < lowest_num) {
+ head = head_thread;
+ lowest_num = head_inst->seqNum;
+ }
+ }
+
+ if (first_valid) {
+ head = instList[0].end();
+ }
+
+}
+
+template <class Impl>
+void
+ROB<Impl>::updateTail()
+{
+ tail = instList[0].end();
+ bool first_valid = true;
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+
+ while (threads != (*activeThreads).end()) {
+ unsigned tid = *threads++;
+
+ if (instList[tid].empty()) {
+ continue;
+ }
+
+ // If this is the first valid then assign w/out
+ // comparison
+ if (first_valid) {
+ tail = instList[tid].end();
+ tail--;
+ first_valid = false;
+ continue;
+ }
+
+ // Assign new tail if this thread's tail is younger
+ // than our current "tail high"
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
+
+ if ((*tail_thread)->seqNum > (*tail)->seqNum) {
+ tail = tail_thread;
+ }
+ }
+}
+
+
+template <class Impl>
+void
+ROB<Impl>::squash(InstSeqNum squash_num,unsigned tid)
+{
+ if (isEmpty()) {
+ DPRINTF(ROB, "Does not need to squash due to being empty "
+ "[sn:%i]\n",
+ squash_num);
+
+ return;
+ }
+
+ DPRINTF(ROB, "Starting to squash within the ROB.\n");
+
+ robStatus[tid] = ROBSquashing;
+
+ doneSquashing[tid] = false;
squashedSeqNum = squash_num;
- assert(tail != cpu->instList.end());
+ if (!instList[tid].empty()) {
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
- squashIt = tail;
+ squashIt[tid] = tail_thread;
- doSquash();
+ doSquash(tid);
+ }
}
+/*
+template <class Impl>
+typename Impl::DynInstPtr
+ROB<Impl>::readHeadInst()
+{
+ if (numInstsInROB != 0) {
+ assert((*head)->isInROB()==true);
+ return *head;
+ } else {
+ return dummyInst;
+ }
+}
+*/
+template <class Impl>
+typename Impl::DynInstPtr
+ROB<Impl>::readHeadInst(unsigned tid)
+{
+ if (threadEntries[tid] != 0) {
+ InstIt head_thread = instList[tid].begin();
+ assert((*head_thread)->isInROB()==true);
+
+ return *head_thread;
+ } else {
+ return dummyInst;
+ }
+}
+/*
template <class Impl>
uint64_t
ROB<Impl>::readHeadPC()
{
- assert(numInstsInROB == countInsts());
+ //assert(numInstsInROB == countInsts());
- DynInstPtr head_inst = cpu->instList.front();
+ DynInstPtr head_inst = *head;
return head_inst->readPC();
}
template <class Impl>
uint64_t
+ROB<Impl>::readHeadPC(unsigned tid)
+{
+ //assert(numInstsInROB == countInsts());
+ InstIt head_thread = instList[tid].begin();
+
+ return (*head_thread)->readPC();
+}
+
+
+template <class Impl>
+uint64_t
ROB<Impl>::readHeadNextPC()
{
- assert(numInstsInROB == countInsts());
+ //assert(numInstsInROB == countInsts());
- DynInstPtr head_inst = cpu->instList.front();
+ DynInstPtr head_inst = *head;
return head_inst->readNextPC();
}
template <class Impl>
+uint64_t
+ROB<Impl>::readHeadNextPC(unsigned tid)
+{
+ //assert(numInstsInROB == countInsts());
+ InstIt head_thread = instList[tid].begin();
+
+ return (*head_thread)->readNextPC();
+}
+
+template <class Impl>
InstSeqNum
ROB<Impl>::readHeadSeqNum()
{
- // Return the last sequence number that has not been squashed. Other
- // stages can use it to squash any instructions younger than the current
- // tail.
- DynInstPtr head_inst = cpu->instList.front();
+ //assert(numInstsInROB == countInsts());
+ DynInstPtr head_inst = *head;
return head_inst->seqNum;
}
template <class Impl>
+InstSeqNum
+ROB<Impl>::readHeadSeqNum(unsigned tid)
+{
+ InstIt head_thread = instList[tid].begin();
+
+ return ((*head_thread)->seqNum);
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+ROB<Impl>::readTailInst()
+{
+ //assert(numInstsInROB == countInsts());
+ //assert(tail != instList[0].end());
+
+ return (*tail);
+}
+*/
+template <class Impl>
+typename Impl::DynInstPtr
+ROB<Impl>::readTailInst(unsigned tid)
+{
+ //assert(tail_thread[tid] != instList[tid].end());
+
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
+
+ return *tail_thread;
+}
+
+/*
+template <class Impl>
uint64_t
ROB<Impl>::readTailPC()
{
- assert(numInstsInROB == countInsts());
+ //assert(numInstsInROB == countInsts());
- assert(tail != cpu->instList.end());
+ //assert(tail != instList[0].end());
return (*tail)->readPC();
}
template <class Impl>
+uint64_t
+ROB<Impl>::readTailPC(unsigned tid)
+{
+ //assert(tail_thread[tid] != instList[tid].end());
+
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
+
+ return (*tail_thread)->readPC();
+}
+
+template <class Impl>
InstSeqNum
ROB<Impl>::readTailSeqNum()
{
@@ -309,4 +677,18 @@ ROB<Impl>::readTailSeqNum()
return (*tail)->seqNum;
}
-#endif // __CPU_O3_CPU_ROB_IMPL_HH__
+template <class Impl>
+InstSeqNum
+ROB<Impl>::readTailSeqNum(unsigned tid)
+{
+ // Return the last sequence number that has not been squashed. Other
+ // stages can use it to squash any instructions younger than the current
+ // tail.
+ // assert(tail_thread[tid] != instList[tid].end());
+
+ InstIt tail_thread = instList[tid].end();
+ tail_thread--;
+
+ return (*tail_thread)->seqNum;
+}
+*/
diff --git a/src/cpu/o3/sat_counter.cc b/src/cpu/o3/sat_counter.cc
index d20fff650..68d3ef627 100644
--- a/src/cpu/o3/sat_counter.cc
+++ b/src/cpu/o3/sat_counter.cc
@@ -24,27 +24,29 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/misc.hh"
#include "cpu/o3/sat_counter.hh"
SatCounter::SatCounter()
- : maxVal(0), counter(0)
+ : initialVal(0), counter(0)
{
}
SatCounter::SatCounter(unsigned bits)
- : maxVal((1 << bits) - 1), counter(0)
+ : initialVal(0), maxVal((1 << bits) - 1), counter(0)
{
}
-SatCounter::SatCounter(unsigned bits, unsigned initial_val)
- : maxVal((1 << bits) - 1), counter(initial_val)
+SatCounter::SatCounter(unsigned bits, uint8_t initial_val)
+ : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val)
{
// Check to make sure initial value doesn't exceed the max counter value.
if (initial_val > maxVal) {
- panic("BP: Initial counter value exceeds max size.");
+ fatal("BP: Initial counter value exceeds max size.");
}
}
@@ -53,19 +55,3 @@ SatCounter::setBits(unsigned bits)
{
maxVal = (1 << bits) - 1;
}
-
-void
-SatCounter::increment()
-{
- if(counter < maxVal) {
- ++counter;
- }
-}
-
-void
-SatCounter::decrement()
-{
- if(counter > 0) {
- --counter;
- }
-}
diff --git a/src/cpu/o3/sat_counter.hh b/src/cpu/o3/sat_counter.hh
index b7cfe6423..7e15119b0 100644
--- a/src/cpu/o3/sat_counter.hh
+++ b/src/cpu/o3/sat_counter.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 The Regents of The University of Michigan
+ * 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
@@ -24,11 +24,14 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_SAT_COUNTER_HH__
-#define __CPU_O3_CPU_SAT_COUNTER_HH__
+#ifndef __CPU_O3_SAT_COUNTER_HH__
+#define __CPU_O3_SAT_COUNTER_HH__
+#include "base/misc.hh"
#include "sim/host.hh"
/**
@@ -44,47 +47,70 @@ class SatCounter
/**
* Constructor for the counter.
*/
- SatCounter();
+ SatCounter()
+ : initialVal(0), counter(0)
+ { }
/**
* Constructor for the counter.
* @param bits How many bits the counter will have.
*/
- SatCounter(unsigned bits);
+ SatCounter(unsigned bits)
+ : initialVal(0), maxVal((1 << bits) - 1), counter(0)
+ { }
/**
* Constructor for the counter.
* @param bits How many bits the counter will have.
* @param initial_val Starting value for each counter.
*/
- SatCounter(unsigned bits, unsigned initial_val);
+ SatCounter(unsigned bits, uint8_t initial_val)
+ : initialVal(initialVal), maxVal((1 << bits) - 1), counter(initial_val)
+ {
+ // Check to make sure initial value doesn't exceed the max
+ // counter value.
+ if (initial_val > maxVal) {
+ fatal("BP: Initial counter value exceeds max size.");
+ }
+ }
/**
* Sets the number of bits.
*/
- void setBits(unsigned bits);
+ void setBits(unsigned bits) { maxVal = (1 << bits) - 1; }
+
+ void reset() { counter = initialVal; }
/**
* Increments the counter's current value.
*/
- void increment();
+ void increment()
+ {
+ if (counter < maxVal) {
+ ++counter;
+ }
+ }
/**
* Decrements the counter's current value.
*/
- void decrement();
+ void decrement()
+ {
+ if (counter > 0) {
+ --counter;
+ }
+ }
/**
* Read the counter's value.
*/
const uint8_t read() const
- {
- return counter;
- }
+ { return counter; }
private:
+ uint8_t initialVal;
uint8_t maxVal;
uint8_t counter;
};
-#endif // __CPU_O3_CPU_SAT_COUNTER_HH__
+#endif // __CPU_O3_SAT_COUNTER_HH__
diff --git a/src/cpu/o3/scoreboard.cc b/src/cpu/o3/scoreboard.cc
new file mode 100644
index 000000000..1859b35a4
--- /dev/null
+++ b/src/cpu/o3/scoreboard.cc
@@ -0,0 +1,109 @@
+/*
+ * 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: Korey Sewell
+ * Kevin Lim
+ */
+
+#include "cpu/o3/scoreboard.hh"
+
+Scoreboard::Scoreboard(unsigned activeThreads,
+ unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ unsigned _numMiscRegs,
+ unsigned _zeroRegIdx)
+ : numLogicalIntRegs(_numLogicalIntRegs),
+ numPhysicalIntRegs(_numPhysicalIntRegs),
+ numLogicalFloatRegs(_numLogicalFloatRegs),
+ numPhysicalFloatRegs(_numPhysicalFloatRegs),
+ numMiscRegs(_numMiscRegs),
+ zeroRegIdx(_zeroRegIdx)
+{
+ //Get Register Sizes
+ numLogicalRegs = numLogicalIntRegs + numLogicalFloatRegs;
+ numPhysicalRegs = numPhysicalIntRegs + numPhysicalFloatRegs;
+
+ //Resize scoreboard appropriately
+ regScoreBoard.resize(numPhysicalRegs + (numMiscRegs * activeThreads));
+
+ //Initialize values
+ for (int i=0; i < numLogicalIntRegs * activeThreads; i++) {
+ regScoreBoard[i] = 1;
+ }
+
+ for (int i= numPhysicalIntRegs;
+ i < numPhysicalIntRegs + (numLogicalFloatRegs * activeThreads);
+ i++) {
+ regScoreBoard[i] = 1;
+ }
+
+ for (int i = numPhysicalRegs;
+ i < numPhysicalRegs + (numMiscRegs * activeThreads);
+ i++) {
+ regScoreBoard[i] = 1;
+ }
+}
+
+std::string
+Scoreboard::name() const
+{
+ return "cpu.scoreboard";
+}
+
+bool
+Scoreboard::getReg(PhysRegIndex phys_reg)
+{
+ // Always ready if int or fp zero reg.
+ if (phys_reg == zeroRegIdx ||
+ phys_reg == (zeroRegIdx + numPhysicalIntRegs)) {
+ return 1;
+ }
+
+ return regScoreBoard[phys_reg];
+}
+
+void
+Scoreboard::setReg(PhysRegIndex phys_reg)
+{
+ DPRINTF(Scoreboard, "Setting reg %i as ready\n", phys_reg);
+
+ regScoreBoard[phys_reg] = 1;
+}
+
+void
+Scoreboard::unsetReg(PhysRegIndex ready_reg)
+{
+ if (ready_reg == zeroRegIdx ||
+ ready_reg == (zeroRegIdx + numPhysicalIntRegs)) {
+ // Don't do anything if int or fp zero reg.
+ return;
+ }
+
+ regScoreBoard[ready_reg] = 0;
+}
diff --git a/src/cpu/o3/scoreboard.hh b/src/cpu/o3/scoreboard.hh
new file mode 100644
index 000000000..f8e4df3b7
--- /dev/null
+++ b/src/cpu/o3/scoreboard.hh
@@ -0,0 +1,117 @@
+/*
+ * 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: Korey Sewell
+ * Kevin Lim
+ */
+
+#ifndef __CPU_O3_SCOREBOARD_HH__
+#define __CPU_O3_SCOREBOARD_HH__
+
+#include <iostream>
+#include <utility>
+#include <vector>
+#include "arch/alpha/isa_traits.hh"
+#include "base/trace.hh"
+#include "base/traceflags.hh"
+#include "cpu/o3/comm.hh"
+
+/**
+ * Implements a simple scoreboard to track which registers are ready.
+ * This class assumes that the fp registers start, index wise, right after
+ * the integer registers. The misc. registers start, index wise, right after
+ * the fp registers.
+ * @todo: Fix up handling of the zero register in case the decoder does not
+ * automatically make insts that write the zero register into nops.
+ */
+class Scoreboard
+{
+ public:
+ /** Constructs a scoreboard.
+ * @param activeThreads The number of active threads.
+ * @param _numLogicalIntRegs Number of logical integer registers.
+ * @param _numPhysicalIntRegs Number of physical integer registers.
+ * @param _numLogicalFloatRegs Number of logical fp registers.
+ * @param _numPhysicalFloatRegs Number of physical fp registers.
+ * @param _numMiscRegs Number of miscellaneous registers.
+ * @param _zeroRegIdx Index of the zero register.
+ */
+ Scoreboard(unsigned activeThreads,
+ unsigned _numLogicalIntRegs,
+ unsigned _numPhysicalIntRegs,
+ unsigned _numLogicalFloatRegs,
+ unsigned _numPhysicalFloatRegs,
+ unsigned _numMiscRegs,
+ unsigned _zeroRegIdx);
+
+ /** Destructor. */
+ ~Scoreboard() {}
+
+ /** Returns the name of the scoreboard. */
+ std::string name() const;
+
+ /** Checks if the register is ready. */
+ bool getReg(PhysRegIndex ready_reg);
+
+ /** Sets the register as ready. */
+ void setReg(PhysRegIndex phys_reg);
+
+ /** Sets the register as not ready. */
+ void unsetReg(PhysRegIndex ready_reg);
+
+ private:
+ /** Scoreboard of physical integer registers, saying whether or not they
+ * are ready.
+ */
+ std::vector<bool> regScoreBoard;
+
+ /** Number of logical integer registers. */
+ int numLogicalIntRegs;
+
+ /** Number of physical integer registers. */
+ int numPhysicalIntRegs;
+
+ /** Number of logical floating point registers. */
+ int numLogicalFloatRegs;
+
+ /** Number of physical floating point registers. */
+ int numPhysicalFloatRegs;
+
+ /** Number of miscellaneous registers. */
+ int numMiscRegs;
+
+ /** Number of logical integer + float registers. */
+ int numLogicalRegs;
+
+ /** Number of physical integer + float registers. */
+ int numPhysicalRegs;
+
+ /** The logical index of the zero register. */
+ int zeroRegIdx;
+};
+
+#endif
diff --git a/src/cpu/o3/store_set.cc b/src/cpu/o3/store_set.cc
index 11023f4a8..2d28b617f 100644
--- a/src/cpu/o3/store_set.cc
+++ b/src/cpu/o3/store_set.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,49 +24,94 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/intmath.hh"
+#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/o3/store_set.hh"
StoreSet::StoreSet(int _SSIT_size, int _LFST_size)
- : SSIT_size(_SSIT_size), LFST_size(_LFST_size)
+ : SSITSize(_SSIT_size), LFSTSize(_LFST_size)
{
DPRINTF(StoreSet, "StoreSet: Creating store set object.\n");
DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n",
- SSIT_size, LFST_size);
+ SSITSize, LFSTSize);
+
+ if (!isPowerOf2(SSITSize)) {
+ fatal("Invalid SSIT size!\n");
+ }
- SSIT = new SSID[SSIT_size];
+ SSIT.resize(SSITSize);
- validSSIT.resize(SSIT_size);
+ validSSIT.resize(SSITSize);
- for (int i = 0; i < SSIT_size; ++i)
+ for (int i = 0; i < SSITSize; ++i)
validSSIT[i] = false;
- LFST = new InstSeqNum[LFST_size];
+ if (!isPowerOf2(LFSTSize)) {
+ fatal("Invalid LFST size!\n");
+ }
+
+ LFST.resize(LFSTSize);
+
+ validLFST.resize(LFSTSize);
+
+ for (int i = 0; i < LFSTSize; ++i) {
+ validLFST[i] = false;
+ LFST[i] = 0;
+ }
+
+ indexMask = SSITSize - 1;
+
+ offsetBits = 2;
+}
+
+StoreSet::~StoreSet()
+{
+}
- validLFST.resize(LFST_size);
+void
+StoreSet::init(int _SSIT_size, int _LFST_size)
+{
+ SSITSize = _SSIT_size;
+ LFSTSize = _LFST_size;
+
+ DPRINTF(StoreSet, "StoreSet: Creating store set object.\n");
+ DPRINTF(StoreSet, "StoreSet: SSIT size: %i, LFST size: %i.\n",
+ SSITSize, LFSTSize);
- SSCounters = new int[LFST_size];
+ SSIT.resize(SSITSize);
- for (int i = 0; i < LFST_size; ++i)
- {
+ validSSIT.resize(SSITSize);
+
+ for (int i = 0; i < SSITSize; ++i)
+ validSSIT[i] = false;
+
+ LFST.resize(LFSTSize);
+
+ validLFST.resize(LFSTSize);
+
+ for (int i = 0; i < LFSTSize; ++i) {
validLFST[i] = false;
- SSCounters[i] = 0;
+ LFST[i] = 0;
}
- index_mask = SSIT_size - 1;
+ indexMask = SSITSize - 1;
- offset_bits = 2;
+ offsetBits = 2;
}
+
void
StoreSet::violation(Addr store_PC, Addr load_PC)
{
int load_index = calcIndex(load_PC);
int store_index = calcIndex(store_PC);
- assert(load_index < SSIT_size && store_index < SSIT_size);
+ assert(load_index < SSITSize && store_index < SSITSize);
bool valid_load_SSID = validSSIT[load_index];
bool valid_store_SSID = validSSIT[store_index];
@@ -83,10 +128,7 @@ StoreSet::violation(Addr store_PC, Addr load_PC)
SSIT[store_index] = new_set;
- assert(new_set < LFST_size);
-
- SSCounters[new_set]++;
-
+ assert(new_set < LFSTSize);
DPRINTF(StoreSet, "StoreSet: Neither load nor store had a valid "
"storeset, creating a new one: %i for load %#x, store %#x\n",
@@ -98,9 +140,7 @@ StoreSet::violation(Addr store_PC, Addr load_PC)
SSIT[store_index] = load_SSID;
- assert(load_SSID < LFST_size);
-
- SSCounters[load_SSID]++;
+ assert(load_SSID < LFSTSize);
DPRINTF(StoreSet, "StoreSet: Load had a valid store set. Adding "
"store to that set: %i for load %#x, store %#x\n",
@@ -112,9 +152,6 @@ StoreSet::violation(Addr store_PC, Addr load_PC)
SSIT[load_index] = store_SSID;
- // Because we are having a load point to an already existing set,
- // the size of the store set is not incremented.
-
DPRINTF(StoreSet, "StoreSet: Store had a valid store set: %i for "
"load %#x, store %#x\n",
store_SSID, load_PC, store_PC);
@@ -122,29 +159,19 @@ StoreSet::violation(Addr store_PC, Addr load_PC)
SSID load_SSID = SSIT[load_index];
SSID store_SSID = SSIT[store_index];
- assert(load_SSID < LFST_size && store_SSID < LFST_size);
+ assert(load_SSID < LFSTSize && store_SSID < LFSTSize);
- int load_SS_size = SSCounters[load_SSID];
- int store_SS_size = SSCounters[store_SSID];
-
- // If the load has the bigger store set, then assign the store
- // to the same store set as the load. Otherwise vice-versa.
- if (load_SS_size > store_SS_size) {
+ // The store set with the lower number wins
+ if (store_SSID > load_SSID) {
SSIT[store_index] = load_SSID;
- SSCounters[load_SSID]++;
- SSCounters[store_SSID]--;
-
- DPRINTF(StoreSet, "StoreSet: Load had bigger store set: %i; "
+ DPRINTF(StoreSet, "StoreSet: Load had smaller store set: %i; "
"for load %#x, store %#x\n",
load_SSID, load_PC, store_PC);
} else {
SSIT[load_index] = store_SSID;
- SSCounters[store_SSID]++;
- SSCounters[load_SSID]--;
-
- DPRINTF(StoreSet, "StoreSet: Store had bigger store set: %i; "
+ DPRINTF(StoreSet, "StoreSet: Store had smaller store set: %i; "
"for load %#x, store %#x\n",
store_SSID, load_PC, store_PC);
}
@@ -159,13 +186,14 @@ StoreSet::insertLoad(Addr load_PC, InstSeqNum load_seq_num)
}
void
-StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num)
+StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num,
+ unsigned tid)
{
int index = calcIndex(store_PC);
int store_SSID;
- assert(index < SSIT_size);
+ assert(index < SSITSize);
if (!validSSIT[index]) {
// Do nothing if there's no valid entry.
@@ -173,13 +201,15 @@ StoreSet::insertStore(Addr store_PC, InstSeqNum store_seq_num)
} else {
store_SSID = SSIT[index];
- assert(store_SSID < LFST_size);
+ assert(store_SSID < LFSTSize);
// Update the last store that was fetched with the current one.
LFST[store_SSID] = store_seq_num;
validLFST[store_SSID] = 1;
+ storeList[store_seq_num] = store_SSID;
+
DPRINTF(StoreSet, "Store %#x updated the LFST, SSID: %i\n",
store_PC, store_SSID);
}
@@ -192,7 +222,7 @@ StoreSet::checkInst(Addr PC)
int inst_SSID;
- assert(index < SSIT_size);
+ assert(index < SSITSize);
if (!validSSIT[index]) {
DPRINTF(StoreSet, "Inst %#x with index %i had no SSID\n",
@@ -203,7 +233,7 @@ StoreSet::checkInst(Addr PC)
} else {
inst_SSID = SSIT[index];
- assert(inst_SSID < LFST_size);
+ assert(inst_SSID < LFSTSize);
if (!validLFST[inst_SSID]) {
@@ -232,7 +262,13 @@ StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store)
int store_SSID;
- assert(index < SSIT_size);
+ assert(index < SSITSize);
+
+ SeqNumMapIt store_list_it = storeList.find(issued_seq_num);
+
+ if (store_list_it != storeList.end()) {
+ storeList.erase(store_list_it);
+ }
// Make sure the SSIT still has a valid entry for the issued store.
if (!validSSIT[index]) {
@@ -241,7 +277,7 @@ StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store)
store_SSID = SSIT[index];
- assert(store_SSID < LFST_size);
+ assert(store_SSID < LFSTSize);
// If the last fetched store in the store set refers to the store that
// was just issued, then invalidate the entry.
@@ -252,18 +288,31 @@ StoreSet::issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store)
}
void
-StoreSet::squash(InstSeqNum squashed_num)
+StoreSet::squash(InstSeqNum squashed_num, unsigned tid)
{
- // Not really sure how to do this well.
- // Generally this is small enough that it should be okay; short circuit
- // evaluation should take care of invalid entries.
-
DPRINTF(StoreSet, "StoreSet: Squashing until inum %i\n",
squashed_num);
- for (int i = 0; i < LFST_size; ++i) {
- if (validLFST[i] && LFST[i] < squashed_num) {
- validLFST[i] = false;
+ int idx;
+ SeqNumMapIt store_list_it = storeList.begin();
+
+ //@todo:Fix to only delete from correct thread
+ while (!storeList.empty()) {
+ idx = (*store_list_it).second;
+
+ if ((*store_list_it).first <= squashed_num) {
+ break;
+ }
+
+ bool younger = LFST[idx] > squashed_num;
+
+ if (validLFST[idx] && younger) {
+ DPRINTF(StoreSet, "Squashed [sn:%lli]\n", LFST[idx]);
+ validLFST[idx] = false;
+
+ storeList.erase(store_list_it++);
+ } else if (!validLFST[idx] && younger) {
+ storeList.erase(store_list_it++);
}
}
}
@@ -271,12 +320,29 @@ StoreSet::squash(InstSeqNum squashed_num)
void
StoreSet::clear()
{
- for (int i = 0; i < SSIT_size; ++i) {
+ for (int i = 0; i < SSITSize; ++i) {
validSSIT[i] = false;
}
- for (int i = 0; i < LFST_size; ++i) {
+ for (int i = 0; i < LFSTSize; ++i) {
validLFST[i] = false;
}
+
+ storeList.clear();
}
+void
+StoreSet::dump()
+{
+ cprintf("storeList.size(): %i\n", storeList.size());
+ SeqNumMapIt store_list_it = storeList.begin();
+
+ int num = 0;
+
+ while (store_list_it != storeList.end()) {
+ cprintf("%i: [sn:%lli] SSID:%i\n",
+ num, (*store_list_it).first, (*store_list_it).second);
+ num++;
+ store_list_it++;
+ }
+}
diff --git a/src/cpu/o3/store_set.hh b/src/cpu/o3/store_set.hh
index 5a885d838..f5a44a1ac 100644
--- a/src/cpu/o3/store_set.hh
+++ b/src/cpu/o3/store_set.hh
@@ -24,63 +24,124 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_STORE_SET_HH__
-#define __CPU_O3_CPU_STORE_SET_HH__
+#ifndef __CPU_O3_STORE_SET_HH__
+#define __CPU_O3_STORE_SET_HH__
+#include <list>
+#include <map>
+#include <utility>
#include <vector>
#include "arch/isa_traits.hh"
#include "cpu/inst_seq.hh"
+struct ltseqnum {
+ bool operator()(const InstSeqNum &lhs, const InstSeqNum &rhs) const
+ {
+ return lhs > rhs;
+ }
+};
+
+/**
+ * Implements a store set predictor for determining if memory
+ * instructions are dependent upon each other. See paper "Memory
+ * Dependence Prediction using Store Sets" by Chrysos and Emer. SSID
+ * stands for Store Set ID, SSIT stands for Store Set ID Table, and
+ * LFST is Last Fetched Store Table.
+ */
class StoreSet
{
public:
typedef unsigned SSID;
public:
+ /** Default constructor. init() must be called prior to use. */
+ StoreSet() { };
+
+ /** Creates store set predictor with given table sizes. */
StoreSet(int SSIT_size, int LFST_size);
+ /** Default destructor. */
+ ~StoreSet();
+
+ /** Initializes the store set predictor with the given table sizes. */
+ void init(int SSIT_size, int LFST_size);
+
+ /** Records a memory ordering violation between the younger load
+ * and the older store. */
void violation(Addr store_PC, Addr load_PC);
+ /** Inserts a load into the store set predictor. This does nothing but
+ * is included in case other predictors require a similar function.
+ */
void insertLoad(Addr load_PC, InstSeqNum load_seq_num);
- void insertStore(Addr store_PC, InstSeqNum store_seq_num);
+ /** Inserts a store into the store set predictor. Updates the
+ * LFST if the store has a valid SSID. */
+ void insertStore(Addr store_PC, InstSeqNum store_seq_num,
+ unsigned tid);
+ /** Checks if the instruction with the given PC is dependent upon
+ * any store. @return Returns the sequence number of the store
+ * instruction this PC is dependent upon. Returns 0 if none.
+ */
InstSeqNum checkInst(Addr PC);
+ /** Records this PC/sequence number as issued. */
void issued(Addr issued_PC, InstSeqNum issued_seq_num, bool is_store);
- void squash(InstSeqNum squashed_num);
+ /** Squashes for a specific thread until the given sequence number. */
+ void squash(InstSeqNum squashed_num, unsigned tid);
+ /** Resets all tables. */
void clear();
+ /** Debug function to dump the contents of the store list. */
+ void dump();
+
private:
+ /** Calculates the index into the SSIT based on the PC. */
inline int calcIndex(Addr PC)
- { return (PC >> offset_bits) & index_mask; }
+ { return (PC >> offsetBits) & indexMask; }
+ /** Calculates a Store Set ID based on the PC. */
inline SSID calcSSID(Addr PC)
- { return ((PC ^ (PC >> 10)) % LFST_size); }
+ { return ((PC ^ (PC >> 10)) % LFSTSize); }
- SSID *SSIT;
+ /** The Store Set ID Table. */
+ std::vector<SSID> SSIT;
+ /** Bit vector to tell if the SSIT has a valid entry. */
std::vector<bool> validSSIT;
- InstSeqNum *LFST;
+ /** Last Fetched Store Table. */
+ std::vector<InstSeqNum> LFST;
+ /** Bit vector to tell if the LFST has a valid entry. */
std::vector<bool> validLFST;
- int *SSCounters;
+ /** Map of stores that have been inserted into the store set, but
+ * not yet issued or squashed.
+ */
+ std::map<InstSeqNum, int, ltseqnum> storeList;
+
+ typedef std::map<InstSeqNum, int, ltseqnum>::iterator SeqNumMapIt;
- int SSIT_size;
+ /** Store Set ID Table size, in entries. */
+ int SSITSize;
- int LFST_size;
+ /** Last Fetched Store Table size, in entries. */
+ int LFSTSize;
- int index_mask;
+ /** Mask to obtain the index. */
+ int indexMask;
// HACK: Hardcoded for now.
- int offset_bits;
+ int offsetBits;
};
-#endif // __CPU_O3_CPU_STORE_SET_HH__
+#endif // __CPU_O3_STORE_SET_HH__
diff --git a/src/cpu/o3/thread_context.hh b/src/cpu/o3/thread_context.hh
new file mode 100755
index 000000000..d097ee63e
--- /dev/null
+++ b/src/cpu/o3/thread_context.hh
@@ -0,0 +1,250 @@
+/*
+ * 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_O3_THREAD_CONTEXT_HH__
+#define __CPU_O3_THREAD_CONTEXT_HH__
+
+#include "cpu/o3/isa_specific.hh"
+
+class EndQuiesceEvent;
+namespace Kernel {
+ class Statistics;
+};
+
+class TranslatingPort;
+
+/**
+ * Derived ThreadContext class for use with the O3CPU. 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 O3CPU 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).
+ */
+template <class Impl>
+class O3ThreadContext : public ThreadContext
+{
+ public:
+ typedef typename Impl::O3CPU O3CPU;
+
+ /** Pointer to the CPU. */
+ O3CPU *cpu;
+
+ /** Pointer to the thread state that this TC corrseponds to. */
+ O3ThreadState<Impl> *thread;
+
+ /** 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(); }
+
+#if FULL_SYSTEM
+ /** Returns a pointer to the system. */
+ virtual System *getSystemPtr() { return cpu->system; }
+
+ /** Returns a pointer to physical memory. */
+ virtual PhysicalMemory *getPhysMemPtr() { return cpu->physmem; }
+
+ /** Returns a pointer to this thread's kernel statistics. */
+ virtual Kernel::Statistics *getKernelStats()
+ { return thread->kernelStats; }
+
+ virtual FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
+
+ virtual VirtualPort *getVirtPort(ThreadContext *src_tc = NULL);
+
+ void delVirtPort(VirtualPort *vp);
+#else
+ virtual TranslatingPort *getMemPort() { return thread->getMemPort(); }
+
+ /** Returns a pointer to this thread's process. */
+ virtual Process *getProcessPtr() { return thread->getProcessPtr(); }
+#endif
+ /** 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();
+
+ /** Set the status to Unallocated. */
+ virtual void deallocate();
+
+ /** Set the status to Halted. */
+ virtual void halt();
+
+#if FULL_SYSTEM
+ /** Dumps the function profiling information.
+ * @todo: Implement.
+ */
+ virtual void dumpFuncProfile();
+#endif
+ /** 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);
+
+#if FULL_SYSTEM
+ /** Reads the last tick that this thread was activated on. */
+ virtual Tick readLastActivate();
+ /** Reads the last tick that this thread was suspended on. */
+ virtual Tick readLastSuspend();
+
+ /** Clears the function profiling information. */
+ virtual void profileClear();
+ /** 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.
+ */
+ virtual TheISA::MachInst getInst();
+
+ /** Copies the architectural registers from another TC into this TC. */
+ virtual void copyArchRegs(ThreadContext *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);
+
+ /** 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);
+
+ /** 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);
+
+ /** Reads a miscellaneous register. */
+ virtual MiscReg readMiscReg(int misc_reg)
+ { return cpu->readMiscReg(misc_reg, thread->readTid()); }
+
+ /** Reads a misc. register, including any side-effects the
+ * read might have as defined by the architecture. */
+ virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ { return cpu->readMiscRegWithEffect(misc_reg, fault, thread->readTid()); }
+
+ /** Sets a misc. register. */
+ virtual Fault setMiscReg(int misc_reg, const MiscReg &val);
+
+ /** Sets a misc. register, including any side-effects the
+ * write might have as defined by the architecture. */
+ virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val);
+
+ /** 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; }
+
+#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()); }
+
+ /** Reads the funcExeInst counter. */
+ virtual Counter readFuncExeInst() { return thread->funcExeInst; }
+#endif
+};
+
+#endif
diff --git a/src/cpu/o3/thread_context_impl.hh b/src/cpu/o3/thread_context_impl.hh
new file mode 100755
index 000000000..cfb71f623
--- /dev/null
+++ b/src/cpu/o3/thread_context_impl.hh
@@ -0,0 +1,489 @@
+/*
+ * 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
+ */
+
+#include "cpu/o3/thread_context.hh"
+#include "cpu/quiesce_event.hh"
+
+using namespace TheISA;
+
+#if FULL_SYSTEM
+template <class Impl>
+VirtualPort *
+O3ThreadContext<Impl>::getVirtPort(ThreadContext *src_tc)
+{
+ if (!src_tc)
+ return thread->getVirtPort();
+
+ VirtualPort *vp;
+ Port *mem_port;
+
+ vp = new VirtualPort("tc-vport", src_tc);
+ mem_port = cpu->system->physmem->getPort("functional");
+ mem_port->setPeer(vp);
+ vp->setPeer(mem_port);
+ return vp;
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::dumpFuncProfile()
+{
+ // Currently not supported
+}
+#endif
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
+{
+ // some things should already be set up
+#if FULL_SYSTEM
+ assert(getSystemPtr() == old_context->getSystemPtr());
+#else
+ assert(getProcessPtr() == old_context->getProcessPtr());
+#endif
+
+ // copy over functional state
+ setStatus(old_context->status());
+ copyArchRegs(old_context);
+ setCpuId(old_context->readCpuId());
+
+#if !FULL_SYSTEM
+ thread->funcExeInst = old_context->readFuncExeInst();
+#else
+ EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
+ if (other_quiesce) {
+ // Point the quiesce event's TC at this TC so that it wakes up
+ // the proper CPU.
+ other_quiesce->tc = this;
+ }
+ if (thread->quiesceEvent) {
+ thread->quiesceEvent->tc = this;
+ }
+
+ // Transfer kernel stats from one CPU to the other.
+ thread->kernelStats = old_context->getKernelStats();
+// storeCondFailures = 0;
+ cpu->lockFlag = false;
+#endif
+
+ old_context->setStatus(ThreadContext::Unallocated);
+
+ thread->inSyscall = false;
+ thread->trapPending = false;
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+O3ThreadContext<Impl>::delVirtPort(VirtualPort *vp)
+{
+ delete vp->getPeer();
+ delete vp;
+}
+#endif
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::activate(int delay)
+{
+ DPRINTF(O3CPU, "Calling activate on AlphaTC\n");
+
+ if (thread->status() == ThreadContext::Active)
+ return;
+
+#if FULL_SYSTEM
+ thread->lastActivate = curTick;
+#endif
+
+ if (thread->status() == ThreadContext::Unallocated) {
+ cpu->activateWhenReady(thread->readTid());
+ return;
+ }
+
+ thread->setStatus(ThreadContext::Active);
+
+ // status() == Suspended
+ cpu->activateContext(thread->readTid(), delay);
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::suspend()
+{
+ DPRINTF(O3CPU, "Calling suspend on AlphaTC\n");
+
+ if (thread->status() == ThreadContext::Suspended)
+ return;
+
+#if FULL_SYSTEM
+ thread->lastActivate = curTick;
+ thread->lastSuspend = curTick;
+#endif
+/*
+#if FULL_SYSTEM
+ // Don't change the status from active if there are pending interrupts
+ if (cpu->check_interrupts()) {
+ assert(status() == ThreadContext::Active);
+ return;
+ }
+#endif
+*/
+ thread->setStatus(ThreadContext::Suspended);
+ cpu->suspendContext(thread->readTid());
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::deallocate()
+{
+ DPRINTF(O3CPU, "Calling deallocate on AlphaTC\n");
+
+ if (thread->status() == ThreadContext::Unallocated)
+ return;
+
+ thread->setStatus(ThreadContext::Unallocated);
+ cpu->deallocateContext(thread->readTid());
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::halt()
+{
+ DPRINTF(O3CPU, "Calling halt on AlphaTC\n");
+
+ if (thread->status() == ThreadContext::Halted)
+ return;
+
+ thread->setStatus(ThreadContext::Halted);
+ cpu->haltContext(thread->readTid());
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::regStats(const std::string &name)
+{
+#if FULL_SYSTEM
+ thread->kernelStats = new Kernel::Statistics(cpu->system);
+ thread->kernelStats->regStats(name + ".kern");
+#endif
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::serialize(std::ostream &os)
+{
+#if FULL_SYSTEM
+ if (thread->kernelStats)
+ thread->kernelStats->serialize(os);
+#endif
+
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::unserialize(Checkpoint *cp, const std::string &section)
+{
+#if FULL_SYSTEM
+ if (thread->kernelStats)
+ thread->kernelStats->unserialize(cp, section);
+#endif
+
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+Tick
+O3ThreadContext<Impl>::readLastActivate()
+{
+ return thread->lastActivate;
+}
+
+template <class Impl>
+Tick
+O3ThreadContext<Impl>::readLastSuspend()
+{
+ return thread->lastSuspend;
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::profileClear()
+{}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::profileSample()
+{}
+#endif
+
+template <class Impl>
+TheISA::MachInst
+O3ThreadContext<Impl>:: getInst()
+{
+ return thread->getInst();
+}
+
+template <class Impl>
+void
+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();
+ PhysRegIndex renamed_reg;
+
+ // First loop through the integer registers.
+ for (int i = 0; i < TheISA::NumIntRegs; ++i) {
+ renamed_reg = cpu->renameMap[tid].lookup(i);
+
+ DPRINTF(O3CPU, "Copying over register %i, had data %lli, "
+ "now has data %lli.\n",
+ renamed_reg, cpu->readIntReg(renamed_reg),
+ tc->readIntReg(i));
+
+ cpu->setIntReg(renamed_reg, tc->readIntReg(i));
+ }
+
+ // Then loop through the floating point registers.
+ for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
+ renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
+ cpu->setFloatRegBits(renamed_reg,
+ tc->readFloatRegBits(i));
+ }
+
+ // Copy the misc regs.
+ copyMiscRegs(tc, this);
+
+ // Then finally set the PC and the next PC.
+ cpu->setPC(tc->readPC(), tid);
+ cpu->setNextPC(tc->readNextPC(), tid);
+#if !FULL_SYSTEM
+ this->thread->funcExeInst = tc->readFuncExeInst();
+#endif
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::clearArchRegs()
+{}
+
+template <class Impl>
+uint64_t
+O3ThreadContext<Impl>::readIntReg(int reg_idx)
+{
+ return cpu->readArchIntReg(reg_idx, thread->readTid());
+}
+
+template <class Impl>
+FloatReg
+O3ThreadContext<Impl>::readFloatReg(int reg_idx, int width)
+{
+ switch(width) {
+ case 32:
+ return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+ case 64:
+ return cpu->readArchFloatRegDouble(reg_idx, thread->readTid());
+ default:
+ panic("Unsupported width!");
+ return 0;
+ }
+}
+
+template <class Impl>
+FloatReg
+O3ThreadContext<Impl>::readFloatReg(int reg_idx)
+{
+ return cpu->readArchFloatRegSingle(reg_idx, thread->readTid());
+}
+
+template <class Impl>
+FloatRegBits
+O3ThreadContext<Impl>::readFloatRegBits(int reg_idx, int width)
+{
+ DPRINTF(Fault, "Reading floatint register through the TC!\n");
+ return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+}
+
+template <class Impl>
+FloatRegBits
+O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
+{
+ return cpu->readArchFloatRegInt(reg_idx, thread->readTid());
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
+{
+ cpu->setArchIntReg(reg_idx, val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ switch(width) {
+ case 32:
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+ break;
+ case 64:
+ cpu->setArchFloatRegDouble(reg_idx, val, thread->readTid());
+ break;
+ }
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
+{
+ cpu->setArchFloatRegSingle(reg_idx, val, thread->readTid());
+
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val,
+ int width)
+{
+ DPRINTF(Fault, "Setting floatint register through the TC!\n");
+ cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ cpu->setArchFloatRegInt(reg_idx, val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setPC(uint64_t val)
+{
+ cpu->setPC(val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+void
+O3ThreadContext<Impl>::setNextPC(uint64_t val)
+{
+ cpu->setNextPC(val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+}
+
+template <class Impl>
+Fault
+O3ThreadContext<Impl>::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ Fault ret_fault = cpu->setMiscReg(misc_reg, val, thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+
+ return ret_fault;
+}
+
+template <class Impl>
+Fault
+O3ThreadContext<Impl>::setMiscRegWithEffect(int misc_reg,
+ const MiscReg &val)
+{
+ Fault ret_fault = cpu->setMiscRegWithEffect(misc_reg, val,
+ thread->readTid());
+
+ // Squash if we're not already in a state update mode.
+ if (!thread->trapPending && !thread->inSyscall) {
+ cpu->squashFromTC(thread->readTid());
+ }
+
+ return ret_fault;
+}
+
+#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
new file mode 100644
index 000000000..1c8105204
--- /dev/null
+++ b/src/cpu/o3/thread_state.hh
@@ -0,0 +1,102 @@
+/*
+ * 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_O3_THREAD_STATE_HH__
+#define __CPU_O3_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 Process;
+
+#if FULL_SYSTEM
+class EndQuiesceEvent;
+class FunctionProfile;
+class ProfileNode;
+#else
+class FunctionalMemory;
+class Process;
+#endif
+
+/**
+ * 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.
+ */
+template <class Impl>
+struct O3ThreadState : public ThreadState {
+ typedef ThreadContext::Status Status;
+ typedef typename Impl::O3CPU O3CPU;
+
+ private:
+ /** Pointer to the CPU. */
+ O3CPU *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;
+
+#if FULL_SYSTEM
+ O3ThreadState(O3CPU *_cpu, int _thread_num)
+ : ThreadState(-1, _thread_num),
+ inSyscall(0), trapPending(0)
+ { }
+#else
+ O3ThreadState(O3CPU *_cpu, int _thread_num, Process *_process, int _asid,
+ MemObject *mem)
+ : ThreadState(-1, _thread_num, _process, _asid, mem),
+ cpu(_cpu), inSyscall(0), trapPending(0)
+ { }
+#endif
+
+ /** Pointer to the ThreadContext of this thread. */
+ ThreadContext *tc;
+
+ /** Returns a pointer to the TC of this thread. */
+ ThreadContext *getTC() { return tc; }
+
+#if !FULL_SYSTEM
+ /** Handles the syscall. */
+ void syscall(int64_t callnum) { process->syscall(callnum, tc); }
+#endif
+};
+
+#endif // __CPU_O3_THREAD_STATE_HH__
diff --git a/src/cpu/o3/tournament_pred.cc b/src/cpu/o3/tournament_pred.cc
index 3fb580510..7cf78dcb1 100644
--- a/src/cpu/o3/tournament_pred.cc
+++ b/src/cpu/o3/tournament_pred.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,41 +24,50 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/intmath.hh"
#include "cpu/o3/tournament_pred.hh"
-TournamentBP::TournamentBP(unsigned _local_predictor_size,
- unsigned _local_ctr_bits,
- unsigned _local_history_table_size,
- unsigned _local_history_bits,
- unsigned _global_predictor_size,
- unsigned _global_ctr_bits,
- unsigned _global_history_bits,
- unsigned _choice_predictor_size,
- unsigned _choice_ctr_bits,
+TournamentBP::TournamentBP(unsigned _localPredictorSize,
+ unsigned _localCtrBits,
+ unsigned _localHistoryTableSize,
+ unsigned _localHistoryBits,
+ unsigned _globalPredictorSize,
+ unsigned _globalCtrBits,
+ unsigned _globalHistoryBits,
+ unsigned _choicePredictorSize,
+ unsigned _choiceCtrBits,
unsigned _instShiftAmt)
- : localPredictorSize(_local_predictor_size),
- localCtrBits(_local_ctr_bits),
- localHistoryTableSize(_local_history_table_size),
- localHistoryBits(_local_history_bits),
- globalPredictorSize(_global_predictor_size),
- globalCtrBits(_global_ctr_bits),
- globalHistoryBits(_global_history_bits),
- choicePredictorSize(_global_predictor_size),
- choiceCtrBits(_choice_ctr_bits),
+ : localPredictorSize(_localPredictorSize),
+ localCtrBits(_localCtrBits),
+ localHistoryTableSize(_localHistoryTableSize),
+ localHistoryBits(_localHistoryBits),
+ globalPredictorSize(_globalPredictorSize),
+ globalCtrBits(_globalCtrBits),
+ globalHistoryBits(_globalHistoryBits),
+ choicePredictorSize(_globalPredictorSize),
+ choiceCtrBits(_choiceCtrBits),
instShiftAmt(_instShiftAmt)
{
- //Should do checks here to make sure sizes are correct (powers of 2)
+ if (!isPowerOf2(localPredictorSize)) {
+ fatal("Invalid local predictor size!\n");
+ }
//Setup the array of counters for the local predictor
- localCtrs = new SatCounter[localPredictorSize];
+ localCtrs.resize(localPredictorSize);
for (int i = 0; i < localPredictorSize; ++i)
localCtrs[i].setBits(localCtrBits);
+ if (!isPowerOf2(localHistoryTableSize)) {
+ fatal("Invalid local history table size!\n");
+ }
+
//Setup the history table for the local table
- localHistoryTable = new unsigned[localHistoryTableSize];
+ localHistoryTable.resize(localHistoryTableSize);
for (int i = 0; i < localHistoryTableSize; ++i)
localHistoryTable[i] = 0;
@@ -66,8 +75,12 @@ TournamentBP::TournamentBP(unsigned _local_predictor_size,
// Setup the local history mask
localHistoryMask = (1 << localHistoryBits) - 1;
+ if (!isPowerOf2(globalPredictorSize)) {
+ fatal("Invalid global predictor size!\n");
+ }
+
//Setup the array of counters for the global predictor
- globalCtrs = new SatCounter[globalPredictorSize];
+ globalCtrs.resize(globalPredictorSize);
for (int i = 0; i < globalPredictorSize; ++i)
globalCtrs[i].setBits(globalCtrBits);
@@ -77,12 +90,17 @@ TournamentBP::TournamentBP(unsigned _local_predictor_size,
// Setup the global history mask
globalHistoryMask = (1 << globalHistoryBits) - 1;
+ if (!isPowerOf2(choicePredictorSize)) {
+ fatal("Invalid choice predictor size!\n");
+ }
+
//Setup the array of counters for the choice predictor
- choiceCtrs = new SatCounter[choicePredictorSize];
+ choiceCtrs.resize(choicePredictorSize);
for (int i = 0; i < choicePredictorSize; ++i)
choiceCtrs[i].setBits(choiceCtrBits);
+ // @todo: Allow for different thresholds between the predictors.
threshold = (1 << (localCtrBits - 1)) - 1;
threshold = threshold / 2;
}
@@ -91,166 +109,185 @@ inline
unsigned
TournamentBP::calcLocHistIdx(Addr &branch_addr)
{
+ // Get low order bits after removing instruction offset.
return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
}
inline
void
-TournamentBP::updateHistoriesTaken(unsigned local_history_idx)
+TournamentBP::updateGlobalHistTaken()
{
globalHistory = (globalHistory << 1) | 1;
globalHistory = globalHistory & globalHistoryMask;
-
- localHistoryTable[local_history_idx] =
- (localHistoryTable[local_history_idx] << 1) | 1;
}
inline
void
-TournamentBP::updateHistoriesNotTaken(unsigned local_history_idx)
+TournamentBP::updateGlobalHistNotTaken()
{
globalHistory = (globalHistory << 1);
globalHistory = globalHistory & globalHistoryMask;
+}
+inline
+void
+TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
+{
+ localHistoryTable[local_history_idx] =
+ (localHistoryTable[local_history_idx] << 1) | 1;
+}
+
+inline
+void
+TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
+{
localHistoryTable[local_history_idx] =
(localHistoryTable[local_history_idx] << 1);
}
bool
-TournamentBP::lookup(Addr &branch_addr)
+TournamentBP::lookup(Addr &branch_addr, void * &bp_history)
{
- uint8_t local_prediction;
+ bool local_prediction;
unsigned local_history_idx;
unsigned local_predictor_idx;
- uint8_t global_prediction;
- uint8_t choice_prediction;
+ bool global_prediction;
+ bool choice_prediction;
//Lookup in the local predictor to get its branch prediction
local_history_idx = calcLocHistIdx(branch_addr);
local_predictor_idx = localHistoryTable[local_history_idx]
& localHistoryMask;
- local_prediction = localCtrs[local_predictor_idx].read();
+ local_prediction = localCtrs[local_predictor_idx].read() > threshold;
//Lookup in the global predictor to get its branch prediction
- global_prediction = globalCtrs[globalHistory].read();
+ global_prediction = globalCtrs[globalHistory].read() > threshold;
//Lookup in the choice predictor to see which one to use
- choice_prediction = choiceCtrs[globalHistory].read();
-
- //@todo Put a threshold value in for the three predictors that can
- // be set through the constructor (so this isn't hard coded).
- //Also should put some of this code into functions.
- if (choice_prediction > threshold) {
- if (global_prediction > threshold) {
- updateHistoriesTaken(local_history_idx);
-
- assert(globalHistory < globalPredictorSize &&
- local_history_idx < localPredictorSize);
-
- globalCtrs[globalHistory].increment();
- localCtrs[local_history_idx].increment();
-
+ choice_prediction = choiceCtrs[globalHistory].read() > threshold;
+
+ // Create BPHistory and pass it back to be recorded.
+ BPHistory *history = new BPHistory;
+ history->globalHistory = globalHistory;
+ history->localPredTaken = local_prediction;
+ history->globalPredTaken = global_prediction;
+ history->globalUsed = choice_prediction;
+ bp_history = (void *)history;
+
+ assert(globalHistory < globalPredictorSize &&
+ local_history_idx < localPredictorSize);
+
+ // Commented code is for doing speculative update of counters and
+ // all histories.
+ if (choice_prediction) {
+ if (global_prediction) {
+// updateHistoriesTaken(local_history_idx);
+// globalCtrs[globalHistory].increment();
+// localCtrs[local_history_idx].increment();
+ updateGlobalHistTaken();
return true;
} else {
- updateHistoriesNotTaken(local_history_idx);
-
- assert(globalHistory < globalPredictorSize &&
- local_history_idx < localPredictorSize);
-
- globalCtrs[globalHistory].decrement();
- localCtrs[local_history_idx].decrement();
-
+// updateHistoriesNotTaken(local_history_idx);
+// globalCtrs[globalHistory].decrement();
+// localCtrs[local_history_idx].decrement();
+ updateGlobalHistNotTaken();
return false;
}
} else {
- if (local_prediction > threshold) {
- updateHistoriesTaken(local_history_idx);
-
- assert(globalHistory < globalPredictorSize &&
- local_history_idx < localPredictorSize);
-
- globalCtrs[globalHistory].increment();
- localCtrs[local_history_idx].increment();
-
+ if (local_prediction) {
+// updateHistoriesTaken(local_history_idx);
+// globalCtrs[globalHistory].increment();
+// localCtrs[local_history_idx].increment();
+ updateGlobalHistTaken();
return true;
} else {
- updateHistoriesNotTaken(local_history_idx);
-
- assert(globalHistory < globalPredictorSize &&
- local_history_idx < localPredictorSize);
-
- globalCtrs[globalHistory].decrement();
- localCtrs[local_history_idx].decrement();
-
+// updateHistoriesNotTaken(local_history_idx);
+// globalCtrs[globalHistory].decrement();
+// localCtrs[local_history_idx].decrement();
+ updateGlobalHistNotTaken();
return false;
}
}
}
-// Update the branch predictor if it predicted a branch wrong.
void
-TournamentBP::update(Addr &branch_addr, unsigned correct_gh, bool taken)
+TournamentBP::uncondBr(void * &bp_history)
{
+ // Create BPHistory and pass it back to be recorded.
+ BPHistory *history = new BPHistory;
+ history->globalHistory = globalHistory;
+ history->localPredTaken = true;
+ history->globalPredTaken = true;
+ bp_history = static_cast<void *>(history);
+
+ updateGlobalHistTaken();
+}
- uint8_t local_prediction;
+void
+TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history)
+{
unsigned local_history_idx;
unsigned local_predictor_idx;
- bool local_pred_taken;
+ unsigned local_predictor_hist;
- uint8_t global_prediction;
- bool global_pred_taken;
-
- // Load the correct global history into the register.
- globalHistory = correct_gh;
-
- // Get the local predictor's current prediction, remove the incorrect
- // update, and update the local predictor
+ // Get the local predictor's current prediction
local_history_idx = calcLocHistIdx(branch_addr);
- local_predictor_idx = localHistoryTable[local_history_idx];
- local_predictor_idx = (local_predictor_idx >> 1) & localHistoryMask;
-
- local_prediction = localCtrs[local_predictor_idx].read();
- local_pred_taken = local_prediction > threshold;
-
- //Get the global predictor's current prediction, and update the
- //global predictor
- global_prediction = globalCtrs[globalHistory].read();
- global_pred_taken = global_prediction > threshold;
-
- //Update the choice predictor to tell it which one was correct
- if (local_pred_taken != global_pred_taken) {
- //If the local prediction matches the actual outcome, decerement
- //the counter. Otherwise increment the counter.
- if (local_pred_taken == taken) {
- choiceCtrs[globalHistory].decrement();
- } else {
- choiceCtrs[globalHistory].increment();
+ local_predictor_hist = localHistoryTable[local_history_idx];
+ local_predictor_idx = local_predictor_hist & localHistoryMask;
+
+ // Update the choice predictor to tell it which one was correct if
+ // there was a prediction.
+ if (bp_history) {
+ BPHistory *history = static_cast<BPHistory *>(bp_history);
+ if (history->localPredTaken != history->globalPredTaken) {
+ // If the local prediction matches the actual outcome,
+ // decerement the counter. Otherwise increment the
+ // counter.
+ if (history->localPredTaken == taken) {
+ choiceCtrs[globalHistory].decrement();
+ } else if (history->globalPredTaken == taken){
+ choiceCtrs[globalHistory].increment();
+ }
}
+
+ // We're done with this history, now delete it.
+ delete history;
}
- if (taken) {
- assert(globalHistory < globalPredictorSize &&
- local_predictor_idx < localPredictorSize);
+ assert(globalHistory < globalPredictorSize &&
+ local_predictor_idx < localPredictorSize);
+ // Update the counters and local history with the proper
+ // resolution of the branch. Global history is updated
+ // speculatively and restored upon squash() calls, so it does not
+ // need to be updated.
+ if (taken) {
localCtrs[local_predictor_idx].increment();
globalCtrs[globalHistory].increment();
- globalHistory = (globalHistory << 1) | 1;
- globalHistory = globalHistory & globalHistoryMask;
+ updateLocalHistTaken(local_history_idx);
+ } else {
+ localCtrs[local_predictor_idx].decrement();
+ globalCtrs[globalHistory].decrement();
- localHistoryTable[local_history_idx] |= 1;
+ updateLocalHistNotTaken(local_history_idx);
}
- else {
- assert(globalHistory < globalPredictorSize &&
- local_predictor_idx < localPredictorSize);
+}
- localCtrs[local_predictor_idx].decrement();
- globalCtrs[globalHistory].decrement();
+void
+TournamentBP::squash(void *bp_history)
+{
+ BPHistory *history = static_cast<BPHistory *>(bp_history);
- globalHistory = (globalHistory << 1);
- globalHistory = globalHistory & globalHistoryMask;
+ // Restore global history to state prior to this branch.
+ globalHistory = history->globalHistory;
- localHistoryTable[local_history_idx] &= ~1;
- }
+ // Delete this BPHistory now that we're done with it.
+ delete history;
}
+
+#ifdef DEBUG
+int
+TournamentBP::BPHistory::newCount = 0;
+#endif
diff --git a/src/cpu/o3/tournament_pred.hh b/src/cpu/o3/tournament_pred.hh
index cb93c2f67..92402adc6 100644
--- a/src/cpu/o3/tournament_pred.hh
+++ b/src/cpu/o3/tournament_pred.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2005 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
@@ -24,61 +24,138 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_CPU_TOURNAMENT_PRED_HH__
-#define __CPU_O3_CPU_TOURNAMENT_PRED_HH__
+#ifndef __CPU_O3_TOURNAMENT_PRED_HH__
+#define __CPU_O3_TOURNAMENT_PRED_HH__
// For Addr type.
#include "arch/isa_traits.hh"
#include "cpu/o3/sat_counter.hh"
-
+#include <vector>
+
+/**
+ * Implements a tournament branch predictor, hopefully identical to the one
+ * used in the 21264. It has a local predictor, which uses a local history
+ * table to index into a table of counters, and a global predictor, which
+ * uses a global history to index into a table of counters. A choice
+ * predictor chooses between the two. Only the global history register
+ * is speculatively updated, the rest are updated upon branches committing
+ * or misspeculating.
+ */
class TournamentBP
{
public:
/**
* Default branch predictor constructor.
*/
- TournamentBP(unsigned local_predictor_size,
- unsigned local_ctr_bits,
- unsigned local_history_table_size,
- unsigned local_history_bits,
- unsigned global_predictor_size,
- unsigned global_history_bits,
- unsigned global_ctr_bits,
- unsigned choice_predictor_size,
- unsigned choice_ctr_bits,
+ TournamentBP(unsigned localPredictorSize,
+ unsigned localCtrBits,
+ unsigned localHistoryTableSize,
+ unsigned localHistoryBits,
+ unsigned globalPredictorSize,
+ unsigned globalHistoryBits,
+ unsigned globalCtrBits,
+ unsigned choicePredictorSize,
+ unsigned choiceCtrBits,
unsigned instShiftAmt);
/**
* Looks up the given address in the branch predictor and returns
- * a true/false value as to whether it is taken.
+ * a true/false value as to whether it is taken. Also creates a
+ * BPHistory object to store any state it will need on squash/update.
* @param branch_addr The address of the branch to look up.
+ * @param bp_history Pointer that will be set to the BPHistory object.
* @return Whether or not the branch is taken.
*/
- bool lookup(Addr &branch_addr);
+ bool lookup(Addr &branch_addr, void * &bp_history);
+
+ /**
+ * Records that there was an unconditional branch, and modifies
+ * the bp history to point to an object that has the previous
+ * global history stored in it.
+ * @param bp_history Pointer that will be set to the BPHistory object.
+ */
+ void uncondBr(void * &bp_history);
/**
* Updates the branch predictor with the actual result of a branch.
* @param branch_addr The address of the branch to update.
* @param taken Whether or not the branch was taken.
+ * @param bp_history Pointer to the BPHistory object that was created
+ * when the branch was predicted.
*/
- void update(Addr &branch_addr, unsigned global_history, bool taken);
+ void update(Addr &branch_addr, bool taken, void *bp_history);
+ /**
+ * Restores the global branch history on a squash.
+ * @param bp_history Pointer to the BPHistory object that has the
+ * previous global branch history in it.
+ */
+ void squash(void *bp_history);
+
+ /** Returns the global history. */
inline unsigned readGlobalHist() { return globalHistory; }
private:
-
+ /**
+ * Returns if the branch should be taken or not, given a counter
+ * value.
+ * @param count The counter value.
+ */
inline bool getPrediction(uint8_t &count);
+ /**
+ * Returns the local history index, given a branch address.
+ * @param branch_addr The branch's PC address.
+ */
inline unsigned calcLocHistIdx(Addr &branch_addr);
- inline void updateHistoriesTaken(unsigned local_history_idx);
+ /** Updates global history as taken. */
+ inline void updateGlobalHistTaken();
+
+ /** Updates global history as not taken. */
+ inline void updateGlobalHistNotTaken();
+
+ /**
+ * Updates local histories as taken.
+ * @param local_history_idx The local history table entry that
+ * will be updated.
+ */
+ inline void updateLocalHistTaken(unsigned local_history_idx);
+
+ /**
+ * Updates local histories as not taken.
+ * @param local_history_idx The local history table entry that
+ * will be updated.
+ */
+ inline void updateLocalHistNotTaken(unsigned local_history_idx);
- inline void updateHistoriesNotTaken(unsigned local_history_idx);
+ /**
+ * The branch history information that is created upon predicting
+ * a branch. It will be passed back upon updating and squashing,
+ * when the BP can use this information to update/restore its
+ * state properly.
+ */
+ struct BPHistory {
+#ifdef DEBUG
+ BPHistory()
+ { newCount++; }
+ ~BPHistory()
+ { newCount--; }
+
+ static int newCount;
+#endif
+ unsigned globalHistory;
+ bool localPredTaken;
+ bool globalPredTaken;
+ bool globalUsed;
+ };
/** Local counters. */
- SatCounter *localCtrs;
+ std::vector<SatCounter> localCtrs;
/** Size of the local predictor. */
unsigned localPredictorSize;
@@ -87,7 +164,7 @@ class TournamentBP
unsigned localCtrBits;
/** Array of local history table entries. */
- unsigned *localHistoryTable;
+ std::vector<unsigned> localHistoryTable;
/** Size of the local history table. */
unsigned localHistoryTableSize;
@@ -100,9 +177,8 @@ class TournamentBP
/** Mask to get the proper local history. */
unsigned localHistoryMask;
-
/** Array of counters that make up the global predictor. */
- SatCounter *globalCtrs;
+ std::vector<SatCounter> globalCtrs;
/** Size of the global predictor. */
unsigned globalPredictorSize;
@@ -119,9 +195,8 @@ class TournamentBP
/** Mask to get the proper global history. */
unsigned globalHistoryMask;
-
/** Array of counters that make up the choice predictor. */
- SatCounter *choiceCtrs;
+ std::vector<SatCounter> choiceCtrs;
/** Size of the choice predictor (identical to the global predictor). */
unsigned choicePredictorSize;
@@ -140,4 +215,4 @@ class TournamentBP
unsigned threshold;
};
-#endif // __CPU_O3_CPU_TOURNAMENT_PRED_HH__
+#endif // __CPU_O3_TOURNAMENT_PRED_HH__
diff --git a/src/cpu/op_class.cc b/src/cpu/op_class.cc
index 00136ded5..f7ef49c0f 100644
--- a/src/cpu/op_class.cc
+++ b/src/cpu/op_class.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "cpu/op_class.hh"
diff --git a/src/cpu/op_class.hh b/src/cpu/op_class.hh
index cdb40a0fb..71819c904 100644
--- a/src/cpu/op_class.hh
+++ b/src/cpu/op_class.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CPU__OP_CLASS_HH__
@@ -59,6 +62,6 @@ enum OpClass {
/**
* Array mapping OpClass enum values to strings. Defined in op_class.cc.
*/
-extern const char *opClassStrings[];
+extern const char *opClassStrings[Num_OpClasses];
#endif // __CPU__OP_CLASS_HH__
diff --git a/src/cpu/ozone/back_end.cc b/src/cpu/ozone/back_end.cc
new file mode 100644
index 000000000..a61a00c84
--- /dev/null
+++ b/src/cpu/ozone/back_end.cc
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/back_end_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+
+//template class BackEnd<OzoneImpl>;
diff --git a/src/cpu/ozone/back_end.hh b/src/cpu/ozone/back_end.hh
new file mode 100644
index 000000000..9bab6a964
--- /dev/null
+++ b/src/cpu/ozone/back_end.hh
@@ -0,0 +1,543 @@
+/*
+ * 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_OZONE_BACK_END_HH__
+#define __CPU_OZONE_BACK_END_HH__
+
+#include <list>
+#include <queue>
+#include <string>
+
+#include "arch/faults.hh"
+#include "base/timebuf.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/rename_table.hh"
+#include "cpu/ozone/thread_state.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+class ThreadContext;
+
+template <class Impl>
+class OzoneThreadState;
+
+template <class Impl>
+class BackEnd
+{
+ public:
+ typedef OzoneThreadState<Impl> Thread;
+
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInst DynInst;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::FrontEnd FrontEnd;
+ typedef typename Impl::FullCPU::CommStruct CommStruct;
+
+ struct SizeStruct {
+ int size;
+ };
+
+ typedef SizeStruct DispatchToIssue;
+ typedef SizeStruct IssueToExec;
+ typedef SizeStruct ExecToCommit;
+ typedef SizeStruct Writeback;
+
+ TimeBuffer<DispatchToIssue> d2i;
+ typename TimeBuffer<DispatchToIssue>::wire instsToDispatch;
+ TimeBuffer<IssueToExec> i2e;
+ typename TimeBuffer<IssueToExec>::wire instsToExecute;
+ TimeBuffer<ExecToCommit> e2c;
+ TimeBuffer<Writeback> numInstsToWB;
+
+ TimeBuffer<CommStruct> *comm;
+ typename TimeBuffer<CommStruct>::wire toIEW;
+ typename TimeBuffer<CommStruct>::wire fromCommit;
+
+ class InstQueue {
+ enum queue {
+ NonSpec,
+ IQ,
+ ToBeScheduled,
+ ReadyList,
+ ReplayList
+ };
+ struct pqCompare {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum > rhs->seqNum;
+ }
+ };
+ public:
+ InstQueue(Params *params);
+
+ std::string name() const;
+
+ void regStats();
+
+ void setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue);
+
+ void setBE(BackEnd *_be) { be = _be; }
+
+ void insert(DynInstPtr &inst);
+
+ void scheduleReadyInsts();
+
+ void scheduleNonSpec(const InstSeqNum &sn);
+
+ DynInstPtr getReadyInst();
+
+ void commit(const InstSeqNum &sn) {}
+
+ void squash(const InstSeqNum &sn);
+
+ int wakeDependents(DynInstPtr &inst);
+
+ /** Tells memory dependence unit that a memory instruction needs to be
+ * rescheduled. It will re-execute once replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &inst);
+
+ /** Re-executes all rescheduled memory instructions. */
+ void replayMemInst(DynInstPtr &inst);
+
+ /** Completes memory instruction. */
+ void completeMemInst(DynInstPtr &inst);
+
+ void violation(DynInstPtr &inst, DynInstPtr &violation) { }
+
+ bool isFull() { return numInsts >= size; }
+
+ void dumpInsts();
+
+ private:
+ bool find(queue q, typename std::list<DynInstPtr>::iterator it);
+ BackEnd *be;
+ TimeBuffer<IssueToExec> *i2e;
+ typename TimeBuffer<IssueToExec>::wire numIssued;
+ typedef typename std::list<DynInstPtr> InstList;
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+ typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue;
+ // Not sure I need the IQ list; it just needs to be a count.
+ InstList iq;
+ InstList toBeScheduled;
+ InstList readyList;
+ InstList nonSpec;
+ InstList replayList;
+ ReadyInstQueue readyQueue;
+ public:
+ int size;
+ int numInsts;
+ int width;
+
+ 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::Formula occ_rate;
+ Stats::Formula avg_residency;
+ Stats::Formula empty_rate;
+ Stats::Formula full_rate;
+ };
+
+ /** LdWriteback event for a load completion. */
+ class LdWritebackEvent : public Event {
+ private:
+ /** Instruction that is writing back data to the register file. */
+ DynInstPtr inst;
+ /** Pointer to IEW stage. */
+ BackEnd *be;
+
+ public:
+ /** Constructs a load writeback event. */
+ LdWritebackEvent(DynInstPtr &_inst, BackEnd *be);
+
+ /** Processes writeback event. */
+ virtual void process();
+ /** Returns the description of the writeback event. */
+ virtual const char *description();
+ };
+
+ BackEnd(Params *params);
+
+ std::string name() const;
+
+ void regStats();
+
+ void setCPU(FullCPU *cpu_ptr)
+ { cpu = cpu_ptr; }
+
+ void setFrontEnd(FrontEnd *front_end_ptr)
+ { frontEnd = front_end_ptr; }
+
+ void setTC(ThreadContext *tc_ptr)
+ { tc = tc_ptr; }
+
+ void setThreadState(Thread *thread_ptr)
+ { thread = thread_ptr; }
+
+ void setCommBuffer(TimeBuffer<CommStruct> *_comm);
+
+ void tick();
+ void squash();
+ void squashFromTC();
+ bool tcSquash;
+
+ template <class T>
+ Fault read(RequestPtr req, T &data, int load_idx);
+
+ template <class T>
+ Fault write(RequestPtr req, T &data, int store_idx);
+
+ Addr readCommitPC() { return commitPC; }
+
+ Addr commitPC;
+
+ bool robEmpty() { return instList.empty(); }
+
+ bool isFull() { return numInsts >= numROBEntries; }
+ bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; }
+
+ /** Tells memory dependence unit that a memory instruction needs to be
+ * rescheduled. It will re-execute once replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &inst)
+ { IQ.rescheduleMemInst(inst); }
+
+ /** Re-executes all rescheduled memory instructions. */
+ void replayMemInst(DynInstPtr &inst)
+ { IQ.replayMemInst(inst); }
+
+ /** Completes memory instruction. */
+ void completeMemInst(DynInstPtr &inst)
+ { IQ.completeMemInst(inst); }
+
+ void fetchFault(Fault &fault);
+
+ private:
+ void updateStructures();
+ void dispatchInsts();
+ void dispatchStall();
+ void checkDispatchStatus();
+ void scheduleReadyInsts();
+ void executeInsts();
+ void commitInsts();
+ void addToIQ(DynInstPtr &inst);
+ void addToLSQ(DynInstPtr &inst);
+ void instToCommit(DynInstPtr &inst);
+ void writebackInsts();
+ bool commitInst(int inst_num);
+ void squash(const InstSeqNum &sn);
+ void squashDueToBranch(DynInstPtr &inst);
+ void squashDueToMemBlocked(DynInstPtr &inst);
+ void updateExeInstStats(DynInstPtr &inst);
+ void updateComInstStats(DynInstPtr &inst);
+
+ public:
+ FullCPU *cpu;
+
+ FrontEnd *frontEnd;
+
+ ThreadContext *tc;
+
+ Thread *thread;
+
+ enum Status {
+ Running,
+ Idle,
+ DcacheMissStall,
+ DcacheMissComplete,
+ Blocked
+ };
+
+ Status status;
+
+ Status dispatchStatus;
+
+ Counter funcExeInst;
+
+ private:
+// typedef typename Impl::InstQueue InstQueue;
+
+ InstQueue IQ;
+
+ typedef typename Impl::LdstQueue LdstQueue;
+
+ LdstQueue LSQ;
+ public:
+ RenameTable<Impl> commitRenameTable;
+
+ RenameTable<Impl> renameTable;
+ private:
+ class DCacheCompletionEvent : public Event
+ {
+ private:
+ BackEnd *be;
+
+ public:
+ DCacheCompletionEvent(BackEnd *_be);
+
+ virtual void process();
+ virtual const char *description();
+ };
+
+ friend class DCacheCompletionEvent;
+
+ DCacheCompletionEvent cacheCompletionEvent;
+
+ MemInterface *dcacheInterface;
+
+ Request *memReq;
+
+ // General back end width. Used if the more specific isn't given.
+ int width;
+
+ // Dispatch width.
+ int dispatchWidth;
+ int numDispatchEntries;
+ int dispatchSize;
+
+ int issueWidth;
+
+ // Writeback width
+ int wbWidth;
+
+ // Commit width
+ int commitWidth;
+
+ /** Index into queue of instructions being written back. */
+ unsigned wbNumInst;
+
+ /** Cycle number within the queue of instructions being written
+ * back. Used in case there are too many instructions writing
+ * back at the current cycle and writesbacks need to be scheduled
+ * for the future. See comments in instToCommit().
+ */
+ unsigned wbCycle;
+
+ int numROBEntries;
+ int numInsts;
+
+ bool squashPending;
+ InstSeqNum squashSeqNum;
+ Addr squashNextPC;
+
+ Fault faultFromFetch;
+
+ private:
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+
+ std::list<DynInstPtr> instList;
+ std::list<DynInstPtr> dispatch;
+ std::list<DynInstPtr> writeback;
+
+ int latency;
+
+ int squashLatency;
+
+ bool exactFullStall;
+
+ bool fetchRedirect[Impl::MaxThreads];
+
+ // number of cycles stalled for D-cache misses
+/* 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;
+ // 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<> issued_ops;
+
+ // total number of loads forwaded from LSQ stores
+ Stats::Vector<> lsq_forw_loads;
+
+ // total number of loads ignored due to invalid addresses
+ Stats::Vector<> inv_addr_loads;
+
+ // total number of software prefetches ignored due to invalid addresses
+ Stats::Vector<> inv_addr_swpfs;
+ // ready loads blocked due to memory disambiguation
+ Stats::Vector<> lsq_blocked_loads;
+
+ Stats::Scalar<> lsqInversion;
+
+ Stats::Vector<> n_issued_dist;
+ Stats::VectorDistribution<> issue_delay_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::Formula misspec_cnt;
+ Stats::Formula misspec_ipc;
+ Stats::Formula issue_rate;
+ Stats::Formula issue_stores;
+ Stats::Formula issue_op_rate;
+ Stats::Formula fu_busy_rate;
+ Stats::Formula commit_stores;
+ Stats::Formula commit_ipc;
+ 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::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::Distribution<> n_committed_dist;
+
+ Stats::Scalar<> commit_eligible_samples;
+ Stats::Vector<> commit_eligible;
+
+ Stats::Scalar<> ROB_fcount;
+ Stats::Formula ROB_full_rate;
+
+ Stats::Vector<> ROB_count; // cumulative ROB occupancy
+ Stats::Formula ROB_occ_rate;
+ Stats::VectorDistribution<> ROB_occ_dist;
+ public:
+ void dumpInsts();
+};
+
+template <class Impl>
+template <class T>
+Fault
+BackEnd<Impl>::read(RequestPtr req, T &data, int load_idx)
+{
+/* memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = cpu->translateDataReadReq(memReq);
+
+ // if we have a cache, do cache access too
+ if (fault == NoFault && dcacheInterface) {
+ memReq->cmd = Read;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~INST_READ;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
+ // Fix this hack for keeping funcExeInst correct with loads that
+ // are executed twice.
+ --funcExeInst;
+
+ memReq->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
+ DPRINTF(OzoneCPU, "Dcache miss stall!\n");
+ } else {
+ // do functional access
+ fault = thread->mem->read(memReq, data);
+
+ }
+ }
+*/
+/*
+ if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Read");
+*/
+ return LSQ.read(req, data, load_idx);
+}
+
+template <class Impl>
+template <class T>
+Fault
+BackEnd<Impl>::write(RequestPtr req, T &data, int store_idx)
+{
+/*
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = cpu->translateDataWriteReq(memReq);
+
+ if (fault == NoFault && dcacheInterface) {
+ memReq->cmd = Write;
+ memcpy(memReq->data,(uint8_t *)&data,memReq->size);
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~INST_READ;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+// status = DcacheMissStall;
+ DPRINTF(OzoneCPU, "Dcache miss stall!\n");
+ }
+ }
+
+ if (res && (fault == NoFault))
+ *res = memReq->result;
+ */
+/*
+ if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Write");
+*/
+ return LSQ.write(req, data, store_idx);
+}
+
+#endif // __CPU_OZONE_BACK_END_HH__
diff --git a/src/cpu/ozone/back_end_impl.hh b/src/cpu/ozone/back_end_impl.hh
new file mode 100644
index 000000000..ac3218c02
--- /dev/null
+++ b/src/cpu/ozone/back_end_impl.hh
@@ -0,0 +1,1933 @@
+/*
+ * 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
+ */
+
+#include "encumbered/cpu/full/op_class.hh"
+#include "cpu/ozone/back_end.hh"
+
+template <class Impl>
+BackEnd<Impl>::InstQueue::InstQueue(Params *params)
+ : size(params->numIQEntries), numInsts(0), width(params->issueWidth)
+{
+}
+
+template <class Impl>
+std::string
+BackEnd<Impl>::InstQueue::name() const
+{
+ return be->name() + ".iq";
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::regStats()
+{
+ using namespace Stats;
+
+ occ_dist
+ .init(1, 0, size, 2)
+ .name(name() + "occ_dist")
+ .desc("IQ Occupancy per cycle")
+ .flags(total | cdf)
+ ;
+
+ inst_count
+ .init(1)
+ .name(name() + "cum_num_insts")
+ .desc("Total occupancy")
+ .flags(total)
+ ;
+
+ peak_inst_count
+ .init(1)
+ .name(name() + "peak_occupancy")
+ .desc("Peak IQ occupancy")
+ .flags(total)
+ ;
+
+ current_count
+ .name(name() + "current_count")
+ .desc("Occupancy this cycle")
+ ;
+
+ empty_count
+ .name(name() + "empty_count")
+ .desc("Number of empty cycles")
+ ;
+
+ fullCount
+ .name(name() + "full_count")
+ .desc("Number of full cycles")
+ ;
+
+
+ occ_rate
+ .name(name() + "occ_rate")
+ .desc("Average occupancy")
+ .flags(total)
+ ;
+ occ_rate = inst_count / be->cpu->numCycles;
+
+ avg_residency
+ .name(name() + "avg_residency")
+ .desc("Average IQ residency")
+ .flags(total)
+ ;
+ avg_residency = occ_rate / be->cpu->numCycles;
+
+ empty_rate
+ .name(name() + "empty_rate")
+ .desc("Fraction of cycles empty")
+ ;
+ empty_rate = 100 * empty_count / be->cpu->numCycles;
+
+ full_rate
+ .name(name() + "full_rate")
+ .desc("Fraction of cycles full")
+ ;
+ full_rate = 100 * fullCount / be->cpu->numCycles;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::setIssueExecQueue(TimeBuffer<IssueToExec> *i2e_queue)
+{
+ i2e = i2e_queue;
+ numIssued = i2e->getWire(0);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::insert(DynInstPtr &inst)
+{
+ numInsts++;
+ inst_count[0]++;
+ if (!inst->isNonSpeculative()) {
+ DPRINTF(BE, "Instruction [sn:%lli] added to IQ\n", inst->seqNum);
+ if (inst->readyToIssue()) {
+ toBeScheduled.push_front(inst);
+ inst->iqIt = toBeScheduled.begin();
+ inst->iqItValid = true;
+ } else {
+ iq.push_front(inst);
+ inst->iqIt = iq.begin();
+ inst->iqItValid = true;
+ }
+ } else {
+ DPRINTF(BE, "Nonspeculative instruction [sn:%lli] added to IQ\n", inst->seqNum);
+ nonSpec.push_front(inst);
+ inst->iqIt = nonSpec.begin();
+ inst->iqItValid = true;
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::scheduleReadyInsts()
+{
+ int scheduled = numIssued->size;
+ InstListIt iq_it = --toBeScheduled.end();
+ InstListIt iq_end_it = toBeScheduled.end();
+
+ while (iq_it != iq_end_it && scheduled < width) {
+// if ((*iq_it)->readyToIssue()) {
+ DPRINTF(BE, "Instruction [sn:%lli] PC:%#x is ready\n",
+ (*iq_it)->seqNum, (*iq_it)->readPC());
+ readyQueue.push(*iq_it);
+ readyList.push_front(*iq_it);
+
+ (*iq_it)->iqIt = readyList.begin();
+
+ toBeScheduled.erase(iq_it--);
+
+ ++scheduled;
+// } else {
+// iq_it++;
+// }
+ }
+
+ numIssued->size+= scheduled;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::scheduleNonSpec(const InstSeqNum &sn)
+{
+/*
+ InstListIt non_spec_it = nonSpec.begin();
+ InstListIt non_spec_end_it = nonSpec.end();
+
+ while ((*non_spec_it)->seqNum != sn) {
+ non_spec_it++;
+ assert(non_spec_it != non_spec_end_it);
+ }
+*/
+ DynInstPtr inst = nonSpec.back();
+
+ DPRINTF(BE, "Nonspeculative instruction [sn:%lli] scheduled\n", inst->seqNum);
+
+ assert(inst->seqNum == sn);
+
+ assert(find(NonSpec, inst->iqIt));
+ nonSpec.erase(inst->iqIt);
+ readyList.push_front(inst);
+ inst->iqIt = readyList.begin();
+ readyQueue.push(inst);
+ numIssued->size++;
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+BackEnd<Impl>::InstQueue::getReadyInst()
+{
+ assert(!readyList.empty());
+
+ DynInstPtr inst = readyQueue.top();
+ readyQueue.pop();
+ assert(find(ReadyList, inst->iqIt));
+ readyList.erase(inst->iqIt);
+ inst->iqItValid = false;
+// if (!inst->isMemRef())
+ --numInsts;
+ return inst;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::squash(const InstSeqNum &sn)
+{
+ InstListIt iq_it = iq.begin();
+ InstListIt iq_end_it = iq.end();
+
+ while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) {
+ DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum);
+ (*iq_it)->iqItValid = false;
+ iq.erase(iq_it++);
+ --numInsts;
+ }
+
+ iq_it = nonSpec.begin();
+ iq_end_it = nonSpec.end();
+
+ while (iq_it != iq_end_it && (*iq_it)->seqNum > sn) {
+ DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum);
+ (*iq_it)->iqItValid = false;
+ nonSpec.erase(iq_it++);
+ --numInsts;
+ }
+
+ iq_it = replayList.begin();
+ iq_end_it = replayList.end();
+
+ while (iq_it != iq_end_it) {
+ if ((*iq_it)->seqNum > sn) {
+ DPRINTF(BE, "Instruction [sn:%lli] removed from IQ\n", (*iq_it)->seqNum);
+ (*iq_it)->iqItValid = false;
+ replayList.erase(iq_it++);
+ --numInsts;
+ } else {
+ iq_it++;
+ }
+ }
+
+ assert(numInsts >= 0);
+/*
+ InstListIt ready_it = readyList.begin();
+ InstListIt ready_end_it = readyList.end();
+
+ while (ready_it != ready_end_it) {
+ if ((*ready_it)->seqNum > sn) {
+ readyList.erase(ready_it++);
+ } else {
+ ready_it++;
+ }
+ }
+*/
+}
+
+template <class Impl>
+int
+BackEnd<Impl>::InstQueue::wakeDependents(DynInstPtr &inst)
+{
+ assert(!inst->isSquashed());
+ std::vector<DynInstPtr> &dependents = inst->getDependents();
+ int num_outputs = dependents.size();
+
+ DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum);
+
+ for (int i = 0; i < num_outputs; i++) {
+ DynInstPtr dep_inst = dependents[i];
+ dep_inst->markSrcRegReady();
+ DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum);
+
+ if (dep_inst->readyToIssue() && dep_inst->iqItValid) {
+ if (dep_inst->isNonSpeculative()) {
+ assert(find(NonSpec, dep_inst->iqIt));
+ nonSpec.erase(dep_inst->iqIt);
+ } else {
+ assert(find(IQ, dep_inst->iqIt));
+ iq.erase(dep_inst->iqIt);
+ }
+
+ toBeScheduled.push_front(dep_inst);
+ dep_inst->iqIt = toBeScheduled.begin();
+ }
+ }
+ return num_outputs;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::rescheduleMemInst(DynInstPtr &inst)
+{
+ DPRINTF(BE, "Rescheduling memory instruction [sn:%lli]\n", inst->seqNum);
+ assert(!inst->iqItValid);
+ replayList.push_front(inst);
+ inst->iqIt = replayList.begin();
+ inst->iqItValid = true;
+ ++numInsts;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::replayMemInst(DynInstPtr &inst)
+{
+ DPRINTF(BE, "Replaying memory instruction [sn:%lli]\n", inst->seqNum);
+ assert(find(ReplayList, inst->iqIt));
+ InstListIt iq_it = --replayList.end();
+ InstListIt iq_end_it = replayList.end();
+ while (iq_it != iq_end_it) {
+ DynInstPtr rescheduled_inst = (*iq_it);
+
+ DPRINTF(BE, "Memory instruction [sn:%lli] also replayed\n", inst->seqNum);
+ replayList.erase(iq_it--);
+ toBeScheduled.push_front(rescheduled_inst);
+ rescheduled_inst->iqIt = toBeScheduled.begin();
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::completeMemInst(DynInstPtr &inst)
+{
+ panic("Not implemented.");
+}
+
+template <class Impl>
+bool
+BackEnd<Impl>::InstQueue::find(queue q, InstListIt it)
+{
+ InstListIt iq_it, iq_end_it;
+ switch(q) {
+ case NonSpec:
+ iq_it = nonSpec.begin();
+ iq_end_it = nonSpec.end();
+ break;
+ case IQ:
+ iq_it = iq.begin();
+ iq_end_it = iq.end();
+ break;
+ case ToBeScheduled:
+ iq_it = toBeScheduled.begin();
+ iq_end_it = toBeScheduled.end();
+ break;
+ case ReadyList:
+ iq_it = readyList.begin();
+ iq_end_it = readyList.end();
+ break;
+ case ReplayList:
+ iq_it = replayList.begin();
+ iq_end_it = replayList.end();
+ }
+
+ while (iq_it != it && iq_it != iq_end_it) {
+ iq_it++;
+ }
+ if (iq_it == it) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::InstQueue::dumpInsts()
+{
+ cprintf("IQ size: %i\n", iq.size());
+
+ InstListIt inst_list_it = --iq.end();
+
+ int num = 0;
+ int valid_num = 0;
+ while (inst_list_it != iq.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+ cprintf("nonSpec size: %i\n", nonSpec.size());
+
+ inst_list_it = --nonSpec.end();
+
+ while (inst_list_it != nonSpec.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+ cprintf("toBeScheduled size: %i\n", toBeScheduled.size());
+
+ inst_list_it = --toBeScheduled.end();
+
+ while (inst_list_it != toBeScheduled.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+ cprintf("readyList size: %i\n", readyList.size());
+
+ inst_list_it = --readyList.end();
+
+ while (inst_list_it != readyList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+}
+
+template<class Impl>
+BackEnd<Impl>::LdWritebackEvent::LdWritebackEvent(DynInstPtr &_inst,
+ BackEnd<Impl> *_be)
+ : Event(&mainEventQueue), inst(_inst), be(_be)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template<class Impl>
+void
+BackEnd<Impl>::LdWritebackEvent::process()
+{
+ DPRINTF(BE, "Load writeback event [sn:%lli]\n", inst->seqNum);
+// DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum);
+
+ //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+
+// iewStage->wakeCPU();
+
+ if (inst->isSquashed()) {
+ inst = NULL;
+ return;
+ }
+
+ if (!inst->isExecuted()) {
+ inst->setExecuted();
+
+ // Execute again to copy data to proper place.
+ inst->completeAcc();
+ }
+
+ // Need to insert instruction into queue to commit
+ be->instToCommit(inst);
+
+ //wroteToTimeBuffer = true;
+// iewStage->activityThisCycle();
+
+ inst = NULL;
+}
+
+template<class Impl>
+const char *
+BackEnd<Impl>::LdWritebackEvent::description()
+{
+ return "Load writeback event";
+}
+
+
+template <class Impl>
+BackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(BackEnd *_be)
+ : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
+{
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::DCacheCompletionEvent::process()
+{
+}
+
+template <class Impl>
+const char *
+BackEnd<Impl>::DCacheCompletionEvent::description()
+{
+ return "Cache completion event";
+}
+
+template <class Impl>
+BackEnd<Impl>::BackEnd(Params *params)
+ : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5),
+ xcSquash(false), IQ(params),
+ cacheCompletionEvent(this), width(params->backEndWidth),
+ exactFullStall(true)
+{
+ numROBEntries = params->numROBEntries;
+ numInsts = 0;
+ numDispatchEntries = 32;
+ IQ.setBE(this);
+ LSQ.setBE(this);
+
+ // Setup IQ and LSQ with their parameters here.
+ instsToDispatch = d2i.getWire(-1);
+
+ instsToExecute = i2e.getWire(-1);
+
+ IQ.setIssueExecQueue(&i2e);
+
+ dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width;
+ issueWidth = params->issueWidth ? params->issueWidth : width;
+ wbWidth = params->wbWidth ? params->wbWidth : width;
+ commitWidth = params->commitWidth ? params->commitWidth : width;
+
+ LSQ.init(params, params->LQEntries, params->SQEntries, 0);
+
+ dispatchStatus = Running;
+}
+
+template <class Impl>
+std::string
+BackEnd<Impl>::name() const
+{
+ return cpu->name() + ".backend";
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::regStats()
+{
+ using namespace Stats;
+ rob_cap_events
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:cap_events")
+ .desc("number of cycles where ROB cap was active")
+ .flags(total)
+ ;
+
+ rob_cap_inst_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:cap_inst")
+ .desc("number of instructions held up by ROB cap")
+ .flags(total)
+ ;
+
+ iq_cap_events
+ .init(cpu->number_of_threads)
+ .name(name() +".IQ:cap_events" )
+ .desc("number of cycles where IQ cap was active")
+ .flags(total)
+ ;
+
+ iq_cap_inst_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".IQ:cap_inst")
+ .desc("number of instructions held up by IQ cap")
+ .flags(total)
+ ;
+
+
+ exe_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:count")
+ .desc("number of insts issued")
+ .flags(total)
+ ;
+
+ exe_swp
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:swp")
+ .desc("number of swp insts issued")
+ .flags(total)
+ ;
+
+ exe_nop
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:nop")
+ .desc("number of nop insts issued")
+ .flags(total)
+ ;
+
+ exe_refs
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:refs")
+ .desc("number of memory reference insts issued")
+ .flags(total)
+ ;
+
+ exe_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:loads")
+ .desc("number of load insts issued")
+ .flags(total)
+ ;
+
+ exe_branches
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:branches")
+ .desc("Number of branches issued")
+ .flags(total)
+ ;
+
+ issued_ops
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:op_count")
+ .desc("number of insts issued")
+ .flags(total)
+ ;
+
+/*
+ for (int i=0; i<Num_OpClasses; ++i) {
+ stringstream subname;
+ subname << opClassStrings[i] << "_delay";
+ issue_delay_dist.subname(i, subname.str());
+ }
+*/
+ //
+ // Other stats
+ //
+ lsq_forw_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".LSQ:forw_loads")
+ .desc("number of loads forwarded via LSQ")
+ .flags(total)
+ ;
+
+ inv_addr_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:addr_loads")
+ .desc("number of invalid-address loads")
+ .flags(total)
+ ;
+
+ inv_addr_swpfs
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:addr_swpfs")
+ .desc("number of invalid-address SW prefetches")
+ .flags(total)
+ ;
+
+ lsq_blocked_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".LSQ:blocked_loads")
+ .desc("number of ready loads not issued due to memory disambiguation")
+ .flags(total)
+ ;
+
+ lsqInversion
+ .name(name() + ".ISSUE:lsq_invert")
+ .desc("Number of times LSQ instruction issued early")
+ ;
+
+ n_issued_dist
+ .init(issueWidth + 1)
+ .name(name() + ".ISSUE:issued_per_cycle")
+ .desc("Number of insts issued each cycle")
+ .flags(total | pdf | dist)
+ ;
+ issue_delay_dist
+ .init(Num_OpClasses,0,99,2)
+ .name(name() + ".ISSUE:")
+ .desc("cycles from operands ready to issue")
+ .flags(pdf | cdf)
+ ;
+
+ queue_res_dist
+ .init(Num_OpClasses, 0, 99, 2)
+ .name(name() + ".IQ:residence:")
+ .desc("cycles from dispatch to issue")
+ .flags(total | pdf | cdf )
+ ;
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ queue_res_dist.subname(i, opClassStrings[i]);
+ }
+
+ writeback_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:count")
+ .desc("cumulative count of insts written-back")
+ .flags(total)
+ ;
+
+ producer_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:producers")
+ .desc("num instructions producing a value")
+ .flags(total)
+ ;
+
+ consumer_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:consumers")
+ .desc("num instructions consuming a value")
+ .flags(total)
+ ;
+
+ wb_penalized
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:penalized")
+ .desc("number of instrctions required to write to 'other' IQ")
+ .flags(total)
+ ;
+
+
+ wb_penalized_rate
+ .name(name() + ".WB:penalized_rate")
+ .desc ("fraction of instructions written-back that wrote to 'other' IQ")
+ .flags(total)
+ ;
+
+ wb_penalized_rate = wb_penalized / writeback_count;
+
+ wb_fanout
+ .name(name() + ".WB:fanout")
+ .desc("average fanout of values written-back")
+ .flags(total)
+ ;
+
+ wb_fanout = producer_inst / consumer_inst;
+
+ wb_rate
+ .name(name() + ".WB:rate")
+ .desc("insts written-back per cycle")
+ .flags(total)
+ ;
+ wb_rate = writeback_count / cpu->numCycles;
+
+ stat_com_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:count")
+ .desc("Number of instructions committed")
+ .flags(total)
+ ;
+
+ stat_com_swp
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:swp_count")
+ .desc("Number of s/w prefetches committed")
+ .flags(total)
+ ;
+
+ stat_com_refs
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:refs")
+ .desc("Number of memory references committed")
+ .flags(total)
+ ;
+
+ stat_com_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:loads")
+ .desc("Number of loads committed")
+ .flags(total)
+ ;
+
+ stat_com_membars
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:membars")
+ .desc("Number of memory barriers committed")
+ .flags(total)
+ ;
+
+ stat_com_branches
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:branches")
+ .desc("Number of branches committed")
+ .flags(total)
+ ;
+ n_committed_dist
+ .init(0,commitWidth,1)
+ .name(name() + ".COM:committed_per_cycle")
+ .desc("Number of insts commited each cycle")
+ .flags(pdf)
+ ;
+
+ //
+ // Commit-Eligible instructions...
+ //
+ // -> The number of instructions eligible to commit in those
+ // cycles where we reached our commit BW limit (less the number
+ // actually committed)
+ //
+ // -> The average value is computed over ALL CYCLES... not just
+ // the BW limited cycles
+ //
+ // -> The standard deviation is computed only over cycles where
+ // we reached the BW limit
+ //
+ commit_eligible
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:bw_limited")
+ .desc("number of insts not committed due to BW limits")
+ .flags(total)
+ ;
+
+ commit_eligible_samples
+ .name(name() + ".COM:bw_lim_events")
+ .desc("number cycles where commit BW limit reached")
+ ;
+
+ ROB_fcount
+ .name(name() + ".ROB:full_count")
+ .desc("number of cycles where ROB was full")
+ ;
+
+ ROB_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:occupancy")
+ .desc(name() + ".ROB occupancy (cumulative)")
+ .flags(total)
+ ;
+
+ ROB_full_rate
+ .name(name() + ".ROB:full_rate")
+ .desc("ROB full per cycle")
+ ;
+ ROB_full_rate = ROB_fcount / cpu->numCycles;
+
+ ROB_occ_rate
+ .name(name() + ".ROB:occ_rate")
+ .desc("ROB occupancy rate")
+ .flags(total)
+ ;
+ ROB_occ_rate = ROB_count / cpu->numCycles;
+
+ ROB_occ_dist
+ .init(cpu->number_of_threads,0,numROBEntries,2)
+ .name(name() + ".ROB:occ_dist")
+ .desc("ROB Occupancy per cycle")
+ .flags(total | cdf)
+ ;
+
+ IQ.regStats();
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
+{
+ comm = _comm;
+ toIEW = comm->getWire(0);
+ fromCommit = comm->getWire(-1);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::tick()
+{
+ DPRINTF(BE, "Ticking back end\n");
+
+ ROB_count[0]+= numInsts;
+
+ wbCycle = 0;
+
+ if (xcSquash) {
+ squashFromXC();
+ }
+
+ // Read in any done instruction information and update the IQ or LSQ.
+ updateStructures();
+
+ if (dispatchStatus != Blocked) {
+ d2i.advance();
+ dispatchInsts();
+ } else {
+ checkDispatchStatus();
+ }
+
+ i2e.advance();
+ scheduleReadyInsts();
+
+ e2c.advance();
+ executeInsts();
+
+ numInstsToWB.advance();
+ writebackInsts();
+
+ commitInsts();
+
+ DPRINTF(BE, "IQ entries in use: %i, ROB entries in use: %i, LSQ loads: %i, LSQ stores: %i\n",
+ IQ.numInsts, numInsts, LSQ.numLoads(), LSQ.numStores());
+
+ assert(numInsts == instList.size());
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::updateStructures()
+{
+ if (fromCommit->doneSeqNum) {
+ IQ.commit(fromCommit->doneSeqNum);
+ LSQ.commitLoads(fromCommit->doneSeqNum);
+ LSQ.commitStores(fromCommit->doneSeqNum);
+ }
+
+ if (fromCommit->nonSpecSeqNum) {
+ if (fromCommit->uncached) {
+ LSQ.executeLoad(fromCommit->lqIdx);
+ } else {
+ IQ.scheduleNonSpec(
+ fromCommit->nonSpecSeqNum);
+ }
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::addToIQ(DynInstPtr &inst)
+{
+ // Do anything IQ specific here?
+ IQ.insert(inst);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::addToLSQ(DynInstPtr &inst)
+{
+ // Do anything LSQ specific here?
+ LSQ.insert(inst);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::dispatchInsts()
+{
+ DPRINTF(BE, "Trying to dispatch instructions.\n");
+
+ // Pull instructions out of the front end.
+ int disp_width = dispatchWidth ? dispatchWidth : width;
+
+ // Could model dispatching time, but in general 1 cycle is probably
+ // good enough.
+
+ if (dispatchSize < numDispatchEntries) {
+ for (int i = 0; i < disp_width; i++) {
+ // Get instructions
+ DynInstPtr inst = frontEnd->getInst();
+
+ if (!inst) {
+ // No more instructions to get
+ break;
+ }
+
+ DPRINTF(BE, "Processing instruction [sn:%lli] PC:%#x\n",
+ inst->seqNum, inst->readPC());
+
+ for (int i = 0; i < inst->numDestRegs(); ++i)
+ renameTable[inst->destRegIdx(i)] = inst;
+
+ // Add to queue to be dispatched.
+ dispatch.push_back(inst);
+
+ d2i[0].size++;
+ ++dispatchSize;
+ }
+ }
+
+ assert(dispatch.size() < 64);
+
+ for (int i = 0; i < instsToDispatch->size; ++i) {
+ assert(!dispatch.empty());
+ // Get instruction from front of time buffer
+ DynInstPtr inst = dispatch.front();
+ dispatch.pop_front();
+ --dispatchSize;
+
+ if (inst->isSquashed())
+ continue;
+
+ ++numInsts;
+ instList.push_back(inst);
+
+ DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n",
+ inst->seqNum, inst->readPC());
+
+ addToIQ(inst);
+
+ if (inst->isMemRef()) {
+ addToLSQ(inst);
+ }
+
+ if (inst->isNonSpeculative()) {
+ inst->setCanCommit();
+ }
+
+ // Check if IQ or LSQ is full. If so we'll need to break and stop
+ // removing instructions. Also update the number of insts to remove
+ // from the queue.
+ if (exactFullStall) {
+ bool stall = false;
+ if (IQ.isFull()) {
+ DPRINTF(BE, "IQ is full!\n");
+ stall = true;
+ } else if (LSQ.isFull()) {
+ DPRINTF(BE, "LSQ is full!\n");
+ stall = true;
+ } else if (isFull()) {
+ DPRINTF(BE, "ROB is full!\n");
+ stall = true;
+ ROB_fcount++;
+ }
+ if (stall) {
+ instsToDispatch->size-= i+1;
+ dispatchStall();
+ return;
+ }
+ }
+ }
+
+ // Check if IQ or LSQ is full. If so we'll need to break and stop
+ // removing instructions. Also update the number of insts to remove
+ // from the queue. Check here if we don't care about exact stall
+ // conditions.
+
+ bool stall = false;
+ if (IQ.isFull()) {
+ DPRINTF(BE, "IQ is full!\n");
+ stall = true;
+ } else if (LSQ.isFull()) {
+ DPRINTF(BE, "LSQ is full!\n");
+ stall = true;
+ } else if (isFull()) {
+ DPRINTF(BE, "ROB is full!\n");
+ stall = true;
+ ROB_fcount++;
+ }
+ if (stall) {
+ d2i.advance();
+ dispatchStall();
+ return;
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::dispatchStall()
+{
+ dispatchStatus = Blocked;
+ if (!cpu->decoupledFrontEnd) {
+ // Tell front end to stall here through a timebuffer, or just tell
+ // it directly.
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::checkDispatchStatus()
+{
+ DPRINTF(BE, "Checking dispatch status\n");
+ assert(dispatchStatus == Blocked);
+ if (!IQ.isFull() && !LSQ.isFull() && !isFull()) {
+ DPRINTF(BE, "Dispatch no longer blocked\n");
+ dispatchStatus = Running;
+ dispatchInsts();
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::scheduleReadyInsts()
+{
+ // Tell IQ to put any ready instructions into the instruction list.
+ // Probably want to have a list of DynInstPtrs returned here. Then I
+ // can choose to either put them into a time buffer to simulate
+ // IQ scheduling time, or hand them directly off to the next stage.
+ // Do you ever want to directly hand it off to the next stage?
+ DPRINTF(BE, "Trying to schedule ready instructions\n");
+ IQ.scheduleReadyInsts();
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::executeInsts()
+{
+ int insts_to_execute = instsToExecute->size;
+
+ issued_ops[0]+= insts_to_execute;
+ n_issued_dist[insts_to_execute]++;
+
+ DPRINTF(BE, "Trying to execute %i instructions\n", insts_to_execute);
+
+ fetchRedirect[0] = false;
+
+ while (insts_to_execute > 0) {
+ // Get ready instruction from the IQ (or queue coming out of IQ)
+ // Execute the ready instruction.
+ // Wakeup any dependents if it's done.
+ DynInstPtr inst = IQ.getReadyInst();
+
+ DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n",
+ inst->seqNum, inst->readPC());
+
+ ++funcExeInst;
+
+ // Check if the instruction is squashed; if so then skip it
+ // and don't count it towards the FU usage.
+ if (inst->isSquashed()) {
+ DPRINTF(BE, "Execute: Instruction was squashed.\n");
+
+ // Not sure how to handle this plus the method of sending # of
+ // instructions to use. Probably will just have to count it
+ // towards the bandwidth usage, but not the FU usage.
+ --insts_to_execute;
+
+ // Consider this instruction executed so that commit can go
+ // ahead and retire the instruction.
+ inst->setExecuted();
+
+ // Not sure if I should set this here or just let commit try to
+ // commit any squashed instructions. I like the latter a bit more.
+ inst->setCanCommit();
+
+// ++iewExecSquashedInsts;
+
+ continue;
+ }
+
+ Fault fault = NoFault;
+
+ // Execute instruction.
+ // Note that if the instruction faults, it will be handled
+ // at the commit stage.
+ if (inst->isMemRef() &&
+ (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
+ DPRINTF(BE, "Execute: Initiating access for memory "
+ "reference.\n");
+
+ // Tell the LDSTQ to execute this instruction (if it is a load).
+ if (inst->isLoad()) {
+ // Loads will mark themselves as executed, and their writeback
+ // event adds the instruction to the queue to commit
+ fault = LSQ.executeLoad(inst);
+
+// ++iewExecLoadInsts;
+ } else if (inst->isStore()) {
+ LSQ.executeStore(inst);
+
+// ++iewExecStoreInsts;
+
+ if (!(inst->req->flags & LOCKED)) {
+ inst->setExecuted();
+
+ instToCommit(inst);
+ }
+ // Store conditionals will mark themselves as executed, and
+ // their writeback event will add the instruction to the queue
+ // to commit.
+ } else {
+ panic("Unexpected memory type!\n");
+ }
+
+ } else {
+ inst->execute();
+
+// ++iewExecutedInsts;
+
+ inst->setExecuted();
+
+ instToCommit(inst);
+ }
+
+ updateExeInstStats(inst);
+
+ // Probably should have some sort of function for this.
+ // More general question of how to handle squashes? Have some sort of
+ // squash unit that controls it? Probably...
+ // Check if branch was correct. This check happens after the
+ // instruction is added to the queue because even if the branch
+ // is mispredicted, the branch instruction itself is still valid.
+ // Only handle this if there hasn't already been something that
+ // redirects fetch in this group of instructions.
+
+ // This probably needs to prioritize the redirects if a different
+ // scheduler is used. Currently the scheduler schedules the oldest
+ // instruction first, so the branch resolution order will be correct.
+ unsigned tid = inst->threadNumber;
+
+ if (!fetchRedirect[tid]) {
+
+ if (inst->mispredicted()) {
+ fetchRedirect[tid] = true;
+
+ DPRINTF(BE, "Execute: Branch mispredict detected.\n");
+ DPRINTF(BE, "Execute: Redirecting fetch to PC: %#x.\n",
+ inst->nextPC);
+
+ // If incorrect, then signal the ROB that it must be squashed.
+ squashDueToBranch(inst);
+
+ if (inst->predTaken()) {
+// predictedTakenIncorrect++;
+ } else {
+// predictedNotTakenIncorrect++;
+ }
+ } else if (LSQ.violation()) {
+ fetchRedirect[tid] = true;
+
+ // Get the DynInst that caused the violation. Note that this
+ // clears the violation signal.
+ DynInstPtr violator;
+ violator = LSQ.getMemDepViolator();
+
+ DPRINTF(BE, "LDSTQ detected a violation. Violator PC: "
+ "%#x, inst PC: %#x. Addr is: %#x.\n",
+ violator->readPC(), inst->readPC(), inst->physEffAddr);
+
+ // Tell the instruction queue that a violation has occured.
+// IQ.violation(inst, violator);
+
+ // Squash.
+// squashDueToMemOrder(inst,tid);
+ squashDueToBranch(inst);
+
+// ++memOrderViolationEvents;
+ } else if (LSQ.loadBlocked()) {
+ fetchRedirect[tid] = true;
+
+ DPRINTF(BE, "Load operation couldn't execute because the "
+ "memory system is blocked. PC: %#x [sn:%lli]\n",
+ inst->readPC(), inst->seqNum);
+
+ squashDueToMemBlocked(inst);
+ }
+ }
+
+// instList.pop_front();
+
+ --insts_to_execute;
+
+ // keep an instruction count
+ thread->numInst++;
+ thread->numInsts++;
+ }
+
+ assert(insts_to_execute >= 0);
+}
+
+template<class Impl>
+void
+BackEnd<Impl>::instToCommit(DynInstPtr &inst)
+{
+ int wb_width = wbWidth;
+ // First check the time slot that this instruction will write
+ // to. If there are free write ports at the time, then go ahead
+ // and write the instruction to that time. If there are not,
+ // keep looking back to see where's the first time there's a
+ // free slot. What happens if you run out of free spaces?
+ // For now naively assume that all instructions take one cycle.
+ // Otherwise would have to look into the time buffer based on the
+ // latency of the instruction.
+
+ DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ while (numInstsToWB[wbCycle].size >= wb_width) {
+ ++wbCycle;
+
+ assert(wbCycle < 5);
+ }
+
+ // Add finished instruction to queue to commit.
+ writeback.push_back(inst);
+ numInstsToWB[wbCycle].size++;
+
+ if (wbCycle)
+ wb_penalized[0]++;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::writebackInsts()
+{
+ int wb_width = wbWidth;
+ // Using this method I'm not quite sure how to prevent an
+ // instruction from waking its own dependents multiple times,
+ // without the guarantee that commit always has enough bandwidth
+ // to accept all instructions being written back. This guarantee
+ // might not be too unrealistic.
+ InstListIt wb_inst_it = writeback.begin();
+ InstListIt wb_end_it = writeback.end();
+ int inst_num = 0;
+ int consumer_insts = 0;
+
+ for (; inst_num < wb_width &&
+ wb_inst_it != wb_end_it; inst_num++) {
+ DynInstPtr inst = (*wb_inst_it);
+
+ // Some instructions will be sent to commit without having
+ // executed because they need commit to handle them.
+ // E.g. Uncached loads have not actually executed when they
+ // are first sent to commit. Instead commit must tell the LSQ
+ // when it's ready to execute the uncached load.
+ if (!inst->isSquashed()) {
+ DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ inst->setCanCommit();
+ inst->setResultReady();
+
+ if (inst->isExecuted()) {
+ int dependents = IQ.wakeDependents(inst);
+ if (dependents) {
+ producer_inst[0]++;
+ consumer_insts+= dependents;
+ }
+ }
+ }
+
+ writeback.erase(wb_inst_it++);
+ }
+ LSQ.writebackStores();
+ consumer_inst[0]+= consumer_insts;
+ writeback_count[0]+= inst_num;
+}
+
+template <class Impl>
+bool
+BackEnd<Impl>::commitInst(int inst_num)
+{
+ // Read instruction from the head of the ROB
+ DynInstPtr inst = instList.front();
+
+ // Make sure instruction is valid
+ assert(inst);
+
+ if (!inst->readyToCommit())
+ return false;
+
+ DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n",
+ inst->seqNum, inst->readPC());
+
+ // If the instruction is not executed yet, then it is a non-speculative
+ // or store inst. Signal backwards that it should be executed.
+ if (!inst->isExecuted()) {
+ // Keep this number correct. We have not yet actually executed
+ // and committed this instruction.
+// thread->funcExeInst--;
+
+ if (inst->isNonSpeculative()) {
+#if !FULL_SYSTEM
+ // Hack to make sure syscalls aren't executed until all stores
+ // write back their data. This direct communication shouldn't
+ // be used for anything other than this.
+ if (inst_num > 0 || LSQ.hasStoresToWB()) {
+ DPRINTF(BE, "Waiting for all stores to writeback.\n");
+ return false;
+ }
+#endif
+
+ DPRINTF(BE, "Encountered a store or non-speculative "
+ "instruction at the head of the ROB, PC %#x.\n",
+ inst->readPC());
+
+ // Send back the non-speculative instruction's sequence number.
+ toIEW->nonSpecSeqNum = inst->seqNum;
+
+ // Change the instruction so it won't try to commit again until
+ // it is executed.
+ inst->clearCanCommit();
+
+// ++commitNonSpecStalls;
+
+ return false;
+ } else if (inst->isLoad()) {
+ DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ // Send back the non-speculative instruction's sequence
+ // number. Maybe just tell the lsq to re-execute the load.
+ toIEW->nonSpecSeqNum = inst->seqNum;
+ toIEW->uncached = true;
+ toIEW->lqIdx = inst->lqIdx;
+
+ inst->clearCanCommit();
+
+ return false;
+ } else {
+ panic("Trying to commit un-executed instruction "
+ "of unknown type!\n");
+ }
+ }
+
+ // Now check if it's one of the special trap or barrier or
+ // serializing instructions.
+ if (inst->isThreadSync())
+ {
+ // Not handled for now.
+ panic("Barrier instructions are not handled yet.\n");
+ }
+
+ // Check if the instruction caused a fault. If so, trap.
+ Fault inst_fault = inst->getFault();
+
+ if (inst_fault != NoFault) {
+ if (!inst->isNop()) {
+#if FULL_SYSTEM
+ DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n",
+ inst->seqNum, inst->readPC());
+
+// assert(!thread->inSyscall);
+
+// thread->inSyscall = true;
+
+ // Consider holding onto the trap and waiting until the trap event
+ // happens for this to be executed.
+ inst_fault->invoke(thread->getXCProxy());
+
+ // Exit state update mode to avoid accidental updating.
+// thread->inSyscall = false;
+
+// commitStatus = TrapPending;
+
+ // Generate trap squash event.
+// generateTrapEvent();
+
+ return false;
+#else // !FULL_SYSTEM
+ panic("fault (%d) detected @ PC %08p", inst_fault,
+ inst->PC);
+#endif // FULL_SYSTEM
+ }
+ }
+
+ if (inst->isControl()) {
+// ++commitCommittedBranches;
+ }
+
+ int freed_regs = 0;
+
+ for (int i = 0; i < inst->numDestRegs(); ++i) {
+ DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n",
+ (int)inst->destRegIdx(i), inst->seqNum);
+ thread->renameTable[inst->destRegIdx(i)] = inst;
+ ++freed_regs;
+ }
+
+ if (inst->traceData) {
+ inst->traceData->finalize();
+ inst->traceData = NULL;
+ }
+
+ inst->clearDependents();
+
+ frontEnd->addFreeRegs(freed_regs);
+
+ instList.pop_front();
+
+ --numInsts;
+ cpu->numInst++;
+ thread->numInsts++;
+ ++thread->funcExeInst;
+ thread->PC = inst->readNextPC();
+ updateComInstStats(inst);
+
+ // Write the done sequence number here.
+ toIEW->doneSeqNum = inst->seqNum;
+
+#if FULL_SYSTEM
+ int count = 0;
+ Addr oldpc;
+ do {
+ if (count == 0)
+ assert(!thread->inSyscall && !thread->trapPending);
+ oldpc = thread->readPC();
+ cpu->system->pcEventQueue.service(
+ thread->getXCProxy());
+ count++;
+ } while (oldpc != thread->readPC());
+ if (count > 1) {
+ DPRINTF(BE, "PC skip function event, stopping commit\n");
+// completed_last_inst = false;
+// squashPending = true;
+ return false;
+ }
+#endif
+ return true;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::commitInsts()
+{
+ int commit_width = commitWidth ? commitWidth : width;
+
+ // Not sure this should be a loop or not.
+ int inst_num = 0;
+ while (!instList.empty() && inst_num < commit_width) {
+ if (instList.front()->isSquashed()) {
+ panic("No squashed insts should still be on the list!");
+ instList.front()->clearDependents();
+ instList.pop_front();
+ continue;
+ }
+
+ if (!commitInst(inst_num++)) {
+ break;
+ }
+ }
+ n_committed_dist.sample(inst_num);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::squash(const InstSeqNum &sn)
+{
+ IQ.squash(sn);
+ LSQ.squash(sn);
+
+ int freed_regs = 0;
+ InstListIt dispatch_end = dispatch.end();
+ InstListIt insts_it = dispatch.end();
+ insts_it--;
+
+ while (insts_it != dispatch_end && (*insts_it)->seqNum > sn)
+ {
+ if ((*insts_it)->isSquashed()) {
+ --insts_it;
+ continue;
+ }
+ DPRINTF(BE, "Squashing instruction on dispatch list PC %#x, [sn:%lli].\n",
+ (*insts_it)->readPC(),
+ (*insts_it)->seqNum);
+
+ // Mark the instruction as squashed, and ready to commit so that
+ // it can drain out of the pipeline.
+ (*insts_it)->setSquashed();
+
+ (*insts_it)->setCanCommit();
+
+ // Be careful with IPRs and such here
+ for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) {
+ DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i);
+ DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n",
+ (int)(*insts_it)->destRegIdx(i), prev_dest);
+ renameTable[(*insts_it)->destRegIdx(i)] = prev_dest;
+ ++freed_regs;
+ }
+
+ (*insts_it)->clearDependents();
+
+ --insts_it;
+ }
+
+ insts_it = instList.end();
+ insts_it--;
+
+ while (!instList.empty() && (*insts_it)->seqNum > sn)
+ {
+ if ((*insts_it)->isSquashed()) {
+ --insts_it;
+ continue;
+ }
+ DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n",
+ (*insts_it)->readPC(),
+ (*insts_it)->seqNum);
+
+ // Mark the instruction as squashed, and ready to commit so that
+ // it can drain out of the pipeline.
+ (*insts_it)->setSquashed();
+
+ (*insts_it)->setCanCommit();
+
+ for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) {
+ DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i);
+ DPRINTF(BE, "Commit rename map setting register %i to [sn:%lli]\n",
+ (int)(*insts_it)->destRegIdx(i), prev_dest);
+ renameTable[(*insts_it)->destRegIdx(i)] = prev_dest;
+ ++freed_regs;
+ }
+
+ (*insts_it)->clearDependents();
+
+ instList.erase(insts_it--);
+ --numInsts;
+ }
+
+ frontEnd->addFreeRegs(freed_regs);
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::squashFromXC()
+{
+ xcSquash = true;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::squashDueToBranch(DynInstPtr &inst)
+{
+ // Update the branch predictor state I guess
+ squash(inst->seqNum);
+ frontEnd->squash(inst->seqNum, inst->readNextPC(),
+ true, inst->mispredicted());
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst)
+{
+ DPRINTF(IEW, "Memory blocked, squashing load and younger insts, "
+ "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum);
+
+ squash(inst->seqNum - 1);
+ frontEnd->squash(inst->seqNum - 1, inst->readPC());
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::fetchFault(Fault &fault)
+{
+ faultFromFetch = fault;
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::updateExeInstStats(DynInstPtr &inst)
+{
+ int thread_number = inst->threadNumber;
+
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch())
+ exe_swp[thread_number]++;
+ else
+ exe_inst[thread_number]++;
+#else
+ exe_inst[thread_number]++;
+#endif
+
+ //
+ // Control operations
+ //
+ if (inst->isControl())
+ exe_branches[thread_number]++;
+
+ //
+ // Memory operations
+ //
+ if (inst->isMemRef()) {
+ exe_refs[thread_number]++;
+
+ if (inst->isLoad())
+ exe_loads[thread_number]++;
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::updateComInstStats(DynInstPtr &inst)
+{
+ unsigned thread = inst->threadNumber;
+
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch()) {
+ stat_com_swp[thread]++;
+ } else {
+ stat_com_inst[thread]++;
+ }
+#else
+ stat_com_inst[thread]++;
+#endif
+
+ //
+ // Control Instructions
+ //
+ if (inst->isControl())
+ stat_com_branches[thread]++;
+
+ //
+ // Memory references
+ //
+ if (inst->isMemRef()) {
+ stat_com_refs[thread]++;
+
+ if (inst->isLoad()) {
+ stat_com_loads[thread]++;
+ }
+ }
+
+ if (inst->isMemBarrier()) {
+ stat_com_membars[thread]++;
+ }
+}
+
+template <class Impl>
+void
+BackEnd<Impl>::dumpInsts()
+{
+ int num = 0;
+ int valid_num = 0;
+
+ InstListIt inst_list_it = instList.begin();
+
+ cprintf("Inst list size: %i\n", instList.size());
+
+ while (inst_list_it != instList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it++;
+ ++num;
+ }
+
+ cprintf("Dispatch list size: %i\n", dispatch.size());
+
+ inst_list_it = dispatch.begin();
+
+ while (inst_list_it != dispatch.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it++;
+ ++num;
+ }
+
+ cprintf("Writeback list size: %i\n", writeback.size());
+
+ inst_list_it = writeback.begin();
+
+ while (inst_list_it != writeback.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it++;
+ ++num;
+ }
+}
diff --git a/src/cpu/ozone/base_dyn_inst.cc b/src/cpu/ozone/base_dyn_inst.cc
new file mode 100644
index 000000000..5a3a69dff
--- /dev/null
+++ b/src/cpu/ozone/base_dyn_inst.cc
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cpu/base_dyn_inst_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+
+// Explicit instantiation
+template class BaseDynInst<OzoneImpl>;
+
+template <>
+int
+BaseDynInst<OzoneImpl>::instcount = 0;
diff --git a/src/cpu/ozone/bpred_unit.cc b/src/cpu/ozone/bpred_unit.cc
new file mode 100644
index 000000000..c823f5e80
--- /dev/null
+++ b/src/cpu/ozone/bpred_unit.cc
@@ -0,0 +1,36 @@
+/*
+ * 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/bpred_unit_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+//#include "cpu/ozone/simple_impl.hh"
+
+template class BPredUnit<OzoneImpl>;
+//template class BPredUnit<SimpleImpl>;
diff --git a/src/cpu/ozone/checker_builder.cc b/src/cpu/ozone/checker_builder.cc
new file mode 100644
index 000000000..c372e51d6
--- /dev/null
+++ b/src/cpu/ozone/checker_builder.cc
@@ -0,0 +1,158 @@
+/*
+ * 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
+ */
+
+#include <string>
+
+#include "cpu/checker/cpu_impl.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/dyn_inst.hh"
+#include "cpu/ozone/ozone_impl.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class MemObject;
+
+template
+class Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >;
+
+/**
+ * Specific non-templated derived class used for SimObject configuration.
+ */
+class OzoneChecker :
+ public Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >
+{
+ public:
+ OzoneChecker(Params *p)
+ : Checker<RefCountingPtr<OzoneDynInst<OzoneImpl> > >(p)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// CheckerCPU Simulation Object
+//
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker)
+
+ Param<Counter> max_insts_any_thread;
+ Param<Counter> max_insts_all_threads;
+ Param<Counter> max_loads_any_thread;
+ Param<Counter> max_loads_all_threads;
+
+#if FULL_SYSTEM
+ SimObjectParam<AlphaITB *> itb;
+ SimObjectParam<AlphaDTB *> dtb;
+ SimObjectParam<System *> system;
+ Param<int> cpu_id;
+ Param<Tick> profile;
+#else
+ SimObjectParam<Process *> workload;
+#endif // FULL_SYSTEM
+ Param<int> clock;
+
+ Param<bool> defer_registration;
+ Param<bool> exitOnError;
+ Param<bool> warnOnlyOnLoadError;
+ Param<bool> function_trace;
+ Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(OzoneChecker)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(OzoneChecker)
+
+ INIT_PARAM(max_insts_any_thread,
+ "terminate when any thread reaches this inst count"),
+ INIT_PARAM(max_insts_all_threads,
+ "terminate when all threads have reached this inst count"),
+ INIT_PARAM(max_loads_any_thread,
+ "terminate when any thread reaches this load count"),
+ INIT_PARAM(max_loads_all_threads,
+ "terminate when all threads have reached this load count"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(itb, "Instruction TLB"),
+ INIT_PARAM(dtb, "Data TLB"),
+ INIT_PARAM(system, "system object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(profile, ""),
+#else
+ INIT_PARAM(workload, "processes to run"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM(clock, "clock speed"),
+
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+ INIT_PARAM(exitOnError, "exit on error"),
+ INIT_PARAM_DFLT(warnOnlyOnLoadError, "warn, but don't exit, if a load "
+ "result errors", false),
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(OzoneChecker)
+
+
+CREATE_SIM_OBJECT(OzoneChecker)
+{
+ OzoneChecker::Params *params = new OzoneChecker::Params();
+ params->name = getInstanceName();
+ params->numberOfThreads = 1;
+ params->max_insts_any_thread = 0;
+ params->max_insts_all_threads = 0;
+ params->max_loads_any_thread = 0;
+ params->max_loads_all_threads = 0;
+ params->exitOnError = exitOnError;
+ params->warnOnlyOnLoadError = warnOnlyOnLoadError;
+ params->deferRegistration = defer_registration;
+ params->functionTrace = function_trace;
+ params->functionTraceStart = function_trace_start;
+ params->clock = clock;
+ // Hack to touch all parameters. Consider not deriving Checker
+ // from BaseCPU..it's not really a CPU in the end.
+ Counter temp;
+ temp = max_insts_any_thread;
+ temp = max_insts_all_threads;
+ temp = max_loads_any_thread;
+ temp = max_loads_all_threads;
+
+#if FULL_SYSTEM
+ params->itb = itb;
+ params->dtb = dtb;
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->profile = profile;
+#else
+ params->process = workload;
+#endif
+
+ OzoneChecker *cpu = new OzoneChecker(params);
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("OzoneChecker", OzoneChecker)
diff --git a/src/cpu/ozone/cpu.cc b/src/cpu/ozone/cpu.cc
index cbeca9d3b..eb6ac37bd 100644
--- a/src/cpu/ozone/cpu.cc
+++ b/src/cpu/ozone/cpu.cc
@@ -24,10 +24,14 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
-#include "cpu/ooo_cpu/ooo_cpu_impl.hh"
-#include "cpu/ooo_cpu/ooo_dyn_inst.hh"
-#include "cpu/ooo_cpu/ooo_impl.hh"
+#include "cpu/ozone/cpu_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+//#include "cpu/ozone/simple_impl.hh"
-template class OoOCPU<OoOImpl>;
+//template class OzoneCPU<SimpleImpl>;
+template class OzoneCPU<OzoneImpl>;
diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh
index fa849bb09..f726ac99b 100644
--- a/src/cpu/ozone/cpu.hh
+++ b/src/cpu/ozone/cpu.hh
@@ -24,32 +24,45 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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_OOO_CPU_OOO_CPU_HH__
-#define __CPU_OOO_CPU_OOO_CPU_HH__
+#ifndef __CPU_OZONE_CPU_HH__
+#define __CPU_OZONE_CPU_HH__
+
+#include <set>
#include "base/statistics.hh"
+#include "base/timebuf.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
-#include "encumbered/cpu/full/fu_pool.hh"
-#include "cpu/ooo_cpu/ea_list.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/rename_table.hh"
+#include "cpu/ozone/thread_state.hh"
#include "cpu/pc_event.hh"
#include "cpu/static_inst.hh"
-#include "mem/mem_interface.hh"
+#include "mem/page_table.hh"
#include "sim/eventq.hh"
// forward declarations
#if FULL_SYSTEM
-class Processor;
+#include "arch/alpha/tlb.hh"
+
class AlphaITB;
class AlphaDTB;
class PhysicalMemory;
+class MemoryController;
+class Sampler;
class RemoteGDB;
class GDBListener;
+namespace Kernel {
+ class Statistics;
+};
+
#else
class Process;
@@ -57,12 +70,17 @@ class Process;
#endif // FULL_SYSTEM
class Checkpoint;
-class MemInterface;
+class EndQuiesceEvent;
+class MemObject;
+class Request;
namespace Trace {
class InstRecord;
}
+template <class>
+class Checker;
+
/**
* Declaration of Out-of-Order CPU class. Basically it is a SimpleCPU with
* simple out-of-order capabilities added to it. It is still a 1 CPI machine
@@ -72,23 +90,205 @@ namespace Trace {
*/
template <class Impl>
-class OoOCPU : public BaseCPU
+class OzoneCPU : public BaseCPU
{
private:
+ typedef typename Impl::FrontEnd FrontEnd;
+ typedef typename Impl::BackEnd BackEnd;
typedef typename Impl::DynInst DynInst;
typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+
+ public:
+ class OzoneTC : public ThreadContext {
+ public:
+ OzoneCPU<Impl> *cpu;
+
+ OzoneThreadState<Impl> *thread;
+
+ BaseCPU *getCpuPtr();
+
+ void setCpuId(int id);
+
+ int readCpuId() { return thread->readCpuId(); }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return cpu->system; }
+
+ PhysicalMemory *getPhysMemPtr() { return cpu->physmem; }
+
+ AlphaITB *getITBPtr() { return cpu->itb; }
+
+ AlphaDTB * getDTBPtr() { return cpu->dtb; }
+
+ Kernel::Statistics *getKernelStats()
+ { return thread->getKernelStats(); }
+
+ FunctionalPort *getPhysPort() { return thread->getPhysPort(); }
+
+ VirtualPort *getVirtPort(ThreadContext *tc = NULL)
+ { return thread->getVirtPort(tc); }
+
+ void delVirtPort(VirtualPort *vp);
+#else
+ TranslatingPort *getMemPort() { return thread->getMemPort(); }
+
+ Process *getProcessPtr() { return thread->getProcessPtr(); }
+#endif
+
+ Status status() const { return thread->status(); }
+
+ void setStatus(Status new_status);
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1);
+
+ /// Set the status to Suspended.
+ void suspend();
+
+ /// Set the status to Unallocated.
+ void deallocate();
+
+ /// Set the status to Halted.
+ void halt();
+
+#if FULL_SYSTEM
+ void dumpFuncProfile();
+#endif
+
+ void takeOverFrom(ThreadContext *old_context);
+
+ void regStats(const std::string &name);
+
+ void serialize(std::ostream &os);
+ void unserialize(Checkpoint *cp, const std::string &section);
+
+#if FULL_SYSTEM
+ EndQuiesceEvent *getQuiesceEvent();
+
+ Tick readLastActivate();
+ Tick readLastSuspend();
+
+ void profileClear();
+ void profileSample();
+#endif
+
+ int getThreadNum();
+
+ // Also somewhat obnoxious. Really only used for the TLB fault.
+ TheISA::MachInst getInst();
+
+ void copyArchRegs(ThreadContext *tc);
+
+ void clearArchRegs();
+
+ uint64_t readIntReg(int reg_idx);
+
+ FloatReg readFloatReg(int reg_idx, int width);
+
+ FloatReg readFloatReg(int reg_idx);
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width);
+
+ FloatRegBits readFloatRegBits(int reg_idx);
+
+ void setIntReg(int reg_idx, uint64_t val);
+
+ void setFloatReg(int reg_idx, FloatReg val, int width);
+
+ void setFloatReg(int reg_idx, FloatReg val);
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width);
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val);
+
+ uint64_t readPC() { return thread->PC; }
+ void setPC(Addr val);
+
+ uint64_t readNextPC() { return thread->nextPC; }
+ void setNextPC(Addr val);
+
+ uint64_t readNextNPC()
+ {
+ return 0;
+ }
+
+ void setNextNPC(uint64_t val)
+ { }
+
+ public:
+ // ISA stuff:
+ MiscReg readMiscReg(int misc_reg);
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault);
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val);
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val);
+
+ unsigned readStCondFailures()
+ { return thread->storeCondFailures; }
+
+ void setStCondFailures(unsigned sc_failures)
+ { thread->storeCondFailures = sc_failures; }
+
+#if FULL_SYSTEM
+ bool inPalMode() { return cpu->inPalMode(); }
+#endif
+
+ bool misspeculating() { return false; }
+
+#if !FULL_SYSTEM
+ TheISA::IntReg getSyscallArg(int i)
+ { return thread->renameTable[TheISA::ArgumentReg0 + i]->readIntResult(); }
+
+ // used to shift args for indirect syscall
+ void setSyscallArg(int i, TheISA::IntReg val)
+ { thread->renameTable[TheISA::ArgumentReg0 + 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::RegFile::ContextParam param,
+ TheISA::RegFile::ContextVal val)
+ { panic("Not supported on Alpha!"); }
+ };
+
+ // Ozone specific thread context
+ OzoneTC ozoneTC;
+ // Thread context to be used
+ ThreadContext *tc;
+ // Checker thread context; will wrap the OzoneTC if a checker is
+ // being used.
+ ThreadContext *checkerTC;
+
+ typedef OzoneThreadState<Impl> ImplState;
+
+ private:
+ OzoneThreadState<Impl> thread;
+
public:
// main simulation loop (one cycle)
void tick();
+ std::set<InstSeqNum> snList;
+ std::set<Addr> lockAddrList;
private:
struct TickEvent : public Event
{
- OoOCPU *cpu;
+ OzoneCPU *cpu;
int width;
- TickEvent(OoOCPU *c, int w);
+ TickEvent(OzoneCPU *c, int w);
void process();
const char *description();
};
@@ -99,9 +299,9 @@ class OoOCPU : public BaseCPU
void scheduleTickEvent(int delay)
{
if (tickEvent.squashed())
- tickEvent.reschedule(curTick + delay);
+ tickEvent.reschedule(curTick + cycles(delay));
else if (!tickEvent.scheduled())
- tickEvent.schedule(curTick + delay);
+ tickEvent.schedule(curTick + cycles(delay));
}
/// Unschedule tick event, regardless of its current state.
@@ -118,20 +318,17 @@ class OoOCPU : public BaseCPU
void trace_data(T data);
public:
- //
enum Status {
Running,
Idle,
- IcacheMiss,
- IcacheMissComplete,
- DcacheMissStall,
SwitchedOut
};
- private:
Status _status;
public:
+ bool checkInterrupts;
+
void post_interrupt(int int_num, int index);
void zero_fill_64(Addr addr) {
@@ -142,97 +339,50 @@ class OoOCPU : public BaseCPU
}
};
- struct Params : public BaseCPU::Params
- {
- MemInterface *icache_interface;
- MemInterface *dcache_interface;
- int width;
-#if FULL_SYSTEM
- AlphaITB *itb;
- AlphaDTB *dtb;
- FunctionalMemory *mem;
-#else
- Process *process;
-#endif
- int issueWidth;
- };
+ typedef typename Impl::Params Params;
- OoOCPU(Params *params);
+ OzoneCPU(Params *params);
- virtual ~OoOCPU();
+ virtual ~OzoneCPU();
void init();
- private:
- void copyFromXC();
-
public:
- // execution context
- ExecContext *xc;
+ BaseCPU *getCpuPtr() { return this; }
- void switchOut();
- void takeOverFrom(BaseCPU *oldCPU);
-
-#if FULL_SYSTEM
- Addr dbg_vtophys(Addr addr);
-
- bool interval_stats;
-#endif
-
- // L1 instruction cache
- MemInterface *icacheInterface;
+ void setCpuId(int id) { cpuId = id; }
- // L1 data cache
- MemInterface *dcacheInterface;
+ int readCpuId() { return cpuId; }
- FuncUnitPool *fuPool;
+ int cpuId;
- // Refcounted pointer to the one memory request.
- MemReqPtr cacheMemReq;
-
- class ICacheCompletionEvent : public Event
- {
- private:
- OoOCPU *cpu;
-
- public:
- ICacheCompletionEvent(OoOCPU *_cpu);
-
- virtual void process();
- virtual const char *description();
- };
-
- // Will need to create a cache completion event upon any memory miss.
- ICacheCompletionEvent iCacheCompletionEvent;
+ void switchOut(Sampler *sampler);
+ void signalSwitched();
+ void takeOverFrom(BaseCPU *oldCPU);
- class DCacheCompletionEvent;
+ Sampler *sampler;
- typedef typename
- std::list<DCacheCompletionEvent>::iterator DCacheCompEventIt;
+ int switchCount;
- class DCacheCompletionEvent : public Event
- {
- private:
- OoOCPU *cpu;
- DynInstPtr inst;
- DCacheCompEventIt dcceIt;
+#if FULL_SYSTEM
+ Addr dbg_vtophys(Addr addr);
- public:
- DCacheCompletionEvent(OoOCPU *_cpu, DynInstPtr &_inst,
- DCacheCompEventIt &_dcceIt);
+ bool interval_stats;
- virtual void process();
- virtual const char *description();
- };
+ AlphaITB *itb;
+ AlphaDTB *dtb;
+ System *system;
+ PhysicalMemory *physmem;
+#endif
- friend class DCacheCompletionEvent;
+ MemObject *mem;
- protected:
- std::list<DCacheCompletionEvent> dCacheCompList;
- DCacheCompEventIt dcceIt;
+ FrontEnd *frontEnd;
+ BackEnd *backEnd;
private:
Status status() const { return _status; }
+ void setStatus(Status new_status) { _status = new_status; }
virtual void activateContext(int thread_num, int delay);
virtual void suspendContext(int thread_num);
@@ -244,18 +394,16 @@ class OoOCPU : public BaseCPU
virtual void resetStats();
// number of simulated instructions
+ public:
Counter numInst;
Counter startNumInst;
- Stats::Scalar<> numInsts;
virtual Counter totalInstructions() const
{
return numInst - startNumInst;
}
- // number of simulated memory references
- Stats::Scalar<> numMemRefs;
-
+ private:
// number of simulated loads
Counter numLoad;
Counter startNumLoad;
@@ -263,376 +411,217 @@ class OoOCPU : public BaseCPU
// number of idle cycles
Stats::Average<> notIdleFraction;
Stats::Formula idleFraction;
-
- // number of cycles stalled for I-cache misses
- Stats::Scalar<> icacheStallCycles;
- Counter lastIcacheStall;
-
- // number of cycles stalled for D-cache misses
- Stats::Scalar<> dcacheStallCycles;
- Counter lastDcacheStall;
-
- void processICacheCompletion();
-
public:
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
-#if FULL_SYSTEM
- bool validInstAddr(Addr addr) { return true; }
- bool validDataAddr(Addr addr) { return true; }
- int getInstAsid() { return xc->regs.instAsid(); }
- int getDataAsid() { return xc->regs.dataAsid(); }
- Fault translateInstReq(MemReqPtr &req)
+#if FULL_SYSTEM
+ /** Translates instruction requestion. */
+ Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return itb->translate(req);
+ return itb->translate(req, thread->getTC());
}
- Fault translateDataReadReq(MemReqPtr &req)
+ /** Translates data read request. */
+ Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return dtb->translate(req, false);
+ return dtb->translate(req, thread->getTC(), false);
}
- Fault translateDataWriteReq(MemReqPtr &req)
+ /** Translates data write request. */
+ Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return dtb->translate(req, true);
+ return dtb->translate(req, thread->getTC(), true);
}
#else
- bool validInstAddr(Addr addr)
- { return xc->validInstAddr(addr); }
-
- bool validDataAddr(Addr addr)
- { return xc->validDataAddr(addr); }
-
- int getInstAsid() { return xc->asid; }
- int getDataAsid() { return xc->asid; }
-
- Fault dummyTranslation(MemReqPtr &req)
- {
-#if 0
- assert((req->vaddr >> 48 & 0xffff) == 0);
-#endif
-
- // put the asid in the upper 16 bits of the paddr
- req->paddr = req->vaddr & ~((Addr)0xffff << sizeof(Addr) * 8 - 16);
- req->paddr = req->paddr | (Addr)req->asid << sizeof(Addr) * 8 - 16;
- return NoFault;
- }
- Fault translateInstReq(MemReqPtr &req)
+ /** Translates instruction requestion in syscall emulation mode. */
+ Fault translateInstReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return dummyTranslation(req);
+ return thread->getProcessPtr()->pTable->translate(req);
}
- Fault translateDataReadReq(MemReqPtr &req)
+
+ /** Translates data read request in syscall emulation mode. */
+ Fault translateDataReadReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return dummyTranslation(req);
+ return thread->getProcessPtr()->pTable->translate(req);
}
- Fault translateDataWriteReq(MemReqPtr &req)
+
+ /** Translates data write request in syscall emulation mode. */
+ Fault translateDataWriteReq(RequestPtr &req, OzoneThreadState<Impl> *thread)
{
- return dummyTranslation(req);
+ return thread->getProcessPtr()->pTable->translate(req);
}
-
#endif
+ /** Old CPU read from memory function. No longer used. */
template <class T>
- Fault read(Addr addr, T &data, unsigned flags, DynInstPtr inst);
-
- template <class T>
- Fault write(T data, Addr addr, unsigned flags,
- uint64_t *res, DynInstPtr inst);
-
- void prefetch(Addr addr, unsigned flags)
+ Fault read(Request *req, T &data)
{
- // need to do this...
- }
-
- void writeHint(Addr addr, int size, unsigned flags)
- {
- // need to do this...
- }
-
- Fault copySrcTranslate(Addr src);
-
- Fault copy(Addr dest);
-
- private:
- bool executeInst(DynInstPtr &inst);
-
- void renameInst(DynInstPtr &inst);
-
- void addInst(DynInstPtr &inst);
-
- void commitHeadInst();
-
- bool getOneInst();
-
- Fault fetchCacheLine();
-
- InstSeqNum getAndIncrementInstSeq();
-
- bool ambigMemAddr;
-
- private:
- InstSeqNum globalSeqNum;
-
- DynInstPtr renameTable[TheISA::TotalNumRegs];
- DynInstPtr commitTable[TheISA::TotalNumRegs];
-
- // Might need a table of the shadow registers as well.
-#if FULL_SYSTEM
- DynInstPtr palShadowTable[TheISA::NumIntRegs];
+#if 0
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+#endif
+ if (req->flags & LOCKED) {
+ lockAddrList.insert(req->paddr);
+ lockFlag = true;
+ }
#endif
+ Fault error;
- 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).
-
- // In the OoO case these shouldn't read from the XC but rather from the
- // rename table of DynInsts. Also these likely shouldn't be called very
- // often, other than when adding things into the xc during say a syscall.
-
- uint64_t readIntReg(StaticInst *si, int idx)
- {
- return xc->readIntReg(si->srcRegIdx(idx));
+ error = this->mem->read(req, data);
+ data = gtoh(data);
+ return error;
}
- FloatReg readFloatReg(StaticInst *si, int idx, width)
- {
- int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return xc->readFloatReg(reg_idx, width);
- }
- FloatReg readFloatReg(StaticInst *si, int idx)
+ /** CPU read function, forwards read to LSQ. */
+ template <class T>
+ Fault read(Request *req, T &data, int load_idx)
{
- int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return xc->readFloatReg(reg_idx);
+ return backEnd->read(req, data, load_idx);
}
- FloatRegBits readFloatRegBits(StaticInst *si, int idx, int width)
+ /** Old CPU write to memory function. No longer used. */
+ template <class T>
+ Fault write(Request *req, T &data)
{
- int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return xc->readFloatRegBits(reg_idx, width);
- }
+#if 0
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
- FloatRegBits readFloatRegBits(StaticInst *si, int idx)
- {
- int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return xc->readFloatRegBits(reg_idx);
- }
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < this->system->threadContexts.size(); i++){
+ xc = this->system->threadContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
- void setIntReg(StaticInst *si, int idx, uint64_t val)
- {
- xc->setIntReg(si->destRegIdx(idx), val);
- }
+#endif
- void setFloatReg(StaticInst *si, int idx, FloatReg val, int width)
- {
- int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- xc->setFloatReg(reg_idx, val, width);
- }
+ if (req->flags & LOCKED) {
+ if (req->flags & UNCACHEABLE) {
+ req->result = 2;
+ } else {
+ if (this->lockFlag) {
+ if (lockAddrList.find(req->paddr) !=
+ lockAddrList.end()) {
+ req->result = 1;
+ } else {
+ req->result = 0;
+ return NoFault;
+ }
+ } else {
+ req->result = 0;
+ return NoFault;
+ }
+ }
+ }
+#endif
- void setFloatReg(StaticInst *si, int idx, FloatReg val)
- {
- int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- xc->setFloatReg(reg_idx, val);
+ return this->mem->write(req, (T)htog(data));
}
- void setFloatRegBits(StaticInst *si, int idx, FloatRegBits val, int width)
+ /** CPU write function, forwards write to LSQ. */
+ template <class T>
+ Fault write(Request *req, T &data, int store_idx)
{
- int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- xc->setFloatRegBits(reg_idx, val, width);
+ return backEnd->write(req, data, store_idx);
}
- void setFloatRegBits(StaticInst *si, int idx, FloatRegBits val)
+ void prefetch(Addr addr, unsigned flags)
{
- int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- xc->setFloatRegBits(reg_idx, val);
+ // need to do this...
}
- uint64_t readPC() { return PC; }
- void setNextPC(Addr val) { nextPC = val; }
-
- private:
- Addr PC;
- Addr nextPC;
-
- unsigned issueWidth;
-
- bool fetchRedirExcp;
- bool fetchRedirBranch;
-
- /** Mask to get a cache block's address. */
- Addr cacheBlkMask;
-
- unsigned cacheBlkSize;
-
- Addr cacheBlkPC;
-
- /** The cache line being fetched. */
- uint8_t *cacheData;
-
- protected:
- bool cacheBlkValid;
-
- private:
-
- // Align an address (typically a PC) to the start of an I-cache block.
- // We fold in the PISA 64- to 32-bit conversion here as well.
- Addr icacheBlockAlignPC(Addr addr)
+ void writeHint(Addr addr, int size, unsigned flags)
{
- addr = TheISA::realPCToFetchPC(addr);
- return (addr & ~(cacheBlkMask));
+ // need to do this...
}
- unsigned instSize;
+ Fault copySrcTranslate(Addr src);
- // ROB tracking stuff.
- DynInstPtr robHeadPtr;
- DynInstPtr robTailPtr;
- unsigned robSize;
- unsigned robInsts;
+ Fault copy(Addr dest);
- // List of outstanding EA instructions.
- protected:
- EAList eaList;
+ InstSeqNum globalSeqNum;
public:
- void branchToTarget(Addr val)
- {
- if (!fetchRedirExcp) {
- fetchRedirBranch = true;
- PC = val;
- }
- }
-
- // ISA stuff:
- uint64_t readUniq() { return xc->readUniq(); }
- void setUniq(uint64_t val) { xc->setUniq(val); }
+ void squashFromTC();
- uint64_t readFpcr() { return xc->readFpcr(); }
- void setFpcr(uint64_t val) { xc->setFpcr(val); }
+ // @todo: This can be a useful debug function. Implement it.
+ void dumpInsts() { frontEnd->dumpInsts(); }
#if FULL_SYSTEM
- uint64_t readIpr(int idx, Fault &fault) { return xc->readIpr(idx, fault); }
- Fault setIpr(int idx, uint64_t val) { return xc->setIpr(idx, val); }
- Fault hwrei() { return xc->hwrei(); }
- int readIntrFlag() { return xc->readIntrFlag(); }
- void setIntrFlag(int val) { xc->setIntrFlag(val); }
- bool inPalMode() { return xc->inPalMode(); }
- void trap(Fault fault) { fault->invoke(xc); }
- bool simPalCheck(int palFunc) { return xc->simPalCheck(palFunc); }
+ Fault hwrei();
+ int readIntrFlag() { return thread.intrflag; }
+ void setIntrFlag(int val) { thread.intrflag = val; }
+ bool inPalMode() { return AlphaISA::PcPAL(thread.PC); }
+ bool inPalMode(Addr pc) { return AlphaISA::PcPAL(pc); }
+ bool simPalCheck(int palFunc);
+ void processInterrupts();
#else
- void syscall() { xc->syscall(); }
-#endif
-
- ExecContext *xcBase() { return xc; }
-};
-
-
-// precise architected memory state accessor macros
-template <class Impl>
-template <class T>
-Fault
-OoOCPU<Impl>::read(Addr addr, T &data, unsigned flags, DynInstPtr inst)
-{
- MemReqPtr readReq = new MemReq();
- readReq->xc = xc;
- readReq->asid = 0;
- readReq->data = new uint8_t[64];
-
- readReq->reset(addr, sizeof(T), flags);
-
- // translate to physical address - This might be an ISA impl call
- Fault fault = translateDataReadReq(readReq);
-
- // do functional access
- if (fault == NoFault)
- fault = xc->mem->read(readReq, data);
-#if 0
- if (traceData) {
- traceData->setAddr(addr);
- if (fault == NoFault)
- traceData->setData(data);
- }
+ void syscall(uint64_t &callnum);
+ void setSyscallReturn(SyscallReturn return_value, int tid);
#endif
- // if we have a cache, do cache access too
- if (fault == NoFault && dcacheInterface) {
- readReq->cmd = Read;
- readReq->completionEvent = NULL;
- readReq->time = curTick;
- /*MemAccessResult result = */dcacheInterface->access(readReq);
-
- if (dcacheInterface->doEvents()) {
- readReq->completionEvent = new DCacheCompletionEvent(this, inst,
- dcceIt);
- }
- }
-
- if (!dcacheInterface && (readReq->flags & UNCACHEABLE))
- recordEvent("Uncached Read");
+ ThreadContext *tcBase() { return tc; }
- return fault;
-}
+ bool decoupledFrontEnd;
+ struct CommStruct {
+ InstSeqNum doneSeqNum;
+ InstSeqNum nonSpecSeqNum;
+ bool uncached;
+ unsigned lqIdx;
-template <class Impl>
-template <class T>
-Fault
-OoOCPU<Impl>::write(T data, Addr addr, unsigned flags,
- uint64_t *res, DynInstPtr inst)
-{
- MemReqPtr writeReq = new MemReq();
- writeReq->xc = xc;
- writeReq->asid = 0;
- writeReq->data = new uint8_t[64];
-
-#if 0
- if (traceData) {
- traceData->setAddr(addr);
- traceData->setData(data);
- }
-#endif
-
- writeReq->reset(addr, sizeof(T), flags);
-
- // translate to physical address
- Fault fault = translateDataWriteReq(writeReq);
-
- // do functional access
- if (fault == NoFault)
- fault = xc->write(writeReq, data);
-
- if (fault == NoFault && dcacheInterface) {
- writeReq->cmd = Write;
- memcpy(writeReq->data,(uint8_t *)&data,writeReq->size);
- writeReq->completionEvent = NULL;
- writeReq->time = curTick;
- /*MemAccessResult result = */dcacheInterface->access(writeReq);
-
- if (dcacheInterface->doEvents()) {
- writeReq->completionEvent = new DCacheCompletionEvent(this, inst,
- dcceIt);
- }
- }
-
- if (res && (fault == NoFault))
- *res = writeReq->result;
+ bool stall;
+ };
+ TimeBuffer<CommStruct> comm;
- if (!dcacheInterface && (writeReq->flags & UNCACHEABLE))
- recordEvent("Uncached Write");
+ bool lockFlag;
- return fault;
-}
+ Stats::Scalar<> quiesceCycles;
+ Checker<DynInstPtr> *checker;
+};
-#endif // __CPU_OOO_CPU_OOO_CPU_HH__
+#endif // __CPU_OZONE_CPU_HH__
diff --git a/src/cpu/ozone/cpu_builder.cc b/src/cpu/ozone/cpu_builder.cc
new file mode 100644
index 000000000..e239b7a94
--- /dev/null
+++ b/src/cpu/ozone/cpu_builder.cc
@@ -0,0 +1,451 @@
+/*
+ * 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
+ */
+
+#include <string>
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/cpu.hh"
+#include "cpu/ozone/ozone_impl.hh"
+#include "cpu/ozone/simple_params.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+class DerivOzoneCPU : public OzoneCPU<OzoneImpl>
+{
+ public:
+ DerivOzoneCPU(SimpleParams *p)
+ : OzoneCPU<OzoneImpl>(p)
+ { }
+};
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// OzoneCPU Simulation Object
+//
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU)
+
+ Param<int> clock;
+ Param<int> numThreads;
+
+#if FULL_SYSTEM
+SimObjectParam<System *> system;
+Param<int> cpu_id;
+SimObjectParam<AlphaITB *> itb;
+SimObjectParam<AlphaDTB *> dtb;
+#else
+SimObjectVectorParam<Process *> workload;
+//SimObjectParam<PageTable *> page_table;
+#endif // FULL_SYSTEM
+
+SimObjectParam<MemObject *> mem;
+
+SimObjectParam<BaseCPU *> checker;
+
+Param<Counter> max_insts_any_thread;
+Param<Counter> max_insts_all_threads;
+Param<Counter> max_loads_any_thread;
+Param<Counter> max_loads_all_threads;
+
+//SimObjectParam<BaseCache *> icache;
+//SimObjectParam<BaseCache *> dcache;
+
+Param<unsigned> cachePorts;
+Param<unsigned> width;
+Param<unsigned> frontEndWidth;
+Param<unsigned> backEndWidth;
+Param<unsigned> backEndSquashLatency;
+Param<unsigned> backEndLatency;
+Param<unsigned> maxInstBufferSize;
+Param<unsigned> numPhysicalRegs;
+Param<unsigned> maxOutstandingMemOps;
+
+Param<unsigned> decodeToFetchDelay;
+Param<unsigned> renameToFetchDelay;
+Param<unsigned> iewToFetchDelay;
+Param<unsigned> commitToFetchDelay;
+Param<unsigned> fetchWidth;
+
+Param<unsigned> renameToDecodeDelay;
+Param<unsigned> iewToDecodeDelay;
+Param<unsigned> commitToDecodeDelay;
+Param<unsigned> fetchToDecodeDelay;
+Param<unsigned> decodeWidth;
+
+Param<unsigned> iewToRenameDelay;
+Param<unsigned> commitToRenameDelay;
+Param<unsigned> decodeToRenameDelay;
+Param<unsigned> renameWidth;
+
+Param<unsigned> commitToIEWDelay;
+Param<unsigned> renameToIEWDelay;
+Param<unsigned> issueToExecuteDelay;
+Param<unsigned> issueWidth;
+Param<unsigned> executeWidth;
+Param<unsigned> executeIntWidth;
+Param<unsigned> executeFloatWidth;
+Param<unsigned> executeBranchWidth;
+Param<unsigned> executeMemoryWidth;
+
+Param<unsigned> iewToCommitDelay;
+Param<unsigned> renameToROBDelay;
+Param<unsigned> commitWidth;
+Param<unsigned> squashWidth;
+
+Param<std::string> predType;
+Param<unsigned> localPredictorSize;
+Param<unsigned> localCtrBits;
+Param<unsigned> localHistoryTableSize;
+Param<unsigned> localHistoryBits;
+Param<unsigned> globalPredictorSize;
+Param<unsigned> globalCtrBits;
+Param<unsigned> globalHistoryBits;
+Param<unsigned> choicePredictorSize;
+Param<unsigned> choiceCtrBits;
+
+Param<unsigned> BTBEntries;
+Param<unsigned> BTBTagSize;
+
+Param<unsigned> RASSize;
+
+Param<unsigned> LQEntries;
+Param<unsigned> SQEntries;
+Param<unsigned> LFSTSize;
+Param<unsigned> SSITSize;
+
+Param<unsigned> numPhysIntRegs;
+Param<unsigned> numPhysFloatRegs;
+Param<unsigned> numIQEntries;
+Param<unsigned> numROBEntries;
+
+Param<bool> decoupledFrontEnd;
+Param<int> dispatchWidth;
+Param<int> wbWidth;
+
+Param<unsigned> smtNumFetchingThreads;
+Param<std::string> smtFetchPolicy;
+Param<std::string> smtLSQPolicy;
+Param<unsigned> smtLSQThreshold;
+Param<std::string> smtIQPolicy;
+Param<unsigned> smtIQThreshold;
+Param<std::string> smtROBPolicy;
+Param<unsigned> smtROBThreshold;
+Param<std::string> smtCommitPolicy;
+
+Param<unsigned> instShiftAmt;
+
+Param<bool> defer_registration;
+
+Param<bool> function_trace;
+Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(DerivOzoneCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU)
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(numThreads, "number of HW thread contexts"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(system, "System object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(itb, "Instruction translation buffer"),
+ INIT_PARAM(dtb, "Data translation buffer"),
+#else
+ INIT_PARAM(workload, "Processes to run"),
+// INIT_PARAM(page_table, "Page table"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(mem, "Memory", NULL),
+
+ INIT_PARAM_DFLT(checker, "Checker CPU", NULL),
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "Terminate when any thread reaches this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "Terminate when all threads have reached"
+ "this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_any_thread,
+ "Terminate when any thread reaches this load count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_all_threads,
+ "Terminate when all threads have reached this load"
+ "count",
+ 0),
+
+// INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL),
+// INIT_PARAM_DFLT(dcache, "L1 data cache", NULL),
+
+ INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200),
+ INIT_PARAM_DFLT(width, "Width", 1),
+ INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1),
+ INIT_PARAM_DFLT(backEndWidth, "Back end width", 1),
+ INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1),
+ INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1),
+ INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16),
+ INIT_PARAM(numPhysicalRegs, "Number of physical registers"),
+ INIT_PARAM_DFLT(maxOutstandingMemOps, "Maximum outstanding memory operations", 4),
+
+ INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"),
+ INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"),
+ INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch"
+ "delay"),
+ INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"),
+ INIT_PARAM(fetchWidth, "Fetch width"),
+ INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"),
+ INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode"
+ "delay"),
+ INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"),
+ INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"),
+ INIT_PARAM(decodeWidth, "Decode width"),
+
+ INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename"
+ "delay"),
+ INIT_PARAM(commitToRenameDelay, "Commit to rename delay"),
+ INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"),
+ INIT_PARAM(renameWidth, "Rename width"),
+
+ INIT_PARAM(commitToIEWDelay, "Commit to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(renameToIEWDelay, "Rename to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal"
+ "to the IEW stage)"),
+ INIT_PARAM(issueWidth, "Issue width"),
+ INIT_PARAM(executeWidth, "Execute width"),
+ INIT_PARAM(executeIntWidth, "Integer execute width"),
+ INIT_PARAM(executeFloatWidth, "Floating point execute width"),
+ INIT_PARAM(executeBranchWidth, "Branch execute width"),
+ INIT_PARAM(executeMemoryWidth, "Memory execute width"),
+
+ INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit "
+ "delay"),
+ INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"),
+ INIT_PARAM(commitWidth, "Commit width"),
+ INIT_PARAM(squashWidth, "Squash width"),
+
+ INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"),
+ INIT_PARAM(localPredictorSize, "Size of local predictor"),
+ INIT_PARAM(localCtrBits, "Bits per counter"),
+ INIT_PARAM(localHistoryTableSize, "Size of local history table"),
+ INIT_PARAM(localHistoryBits, "Bits for the local history"),
+ INIT_PARAM(globalPredictorSize, "Size of global predictor"),
+ INIT_PARAM(globalCtrBits, "Bits per counter"),
+ INIT_PARAM(globalHistoryBits, "Bits of history"),
+ INIT_PARAM(choicePredictorSize, "Size of choice predictor"),
+ INIT_PARAM(choiceCtrBits, "Bits of choice counters"),
+
+ INIT_PARAM(BTBEntries, "Number of BTB entries"),
+ INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"),
+
+ INIT_PARAM(RASSize, "RAS size"),
+
+ INIT_PARAM(LQEntries, "Number of load queue entries"),
+ INIT_PARAM(SQEntries, "Number of store queue entries"),
+ INIT_PARAM(LFSTSize, "Last fetched store table size"),
+ INIT_PARAM(SSITSize, "Store set ID table size"),
+
+ INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"),
+ INIT_PARAM(numPhysFloatRegs, "Number of physical floating point "
+ "registers"),
+ INIT_PARAM(numIQEntries, "Number of instruction queue entries"),
+ INIT_PARAM(numROBEntries, "Number of reorder buffer entries"),
+
+ INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true),
+ INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0),
+ INIT_PARAM_DFLT(wbWidth, "Writeback width", 0),
+
+ INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1),
+ INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"),
+ INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100),
+ INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100),
+ INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100),
+ INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"),
+
+ INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"),
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(DerivOzoneCPU)
+
+CREATE_SIM_OBJECT(DerivOzoneCPU)
+{
+ DerivOzoneCPU *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.isValid() ? numThreads : workload.size();
+
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
+ }
+
+#endif
+
+ SimpleParams *params = new SimpleParams;
+
+ params->clock = clock;
+
+ params->name = getInstanceName();
+ params->numberOfThreads = actual_num_threads;
+
+#if FULL_SYSTEM
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->itb = itb;
+ params->dtb = dtb;
+#else
+ params->workload = workload;
+// params->pTable = page_table;
+#endif // FULL_SYSTEM
+
+ params->mem = mem;
+ params->checker = checker;
+ 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->icacheInterface = icache ? icache->getInterface() : NULL;
+// params->dcacheInterface = dcache ? dcache->getInterface() : NULL;
+ params->cachePorts = cachePorts;
+
+ params->width = width;
+ params->frontEndWidth = frontEndWidth;
+ params->backEndWidth = backEndWidth;
+ params->backEndSquashLatency = backEndSquashLatency;
+ params->backEndLatency = backEndLatency;
+ params->maxInstBufferSize = maxInstBufferSize;
+ params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs;
+ params->maxOutstandingMemOps = maxOutstandingMemOps;
+
+ 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->issueWidth = issueWidth;
+ params->executeWidth = executeWidth;
+ params->executeIntWidth = executeIntWidth;
+ params->executeFloatWidth = executeFloatWidth;
+ params->executeBranchWidth = executeBranchWidth;
+ params->executeMemoryWidth = executeMemoryWidth;
+
+ params->iewToCommitDelay = iewToCommitDelay;
+ params->renameToROBDelay = renameToROBDelay;
+ params->commitWidth = commitWidth;
+ params->squashWidth = squashWidth;
+
+ 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->decoupledFrontEnd = decoupledFrontEnd;
+ params->dispatchWidth = dispatchWidth;
+ params->wbWidth = wbWidth;
+
+ params->smtNumFetchingThreads = smtNumFetchingThreads;
+ 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 DerivOzoneCPU(params);
+
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("DerivOzoneCPU", DerivOzoneCPU)
diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh
index e7ed3cfe0..2cdc8a3da 100644
--- a/src/cpu/ozone/cpu_impl.hh
+++ b/src/cpu/ozone/cpu_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 The Regents of The University of Michigan
+ * Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,25 +24,1102 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
-#ifndef __CPU_OOO_CPU_OOO_IMPL_HH__
-#define __CPU_OOO_CPU_OOO_IMPL_HH__
+#include "config/full_system.hh"
+#include "config/use_checker.hh"
+
+#include "arch/isa_traits.hh" // For MachInst
+#include "base/trace.hh"
+#include "cpu/base.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/ozone/cpu.hh"
+#include "cpu/quiesce_event.hh"
+#include "cpu/static_inst.hh"
+#include "sim/sim_object.hh"
+#include "sim/stats.hh"
+
+#if FULL_SYSTEM
+#include "arch/faults.hh"
+#include "arch/alpha/osfpal.hh"
+#include "arch/alpha/tlb.hh"
+#include "arch/vtophys.hh"
+#include "base/callback.hh"
+//#include "base/remote_gdb.hh"
+#include "cpu/profile.hh"
+#include "kern/kernel_stats.hh"
+#include "sim/faults.hh"
+#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
+#include "sim/system.hh"
+#else // !FULL_SYSTEM
+#include "sim/process.hh"
+#endif // FULL_SYSTEM
+
+#if USE_CHECKER
+#include "cpu/checker/thread_context.hh"
+#endif
+
+using namespace TheISA;
+
+template <class Impl>
+template<typename T>
+void
+OzoneCPU<Impl>::trace_data(T data) {
+ if (traceData) {
+ traceData->setData(data);
+ }
+}
+
+template <class Impl>
+OzoneCPU<Impl>::TickEvent::TickEvent(OzoneCPU *c, int w)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cpu(c), width(w)
+{
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::TickEvent::process()
+{
+ cpu->tick();
+}
+
+template <class Impl>
+const char *
+OzoneCPU<Impl>::TickEvent::description()
+{
+ return "OzoneCPU tick event";
+}
+
+template <class Impl>
+OzoneCPU<Impl>::OzoneCPU(Params *p)
+#if FULL_SYSTEM
+ : BaseCPU(p), thread(this, 0), tickEvent(this, p->width),
+#else
+ : BaseCPU(p), thread(this, 0, p->workload[0], 0, p->mem),
+ tickEvent(this, p->width),
+#endif
+ mem(p->mem), comm(5, 5)
+{
+ frontEnd = new FrontEnd(p);
+ backEnd = new BackEnd(p);
+
+ _status = Idle;
+
+ if (p->checker) {
+#if USE_CHECKER
+ BaseCPU *temp_checker = p->checker;
+ checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
+ checker->setMemory(mem);
+#if FULL_SYSTEM
+ checker->setSystem(p->system);
+#endif
+ checkerTC = new CheckerThreadContext<OzoneTC>(&ozoneTC, checker);
+ thread.tc = checkerTC;
+ tc = checkerTC;
+#else
+ panic("Checker enabled but not compiled in!");
+#endif
+ } else {
+ checker = NULL;
+ thread.tc = &ozoneTC;
+ tc = &ozoneTC;
+ }
+
+ ozoneTC.cpu = this;
+ ozoneTC.thread = &thread;
+
+ thread.inSyscall = false;
+
+ thread.setStatus(ThreadContext::Suspended);
+#if FULL_SYSTEM
+ /***** All thread state stuff *****/
+ thread.cpu = this;
+ thread.setTid(0);
+
+ thread.quiesceEvent = new EndQuiesceEvent(tc);
+
+ system = p->system;
+ itb = p->itb;
+ dtb = p->dtb;
+ physmem = p->system->physmem;
+
+ if (p->profile) {
+ thread.profile = new FunctionProfile(p->system->kernelSymtab);
+ // @todo: This might be better as an ThreadContext instead of OzoneTC
+ Callback *cb =
+ new MakeCallback<OzoneTC,
+ &OzoneTC::dumpFuncProfile>(&ozoneTC);
+ registerExitCallback(cb);
+ }
+
+ // let's fill with a dummy node for now so we don't get a segfault
+ // on the first cycle when there's no node available.
+ static ProfileNode dummyNode;
+ thread.profileNode = &dummyNode;
+ thread.profilePC = 3;
+#else
+ thread.cpu = this;
+#endif // !FULL_SYSTEM
+
+ numInst = 0;
+ startNumInst = 0;
+
+ threadContexts.push_back(tc);
+
+ frontEnd->setCPU(this);
+ backEnd->setCPU(this);
+
+ frontEnd->setTC(tc);
+ backEnd->setTC(tc);
+
+ frontEnd->setThreadState(&thread);
+ backEnd->setThreadState(&thread);
-#include "arch/isa_traits.hh"
+ frontEnd->setCommBuffer(&comm);
+ backEnd->setCommBuffer(&comm);
+
+ frontEnd->setBackEnd(backEnd);
+ backEnd->setFrontEnd(frontEnd);
+
+ decoupledFrontEnd = p->decoupledFrontEnd;
+
+ globalSeqNum = 1;
+
+ checkInterrupts = false;
+
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ thread.renameTable[i] = new DynInst(this);
+ thread.renameTable[i]->setResultReady();
+ }
+
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+#if !FULL_SYSTEM
+ /* Use this port to for syscall emulation writes to memory. */
+ Port *mem_port;
+ TranslatingPort *trans_port;
+ trans_port = new TranslatingPort(csprintf("%s-%d-funcport",
+ name(), 0),
+ p->workload[0]->pTable,
+ false);
+ mem_port = p->mem->getPort("functional");
+ mem_port->setPeer(trans_port);
+ trans_port->setPeer(mem_port);
+ thread.setMemPort(trans_port);
+#else
+ Port *mem_port;
+ FunctionalPort *phys_port;
+ VirtualPort *virt_port;
+ phys_port = new FunctionalPort(csprintf("%s-%d-funcport",
+ name(), 0));
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(phys_port);
+ phys_port->setPeer(mem_port);
+
+ virt_port = new VirtualPort(csprintf("%s-%d-vport",
+ name(), 0));
+ mem_port = system->physmem->getPort("functional");
+ mem_port->setPeer(virt_port);
+ virt_port->setPeer(mem_port);
+
+ thread.setPhysPort(phys_port);
+ thread.setVirtPort(virt_port);
+#endif
+
+ lockFlag = 0;
+
+ DPRINTF(OzoneCPU, "OzoneCPU: Created Ozone cpu object.\n");
+}
+
+template <class Impl>
+OzoneCPU<Impl>::~OzoneCPU()
+{
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::switchOut(Sampler *_sampler)
+{
+ sampler = _sampler;
+ switchCount = 0;
+ // Front end needs state from back end, so switch out the back end first.
+ backEnd->switchOut();
+ frontEnd->switchOut();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::signalSwitched()
+{
+ if (++switchCount == 2) {
+ backEnd->doSwitchOut();
+ frontEnd->doSwitchOut();
+#if USE_CHECKER
+ if (checker)
+ checker->switchOut(sampler);
+#endif
+
+ _status = SwitchedOut;
+ if (tickEvent.scheduled())
+ tickEvent.squash();
+ sampler->signalSwitched();
+ }
+ assert(switchCount <= 2);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::takeOverFrom(BaseCPU *oldCPU)
+{
+ BaseCPU::takeOverFrom(oldCPU);
+
+ backEnd->takeOverFrom();
+ frontEnd->takeOverFrom();
+ assert(!tickEvent.scheduled());
+
+ // @todo: Fix hardcoded number
+ // Clear out any old information in time buffer.
+ for (int i = 0; i < 6; ++i) {
+ comm.advance();
+ }
+
+ // if any of this CPU's ThreadContexts are active, mark the CPU as
+ // running and schedule its tick event.
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active &&
+ _status != Running) {
+ _status = Running;
+ tickEvent.schedule(curTick);
+ }
+ }
+ // Nothing running, change status to reflect that we're no longer
+ // switched out.
+ if (_status == SwitchedOut) {
+ _status = Idle;
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::activateContext(int thread_num, int delay)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+
+ assert(_status == Idle);
+ notIdleFraction++;
+ scheduleTickEvent(delay);
+ _status = Running;
+ thread.setStatus(ThreadContext::Active);
+ frontEnd->wakeFromQuiesce();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::suspendContext(int thread_num)
+{
+ // Eventually change this in SMT.
+ assert(thread_num == 0);
+ // @todo: Figure out how to initially set the status properly so
+ // this is running.
+// assert(_status == Running);
+ notIdleFraction--;
+ unscheduleTickEvent();
+ _status = Idle;
+}
template <class Impl>
-class OoOCPU;
+void
+OzoneCPU<Impl>::deallocateContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::haltContext(int thread_num)
+{
+ // for now, these are equivalent
+ suspendContext(thread_num);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::regStats()
+{
+ using namespace Stats;
+
+ BaseCPU::regStats();
+
+ thread.numInsts
+ .name(name() + ".num_insts")
+ .desc("Number of instructions executed")
+ ;
+
+ thread.numMemRefs
+ .name(name() + ".num_refs")
+ .desc("Number of memory references")
+ ;
+
+ notIdleFraction
+ .name(name() + ".not_idle_fraction")
+ .desc("Percentage of non-idle cycles")
+ ;
+
+ idleFraction
+ .name(name() + ".idle_fraction")
+ .desc("Percentage of idle cycles")
+ ;
+
+ quiesceCycles
+ .name(name() + ".quiesce_cycles")
+ .desc("Number of cycles spent in quiesce")
+ ;
+
+ idleFraction = constant(1.0) - notIdleFraction;
+
+ frontEnd->regStats();
+ backEnd->regStats();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::resetStats()
+{
+ startNumInst = numInst;
+ notIdleFraction = (_status != Idle);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::init()
+{
+ BaseCPU::init();
+
+ // Mark this as in syscall so it won't need to squash
+ thread.inSyscall = true;
+#if FULL_SYSTEM
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+
+ // initialize CPU, including PC
+ TheISA::initCPU(tc, tc->readCpuId());
+ }
+#endif
+ frontEnd->renameTable.copyFrom(thread.renameTable);
+ backEnd->renameTable.copyFrom(thread.renameTable);
+
+ thread.inSyscall = false;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::serialize(std::ostream &os)
+{
+ BaseCPU::serialize(os);
+ SERIALIZE_ENUM(_status);
+ nameOut(os, csprintf("%s.tc", name()));
+ ozoneTC.serialize(os);
+ nameOut(os, csprintf("%s.tickEvent", name()));
+ tickEvent.serialize(os);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
+{
+ BaseCPU::unserialize(cp, section);
+ UNSERIALIZE_ENUM(_status);
+ ozoneTC.unserialize(cp, csprintf("%s.tc", section));
+ tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::copySrcTranslate(Addr src)
+{
+ panic("Copy not implemented!\n");
+ return NoFault;
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ int offset = src & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (src & TheISA::PageMask) != ((src + blk_size) & TheISA::PageMask) &&
+ (src >> 40) != 0xfffffc) {
+ warn("Copied block source spans pages %x.", src);
+ no_warn = false;
+ }
+
+ memReq->reset(src & ~(blk_size - 1), blk_size);
+
+ // translate to physical address
+ Fault fault = tc->translateDataReadReq(memReq);
+
+ assert(fault != Alignment_Fault);
+
+ if (fault == NoFault) {
+ tc->copySrcAddr = src;
+ tc->copySrcPhysAddr = memReq->paddr + offset;
+ } else {
+ tc->copySrcAddr = 0;
+ tc->copySrcPhysAddr = 0;
+ }
+ return fault;
+#endif
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::copy(Addr dest)
+{
+ panic("Copy not implemented!\n");
+ return NoFault;
+#if 0
+ static bool no_warn = true;
+ int blk_size = (dcacheInterface) ? dcacheInterface->getBlockSize() : 64;
+ // Only support block sizes of 64 atm.
+ assert(blk_size == 64);
+ uint8_t data[blk_size];
+ //assert(tc->copySrcAddr);
+ int offset = dest & (blk_size - 1);
+
+ // Make sure block doesn't span page
+ if (no_warn &&
+ (dest & TheISA::PageMask) != ((dest + blk_size) & TheISA::PageMask) &&
+ (dest >> 40) != 0xfffffc) {
+ no_warn = false;
+ warn("Copied block destination spans pages %x. ", dest);
+ }
+
+ memReq->reset(dest & ~(blk_size -1), blk_size);
+ // translate to physical address
+ Fault fault = tc->translateDataWriteReq(memReq);
+
+ assert(fault != Alignment_Fault);
+
+ if (fault == NoFault) {
+ Addr dest_addr = memReq->paddr + offset;
+ // Need to read straight from memory since we have more than 8 bytes.
+ memReq->paddr = tc->copySrcPhysAddr;
+ tc->mem->read(memReq, data);
+ memReq->paddr = dest_addr;
+ tc->mem->write(memReq, data);
+ if (dcacheInterface) {
+ memReq->cmd = Copy;
+ memReq->completionEvent = NULL;
+ memReq->paddr = tc->copySrcPhysAddr;
+ memReq->dest = dest_addr;
+ memReq->size = 64;
+ memReq->time = curTick;
+ dcacheInterface->access(memReq);
+ }
+ }
+ return fault;
+#endif
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+Addr
+OzoneCPU<Impl>::dbg_vtophys(Addr addr)
+{
+ return vtophys(tc, addr);
+}
+#endif // FULL_SYSTEM
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::post_interrupt(int int_num, int index)
+{
+ BaseCPU::post_interrupt(int_num, index);
+
+ if (_status == Idle) {
+ DPRINTF(IPI,"Suspended Processor awoke\n");
+// 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);
+ }
+}
+#endif // FULL_SYSTEM
+
+/* start simulation, program loaded, processor precise state initialized */
+template <class Impl>
+void
+OzoneCPU<Impl>::tick()
+{
+ DPRINTF(OzoneCPU, "\n\nOzoneCPU: Ticking cpu.\n");
+
+ _status = Running;
+ thread.renameTable[ZeroReg]->setIntResult(0);
+ thread.renameTable[ZeroReg+TheISA::FP_Base_DepTag]->
+ setDoubleResult(0.0);
+
+ comm.advance();
+ frontEnd->tick();
+ backEnd->tick();
+
+ // check for instruction-count-based events
+ comInstEventQueue[0]->serviceEvents(numInst);
+
+ if (!tickEvent.scheduled() && _status == Running)
+ tickEvent.schedule(curTick + cycles(1));
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::squashFromTC()
+{
+ thread.inSyscall = true;
+ backEnd->generateTCEvent();
+}
+
+#if !FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::syscall(uint64_t &callnum)
+{
+ // Not sure this copy is needed, depending on how the TC proxy is made.
+ thread.renameTable.copyFrom(backEnd->renameTable);
+
+ thread.inSyscall = true;
+
+ thread.funcExeInst++;
+
+ DPRINTF(OzoneCPU, "FuncExeInst: %i\n", thread.funcExeInst);
+
+ thread.process->syscall(callnum, tc);
+
+ thread.funcExeInst--;
+
+ thread.inSyscall = false;
+
+ 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
+OzoneCPU<Impl>::hwrei()
+{
+ // Need to move this to ISA code
+ // May also need to make this per thread
+
+ lockFlag = false;
+ lockAddrList.clear();
+ thread.kernelStats->hwrei();
+
+ checkInterrupts = true;
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::processInterrupts()
+{
+ // Check for interrupts here. For now can copy the code that
+ // exists within isa_fullsys_traits.hh. Also assume that thread 0
+ // is the one that handles the interrupts.
+
+ // Check if there are any outstanding interrupts
+ //Handle the interrupts
+ int ipl = 0;
+ int summary = 0;
+
+ checkInterrupts = false;
+
+ if (thread.readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (thread.readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (thread.readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = intr_status();
+
+ if (interrupts) {
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ if (ipl && ipl > thread.readMiscReg(IPR_IPLR)) {
+ thread.setMiscReg(IPR_ISR, summary);
+ thread.setMiscReg(IPR_INTID, ipl);
+ // @todo: Make this more transparent
+ if (checker) {
+ checker->threadBase()->setMiscReg(IPR_ISR, summary);
+ checker->threadBase()->setMiscReg(IPR_INTID, ipl);
+ }
+ Fault fault = new InterruptFault;
+ fault->invoke(thread.getTC());
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ thread.readMiscReg(IPR_IPLR), ipl, summary);
+ }
+}
+
+template <class Impl>
+bool
+OzoneCPU<Impl>::simPalCheck(int palFunc)
+{
+ // Need to move this to ISA code
+ // May also need to make this per thread
+ thread.kernelStats->callpal(palFunc, tc);
+
+ switch (palFunc) {
+ case PAL::halt:
+ haltContext(thread.readTid());
+ if (--System::numSystemsRunning == 0)
+ exitSimLoop("all cpus halted");
+ break;
+
+ case PAL::bpt:
+ case PAL::bugchk:
+ if (system->breakpoint())
+ return false;
+ break;
+ }
+
+ return true;
+}
+#endif
+
+template <class Impl>
+BaseCPU *
+OzoneCPU<Impl>::OzoneTC::getCpuPtr()
+{
+ return cpu;
+}
+
+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)
+{
+ delete vp->getPeer();
+ delete vp;
+}
+#endif
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setStatus(Status new_status)
+{
+ thread->setStatus(new_status);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::activate(int delay)
+{
+ cpu->activateContext(thread->readTid(), delay);
+}
+
+/// Set the status to Suspended.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::suspend()
+{
+ cpu->suspendContext(thread->readTid());
+}
+
+/// Set the status to Unallocated.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::deallocate()
+{
+ cpu->deallocateContext(thread->readTid());
+}
+
+/// Set the status to Halted.
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::halt()
+{
+ cpu->haltContext(thread->readTid());
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::dumpFuncProfile()
+{ }
+#endif
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::takeOverFrom(ThreadContext *old_context)
+{
+ // some things should already be set up
+#if FULL_SYSTEM
+ assert(getSystemPtr() == old_context->getSystemPtr());
+#else
+ assert(getProcessPtr() == old_context->getProcessPtr());
+#endif
+
+ // copy over functional state
+ setStatus(old_context->status());
+ copyArchRegs(old_context);
+ setCpuId(old_context->readCpuId());
+
+#if !FULL_SYSTEM
+ setFuncExeInst(old_context->readFuncExeInst());
+#else
+ EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
+ if (other_quiesce) {
+ // Point the quiesce event's TC at this TC so that it wakes up
+ // the proper CPU.
+ other_quiesce->tc = this;
+ }
+ if (thread->quiesceEvent) {
+ thread->quiesceEvent->tc = this;
+ }
+
+ thread->kernelStats = old_context->getKernelStats();
+// storeCondFailures = 0;
+ cpu->lockFlag = false;
+#endif
+
+ old_context->setStatus(ThreadContext::Unallocated);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::regStats(const std::string &name)
+{
+#if FULL_SYSTEM
+ thread->kernelStats = new Kernel::Statistics(cpu->system);
+ thread->kernelStats->regStats(name + ".kern");
+#endif
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::serialize(std::ostream &os)
+{ }
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::unserialize(Checkpoint *cp, const std::string &section)
+{ }
+
+#if FULL_SYSTEM
+template <class Impl>
+EndQuiesceEvent *
+OzoneCPU<Impl>::OzoneTC::getQuiesceEvent()
+{
+ return thread->quiesceEvent;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneTC::readLastActivate()
+{
+ return thread->lastActivate;
+}
+
+template <class Impl>
+Tick
+OzoneCPU<Impl>::OzoneTC::readLastSuspend()
+{
+ return thread->lastSuspend;
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::profileClear()
+{
+ if (thread->profile)
+ thread->profile->clear();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::profileSample()
+{
+ if (thread->profile)
+ thread->profile->sample(thread->profileNode, thread->profilePC);
+}
+#endif
+
+template <class Impl>
+int
+OzoneCPU<Impl>::OzoneTC::getThreadNum()
+{
+ return thread->readTid();
+}
+
+// Also somewhat obnoxious. Really only used for the TLB fault.
+template <class Impl>
+TheISA::MachInst
+OzoneCPU<Impl>::OzoneTC::getInst()
+{
+ return thread->getInst();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::copyArchRegs(ThreadContext *tc)
+{
+ thread->PC = tc->readPC();
+ thread->nextPC = tc->readNextPC();
+
+ cpu->frontEnd->setPC(thread->PC);
+ cpu->frontEnd->setNextPC(thread->nextPC);
+
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ if (i < TheISA::FP_Base_DepTag) {
+ thread->renameTable[i]->setIntResult(tc->readIntReg(i));
+ } else if (i < (TheISA::FP_Base_DepTag + TheISA::NumFloatRegs)) {
+ int fp_idx = i - TheISA::FP_Base_DepTag;
+ thread->renameTable[i]->setDoubleResult(
+ tc->readFloatReg(fp_idx, 64));
+ }
+ }
+
+#if !FULL_SYSTEM
+ thread->funcExeInst = tc->readFuncExeInst();
+#endif
+
+ // Need to copy the TC values into the current rename table,
+ // copy the misc regs.
+ copyMiscRegs(tc, this);
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::clearArchRegs()
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readIntReg(int reg_idx)
+{
+ return thread->renameTable[reg_idx]->readIntResult();
+}
+
+template <class Impl>
+TheISA::FloatReg
+OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ switch(width) {
+ case 32:
+ return thread->renameTable[idx]->readFloatResult();
+ case 64:
+ return thread->renameTable[idx]->readDoubleResult();
+ default:
+ panic("Unsupported width!");
+ return 0;
+ }
+}
+
+template <class Impl>
+double
+OzoneCPU<Impl>::OzoneTC::readFloatReg(int reg_idx)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readFloatResult();
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readIntResult();
+}
+
+template <class Impl>
+uint64_t
+OzoneCPU<Impl>::OzoneTC::readFloatRegBits(int reg_idx)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ return thread->renameTable[idx]->readIntResult();
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setIntReg(int reg_idx, uint64_t val)
+{
+ thread->renameTable[reg_idx]->setIntResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val, int width)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+ switch(width) {
+ case 32:
+ panic("Unimplemented!");
+ break;
+ case 64:
+ thread->renameTable[idx]->setDoubleResult(val);
+ break;
+ default:
+ panic("Unsupported width!");
+ }
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatReg(int reg_idx, FloatReg val)
+{
+ int idx = reg_idx + TheISA::FP_Base_DepTag;
+
+ thread->renameTable[idx]->setDoubleResult(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val,
+ int width)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setFloatRegBits(int reg_idx, FloatRegBits val)
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setPC(Addr val)
+{
+ thread->PC = val;
+ cpu->frontEnd->setPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+void
+OzoneCPU<Impl>::OzoneTC::setNextPC(Addr val)
+{
+ thread->nextPC = val;
+ cpu->frontEnd->setNextPC(val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneTC::readMiscReg(int misc_reg)
+{
+ return thread->miscRegFile.readReg(misc_reg);
+}
+
+template <class Impl>
+TheISA::MiscReg
+OzoneCPU<Impl>::OzoneTC::readMiscRegWithEffect(int misc_reg, Fault &fault)
+{
+ return thread->miscRegFile.readRegWithEffect(misc_reg,
+ fault, this);
+}
+
+template <class Impl>
+Fault
+OzoneCPU<Impl>::OzoneTC::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->miscRegFile.setReg(misc_reg, val);
+
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
+
+ return ret_fault;
+}
template <class Impl>
-class OoODynInst;
+Fault
+OzoneCPU<Impl>::OzoneTC::setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+{
+ // Needs to setup a squash event unless we're in syscall mode
+ Fault ret_fault = thread->miscRegFile.setRegWithEffect(misc_reg, val,
+ this);
-struct OoOImpl {
- typedef AlphaISA ISA;
- typedef OoOCPU<OoOImpl> OoOCPU;
- typedef OoOCPU FullCPU;
- typedef OoODynInst<OoOImpl> DynInst;
- typedef RefCountingPtr<DynInst> DynInstPtr;
-};
+ if (!thread->inSyscall) {
+ cpu->squashFromTC();
+ }
-#endif // __CPU_OOO_CPU_OOO_IMPL_HH__
+ return ret_fault;
+}
diff --git a/src/cpu/ozone/dyn_inst.cc b/src/cpu/ozone/dyn_inst.cc
new file mode 100644
index 000000000..732fb96b8
--- /dev/null
+++ b/src/cpu/ozone/dyn_inst.cc
@@ -0,0 +1,37 @@
+/*
+ * 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: Kevin Lim
+ */
+
+#include "cpu/ozone/dyn_inst_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+//#include "cpu/ozone/simple_impl.hh"
+
+template class OzoneDynInst<OzoneImpl>;
+//template class OzoneDynInst<SimpleImpl>;
+
diff --git a/src/cpu/ozone/dyn_inst.hh b/src/cpu/ozone/dyn_inst.hh
new file mode 100644
index 000000000..67691d416
--- /dev/null
+++ b/src/cpu/ozone/dyn_inst.hh
@@ -0,0 +1,253 @@
+/*
+ * 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: Kevin Lim
+ */
+
+#ifndef __CPU_OZONE_DYN_INST_HH__
+#define __CPU_OZONE_DYN_INST_HH__
+
+#include "arch/isa_traits.hh"
+#include "config/full_system.hh"
+#include "cpu/base_dyn_inst.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/cpu.hh" // MUST include this
+#include "cpu/ozone/ozone_impl.hh"
+
+#include <list>
+#include <vector>
+
+template <class Impl>
+class OzoneDynInst : public BaseDynInst<Impl>
+{
+ public:
+ // Typedefs
+ typedef typename Impl::OzoneCPU OzoneCPU;
+
+ typedef typename OzoneCPU::ImplState ImplState;
+
+ // Typedef for DynInstPtr. This is really just a RefCountingPtr<OoODynInst>.
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ typedef TheISA::ExtMachInst ExtMachInst;
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscReg MiscReg;
+ typedef typename std::list<DynInstPtr>::iterator ListIt;
+
+ // Note that this is duplicated from the BaseDynInst class; I'm
+ // simply not sure the enum would carry through so I could use it
+ // in array declarations in this class.
+ enum {
+ MaxInstSrcRegs = TheISA::MaxInstSrcRegs,
+ MaxInstDestRegs = TheISA::MaxInstDestRegs
+ };
+
+ OzoneDynInst(OzoneCPU *cpu);
+
+ OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC,
+ InstSeqNum seq_num, OzoneCPU *cpu);
+
+ OzoneDynInst(StaticInstPtr inst);
+
+ ~OzoneDynInst();
+
+ void setSrcInst(DynInstPtr &newSrcInst, int regIdx)
+ { srcInsts[regIdx] = newSrcInst; }
+
+ bool srcInstReady(int regIdx);
+
+ void setPrevDestInst(DynInstPtr &oldDestInst, int regIdx)
+ { prevDestInst[regIdx] = oldDestInst; }
+
+ DynInstPtr &getPrevDestInst(int regIdx)
+ { return prevDestInst[regIdx]; }
+
+ void addDependent(DynInstPtr &dependent_inst);
+
+ std::vector<DynInstPtr> &getDependents() { return dependents; }
+ std::vector<DynInstPtr> &getMemDeps() { return memDependents; }
+ std::list<DynInstPtr> &getMemSrcs() { return srcMemInsts; }
+
+ void wakeDependents();
+
+ void wakeMemDependents();
+
+ void addMemDependent(DynInstPtr &inst) { memDependents.push_back(inst); }
+
+ void addSrcMemInst(DynInstPtr &inst) { srcMemInsts.push_back(inst); }
+
+ void markMemInstReady(OzoneDynInst<Impl> *inst);
+
+ // For now I will remove instructions from the list when they wake
+ // up. In the future, you only really need a counter.
+ bool memDepReady() { return srcMemInsts.empty(); }
+
+ private:
+ void initInstPtrs();
+
+ std::vector<DynInstPtr> dependents;
+
+ std::vector<DynInstPtr> memDependents;
+
+ std::list<DynInstPtr> srcMemInsts;
+
+ /** The instruction that produces the value of the source
+ * registers. These may be NULL if the value has already been
+ * read from the source instruction.
+ */
+ DynInstPtr srcInsts[MaxInstSrcRegs];
+
+ /**
+ * Previous rename instruction for this destination.
+ */
+ DynInstPtr prevDestInst[MaxInstSrcRegs];
+
+ public:
+
+ Fault initiateAcc();
+
+ Fault completeAcc(Packet *pkt);
+
+ // The register accessor methods provide the index of the
+ // instruction's operand (e.g., 0 or 1), not the architectural
+ // register index, to simplify the implementation of register
+ // renaming. We find the architectural register index by indexing
+ // into the instruction's own operand index table. Note that a
+ // raw pointer to the StaticInst is provided instead of a
+ // ref-counted StaticInstPtr to redice overhead. This is fine as
+ // long as these methods don't copy the pointer into any long-term
+ // storage (which is pretty hard to imagine they would have reason
+ // to do).
+
+ uint64_t readIntReg(const StaticInst *si, int idx)
+ {
+ return srcInsts[idx]->readIntResult();
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx, int width)
+ {
+ switch(width) {
+ case 32:
+ return srcInsts[idx]->readFloatResult();
+ case 64:
+ return srcInsts[idx]->readDoubleResult();
+ default:
+ panic("Width not supported");
+ return 0;
+ }
+ }
+
+ FloatReg readFloatReg(const StaticInst *si, int idx)
+ {
+ return srcInsts[idx]->readFloatResult();
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width)
+ {
+ return srcInsts[idx]->readIntResult();
+ }
+
+ FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
+ {
+ return srcInsts[idx]->readIntResult();
+ }
+
+ /** @todo: Make results into arrays so they can handle multiple dest
+ * registers.
+ */
+ void setIntReg(const StaticInst *si, int idx, uint64_t val)
+ {
+ BaseDynInst<Impl>::setIntReg(si, idx, val);
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
+ {
+ BaseDynInst<Impl>::setFloatReg(si, idx, val, width);
+ }
+
+ void setFloatReg(const StaticInst *si, int idx, FloatReg val)
+ {
+ BaseDynInst<Impl>::setFloatReg(si, idx, val);
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx,
+ FloatRegBits val, int width)
+ {
+ BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
+ }
+
+ void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
+ {
+ BaseDynInst<Impl>::setFloatRegBits(si, idx, val);
+ }
+
+ void setIntResult(uint64_t result) { this->instResult.integer = result; }
+ void setDoubleResult(double result) { this->instResult.dbl = result; }
+
+ bool srcsReady();
+ bool eaSrcsReady();
+
+ Fault execute();
+
+ Fault executeEAComp()
+ { return NoFault; }
+
+ Fault executeMemAcc()
+ { return this->staticInst->memAccInst()->execute(this, this->traceData); }
+
+ void clearDependents();
+
+ void clearMemDependents();
+
+ public:
+ // ISA stuff
+ MiscReg readMiscReg(int misc_reg);
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault);
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val);
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val);
+
+#if FULL_SYSTEM
+ Fault hwrei();
+ int readIntrFlag();
+ void setIntrFlag(int val);
+ bool inPalMode();
+ void trap(Fault fault);
+ bool simPalCheck(int palFunc);
+#else
+ void syscall(uint64_t &callnum);
+#endif
+
+ ListIt iqIt;
+ bool iqItValid;
+};
+
+#endif // __CPU_OZONE_DYN_INST_HH__
diff --git a/src/cpu/ozone/dyn_inst_impl.hh b/src/cpu/ozone/dyn_inst_impl.hh
new file mode 100644
index 000000000..bad902c2a
--- /dev/null
+++ b/src/cpu/ozone/dyn_inst_impl.hh
@@ -0,0 +1,307 @@
+/*
+ * 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: Kevin Lim
+ */
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "config/full_system.hh"
+#include "cpu/ozone/dyn_inst.hh"
+#include "kern/kernel_stats.hh"
+
+using namespace TheISA;
+
+template <class Impl>
+OzoneDynInst<Impl>::OzoneDynInst(OzoneCPU *cpu)
+ : BaseDynInst<Impl>(0, 0, 0, 0, cpu)
+{
+ this->setResultReady();
+
+ initInstPtrs();
+}
+
+template <class Impl>
+OzoneDynInst<Impl>::OzoneDynInst(ExtMachInst inst, Addr PC, Addr Pred_PC,
+ InstSeqNum seq_num, OzoneCPU *cpu)
+ : BaseDynInst<Impl>(inst, PC, Pred_PC, seq_num, cpu)
+{
+ initInstPtrs();
+}
+
+template <class Impl>
+OzoneDynInst<Impl>::OzoneDynInst(StaticInstPtr _staticInst)
+ : BaseDynInst<Impl>(_staticInst)
+{
+ initInstPtrs();
+}
+
+template <class Impl>
+OzoneDynInst<Impl>::~OzoneDynInst()
+{
+ DPRINTF(BE, "[sn:%lli] destructor called\n", this->seqNum);
+ for (int i = 0; i < this->numSrcRegs(); ++i) {
+ srcInsts[i] = NULL;
+ }
+
+ for (int i = 0; i < this->numDestRegs(); ++i) {
+ prevDestInst[i] = NULL;
+ }
+
+ dependents.clear();
+}
+
+template <class Impl>
+Fault
+OzoneDynInst<Impl>::execute()
+{
+ // @todo: Pretty convoluted way to avoid squashing from happening when using
+ // the XC during an instruction's execution (specifically for instructions
+ // that have sideeffects that use the XC). 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
+OzoneDynInst<Impl>::initiateAcc()
+{
+ // @todo: Pretty convoluted way to avoid squashing from happening when using
+ // the XC during an instruction's execution (specifically for instructions
+ // that have sideeffects that use the XC). 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
+OzoneDynInst<Impl>::completeAcc(Packet *pkt)
+{
+ this->fault = this->staticInst->completeAcc(pkt, this, this->traceData);
+
+ return this->fault;
+}
+
+template <class Impl>
+bool
+OzoneDynInst<Impl>::srcInstReady(int regIdx)
+{
+ return srcInsts[regIdx]->isResultReady();
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::addDependent(DynInstPtr &dependent_inst)
+{
+ dependents.push_back(dependent_inst);
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::wakeDependents()
+{
+ for (int i = 0; i < dependents.size(); ++i) {
+ dependents[i]->markSrcRegReady();
+ }
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::wakeMemDependents()
+{
+ for (int i = 0; i < memDependents.size(); ++i) {
+ memDependents[i]->markMemInstReady(this);
+ }
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::markMemInstReady(OzoneDynInst<Impl> *inst)
+{
+ ListIt mem_it = srcMemInsts.begin();
+ while ((*mem_it) != inst && mem_it != srcMemInsts.end()) {
+ mem_it++;
+ }
+ assert(mem_it != srcMemInsts.end());
+
+ srcMemInsts.erase(mem_it);
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::initInstPtrs()
+{
+ for (int i = 0; i < MaxInstSrcRegs; ++i) {
+ srcInsts[i] = NULL;
+ }
+ iqItValid = false;
+}
+
+template <class Impl>
+bool
+OzoneDynInst<Impl>::srcsReady()
+{
+ for (int i = 0; i < this->numSrcRegs(); ++i) {
+ if (!srcInsts[i]->isResultReady())
+ return false;
+ }
+
+ return true;
+}
+
+template <class Impl>
+bool
+OzoneDynInst<Impl>::eaSrcsReady()
+{
+ for (int i = 1; i < this->numSrcRegs(); ++i) {
+ if (!srcInsts[i]->isResultReady())
+ return false;
+ }
+
+ return true;
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::clearDependents()
+{
+ dependents.clear();
+ for (int i = 0; i < this->numSrcRegs(); ++i) {
+ srcInsts[i] = NULL;
+ }
+ for (int i = 0; i < this->numDestRegs(); ++i) {
+ prevDestInst[i] = NULL;
+ }
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::clearMemDependents()
+{
+ memDependents.clear();
+}
+
+template <class Impl>
+MiscReg
+OzoneDynInst<Impl>::readMiscReg(int misc_reg)
+{
+ return this->thread->readMiscReg(misc_reg);
+}
+
+template <class Impl>
+MiscReg
+OzoneDynInst<Impl>::readMiscRegWithEffect(int misc_reg, Fault &fault)
+{
+ return this->thread->readMiscRegWithEffect(misc_reg, fault);
+}
+
+template <class Impl>
+Fault
+OzoneDynInst<Impl>::setMiscReg(int misc_reg, const MiscReg &val)
+{
+ this->setIntResult(val);
+ return this->thread->setMiscReg(misc_reg, val);
+}
+
+template <class Impl>
+Fault
+OzoneDynInst<Impl>::setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+{
+ return this->thread->setMiscRegWithEffect(misc_reg, val);
+}
+
+#if FULL_SYSTEM
+
+template <class Impl>
+Fault
+OzoneDynInst<Impl>::hwrei()
+{
+ if (!this->cpu->inPalMode(this->readPC()))
+ return new AlphaISA::UnimplementedOpcodeFault;
+
+ this->setNextPC(this->thread->readMiscReg(AlphaISA::IPR_EXC_ADDR));
+
+ this->cpu->hwrei();
+
+ // FIXME: XXX check for interrupts? XXX
+ return NoFault;
+}
+
+template <class Impl>
+int
+OzoneDynInst<Impl>::readIntrFlag()
+{
+return this->cpu->readIntrFlag();
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::setIntrFlag(int val)
+{
+ this->cpu->setIntrFlag(val);
+}
+
+template <class Impl>
+bool
+OzoneDynInst<Impl>::inPalMode()
+{
+ return this->cpu->inPalMode();
+}
+
+template <class Impl>
+void
+OzoneDynInst<Impl>::trap(Fault fault)
+{
+ fault->invoke(this->thread->getTC());
+}
+
+template <class Impl>
+bool
+OzoneDynInst<Impl>::simPalCheck(int palFunc)
+{
+ return this->cpu->simPalCheck(palFunc);
+}
+#else
+template <class Impl>
+void
+OzoneDynInst<Impl>::syscall(uint64_t &callnum)
+{
+ this->cpu->syscall(callnum);
+}
+#endif
diff --git a/src/cpu/ozone/ea_list.cc b/src/cpu/ozone/ea_list.cc
index 6114a0ca1..5ef240700 100644
--- a/src/cpu/ozone/ea_list.cc
+++ b/src/cpu/ozone/ea_list.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#include "arch/isa_traits.hh"
diff --git a/src/cpu/ozone/ea_list.hh b/src/cpu/ozone/ea_list.hh
index c0eee4bb8..64882632c 100644
--- a/src/cpu/ozone/ea_list.hh
+++ b/src/cpu/ozone/ea_list.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __CPU_EA_LIST_HH__
diff --git a/src/cpu/ozone/front_end.cc b/src/cpu/ozone/front_end.cc
new file mode 100644
index 000000000..cfd033564
--- /dev/null
+++ b/src/cpu/ozone/front_end.cc
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/front_end_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+//#include "cpu/ozone/simple_impl.hh"
+
+template class FrontEnd<OzoneImpl>;
+//template class FrontEnd<SimpleImpl>;
diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh
new file mode 100644
index 000000000..181609098
--- /dev/null
+++ b/src/cpu/ozone/front_end.hh
@@ -0,0 +1,318 @@
+/*
+ * 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_OZONE_FRONT_END_HH__
+#define __CPU_OZONE_FRONT_END_HH__
+
+#include <deque>
+
+#include "arch/utility.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/o3/bpred_unit.hh"
+#include "cpu/ozone/rename_table.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+#include "sim/stats.hh"
+
+class ThreadContext;
+class MemObject;
+template <class>
+class OzoneThreadState;
+class PageTable;
+template <class>
+class TimeBuffer;
+
+template <class Impl>
+class FrontEnd
+{
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInst DynInst;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::CPUType CPUType;
+ typedef typename Impl::BackEnd BackEnd;
+
+ typedef typename Impl::CPUType::OzoneTC OzoneTC;
+ typedef typename Impl::CPUType::CommStruct CommStruct;
+
+ /** IcachePort class. Handles doing the communication with the
+ * cache/memory.
+ */
+ class IcachePort : public Port
+ {
+ protected:
+ /** Pointer to FE. */
+ FrontEnd<Impl> *fe;
+
+ public:
+ /** Default constructor. */
+ IcachePort(FrontEnd<Impl> *_fe)
+ : fe(_fe)
+ { }
+
+ 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();
+ };
+
+ FrontEnd(Params *params);
+
+ std::string name() const;
+
+ void setCPU(CPUType *cpu_ptr);
+
+ void setBackEnd(BackEnd *back_end_ptr)
+ { backEnd = back_end_ptr; }
+
+ void setCommBuffer(TimeBuffer<CommStruct> *_comm);
+
+ void setTC(ThreadContext *tc_ptr);
+
+ void setThreadState(OzoneThreadState<Impl> *thread_ptr)
+ { thread = thread_ptr; }
+
+ void regStats();
+
+ void tick();
+ Fault fetchCacheLine();
+ void processInst(DynInstPtr &inst);
+ void squash(const InstSeqNum &squash_num, const Addr &next_PC,
+ const bool is_branch = false, const bool branch_taken = false);
+ DynInstPtr getInst();
+
+ void processCacheCompletion(Packet *pkt);
+
+ void addFreeRegs(int num_freed);
+
+ bool isEmpty() { return instBuffer.empty(); }
+
+ void switchOut();
+
+ void doSwitchOut();
+
+ void takeOverFrom(ThreadContext *old_tc = NULL);
+
+ bool isSwitchedOut() { return switchedOut; }
+
+ bool switchedOut;
+
+ private:
+ void recvRetry();
+
+ bool updateStatus();
+
+ void checkBE();
+ DynInstPtr getInstFromCacheline();
+ void renameInst(DynInstPtr &inst);
+ // Returns true if we need to stop the front end this cycle
+ bool processBarriers(DynInstPtr &inst);
+
+ void handleFault(Fault &fault);
+ public:
+ Fault getFault() { return fetchFault; }
+ private:
+ Fault fetchFault;
+
+ // Align an address (typically a PC) to the start of an I-cache block.
+ // We fold in the PISA 64- to 32-bit conversion here as well.
+ Addr icacheBlockAlignPC(Addr addr)
+ {
+ addr = TheISA::realPCToFetchPC(addr);
+ return (addr & ~(cacheBlkMask));
+ }
+
+ InstSeqNum getAndIncrementInstSeq()
+ { return cpu->globalSeqNum++; }
+
+ public:
+ CPUType *cpu;
+
+ BackEnd *backEnd;
+
+ ThreadContext *tc;
+
+ OzoneThreadState<Impl> *thread;
+
+ enum Status {
+ Running,
+ Idle,
+ IcacheWaitResponse,
+ IcacheWaitRetry,
+ IcacheAccessComplete,
+ SerializeBlocked,
+ SerializeComplete,
+ RenameBlocked,
+ QuiescePending,
+ TrapPending,
+ BEBlocked
+ };
+
+ Status status;
+
+ private:
+ TimeBuffer<CommStruct> *comm;
+ typename TimeBuffer<CommStruct>::wire fromCommit;
+
+ typedef typename Impl::BranchPred BranchPred;
+
+ BranchPred branchPred;
+
+ IcachePort icachePort;
+
+ MemObject *mem;
+
+ RequestPtr memReq;
+
+ /** Mask to get a cache block's address. */
+ Addr cacheBlkMask;
+
+ unsigned cacheBlkSize;
+
+ Addr cacheBlkPC;
+
+ /** The cache line being fetched. */
+ uint8_t *cacheData;
+
+ bool fetchCacheLineNextCycle;
+
+ bool cacheBlkValid;
+
+ bool cacheBlocked;
+
+ /** The packet that is waiting to be retried. */
+ PacketPtr retryPkt;
+
+ public:
+ RenameTable<Impl> renameTable;
+
+ private:
+ Addr PC;
+ Addr nextPC;
+
+ public:
+ void setPC(Addr val) { PC = val; }
+ void setNextPC(Addr val) { nextPC = val; }
+
+ void wakeFromQuiesce();
+
+ void dumpInsts();
+
+ private:
+ typedef typename std::deque<DynInstPtr> InstBuff;
+ typedef typename InstBuff::iterator InstBuffIt;
+
+ InstBuff instBuffer;
+
+ int instBufferSize;
+
+ int maxInstBufferSize;
+
+ int width;
+
+ int freeRegs;
+
+ int numPhysRegs;
+
+ bool serializeNext;
+
+ DynInstPtr barrierInst;
+
+ public:
+ bool interruptPending;
+ private:
+ // number of idle cycles
+/*
+ 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;
+ /** Stat for total number of fetched instructions. */
+ Stats::Scalar<> fetchedInsts;
+ Stats::Scalar<> fetchedBranches;
+ /** Stat for total number of predicted branches. */
+ Stats::Scalar<> predictedBranches;
+ /** Stat for total number of cycles spent fetching. */
+ Stats::Scalar<> fetchCycles;
+
+ Stats::Scalar<> fetchIdleCycles;
+ /** Stat for total number of cycles spent squashing. */
+ Stats::Scalar<> fetchSquashCycles;
+ /** Stat for total number of cycles spent blocked due to other stages in
+ * the pipeline.
+ */
+ Stats::Scalar<> fetchBlockedCycles;
+ /** Stat for total number of fetched cache lines. */
+ Stats::Scalar<> fetchedCacheLines;
+
+ 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::Formula idleRate;
+ Stats::Formula branchRate;
+ Stats::Formula fetchRate;
+ Stats::Scalar<> IFQCount; // cumulative IFQ occupancy
+ Stats::Formula IFQOccupancy;
+ Stats::Formula IFQLatency;
+ Stats::Scalar<> IFQFcount; // cumulative IFQ full count
+ Stats::Formula IFQFullRate;
+
+ Stats::Scalar<> dispatchCountStat;
+ Stats::Scalar<> dispatchedSerializing;
+ Stats::Scalar<> dispatchedTempSerializing;
+ Stats::Scalar<> dispatchSerializeStallCycles;
+ Stats::Formula dispatchRate;
+ Stats::Formula regIntFull;
+ Stats::Formula regFpFull;
+};
+
+#endif // __CPU_OZONE_FRONT_END_HH__
diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh
new file mode 100644
index 000000000..40042489d
--- /dev/null
+++ b/src/cpu/ozone/front_end_impl.hh
@@ -0,0 +1,976 @@
+/*
+ * 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
+ */
+
+#include "config/use_checker.hh"
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "base/statistics.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/ozone/front_end.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
+using namespace TheISA;
+
+template<class Impl>
+Tick
+FrontEnd<Impl>::IcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("FrontEnd doesn't expect recvAtomic callback!");
+ return curTick;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvFunctional(PacketPtr pkt)
+{
+ panic("FrontEnd doesn't expect recvFunctional callback!");
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("FrontEnd doesn't expect recvStatusChange callback!");
+}
+
+template<class Impl>
+bool
+FrontEnd<Impl>::IcachePort::recvTiming(Packet *pkt)
+{
+ fe->processCacheCompletion(pkt);
+ return true;
+}
+
+template<class Impl>
+void
+FrontEnd<Impl>::IcachePort::recvRetry()
+{
+ fe->recvRetry();
+}
+
+template <class Impl>
+FrontEnd<Impl>::FrontEnd(Params *params)
+ : branchPred(params),
+ icachePort(this),
+ mem(params->mem),
+ instBufferSize(0),
+ maxInstBufferSize(params->maxInstBufferSize),
+ width(params->frontEndWidth),
+ freeRegs(params->numPhysicalRegs),
+ numPhysRegs(params->numPhysicalRegs),
+ serializeNext(false),
+ interruptPending(false)
+{
+ switchedOut = false;
+
+ status = Idle;
+
+ memReq = NULL;
+ // Size of cache block.
+ cacheBlkSize = 64;
+
+ assert(isPowerOf2(cacheBlkSize));
+
+ // Create mask to get rid of offset bits.
+ cacheBlkMask = (cacheBlkSize - 1);
+
+ // Create space to store a cache line.
+ cacheData = new uint8_t[cacheBlkSize];
+
+ fetchCacheLineNextCycle = true;
+
+ cacheBlkValid = cacheBlocked = false;
+
+ retryPkt = NULL;
+
+ fetchFault = NoFault;
+}
+
+template <class Impl>
+std::string
+FrontEnd<Impl>::name() const
+{
+ return cpu->name() + ".frontend";
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::setCPU(CPUType *cpu_ptr)
+{
+ cpu = cpu_ptr;
+
+ icachePort.setName(this->name() + "-iport");
+
+ Port *mem_dport = mem->getPort("");
+ icachePort.setPeer(mem_dport);
+ mem_dport->setPeer(&icachePort);
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setIcachePort(&icachePort);
+ }
+#endif
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
+{
+ comm = _comm;
+ // @todo: Hardcoded for now. Allow this to be set by a latency.
+ fromCommit = comm->getWire(-1);
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::setTC(ThreadContext *tc_ptr)
+{
+ tc = tc_ptr;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::regStats()
+{
+ icacheStallCycles
+ .name(name() + ".icacheStallCycles")
+ .desc("Number of cycles fetch is stalled on an Icache miss")
+ .prereq(icacheStallCycles);
+
+ fetchedInsts
+ .name(name() + ".fetchedInsts")
+ .desc("Number of instructions fetch has processed")
+ .prereq(fetchedInsts);
+
+ fetchedBranches
+ .name(name() + ".fetchedBranches")
+ .desc("Number of fetched branches")
+ .prereq(fetchedBranches);
+
+ predictedBranches
+ .name(name() + ".predictedBranches")
+ .desc("Number of branches that fetch has predicted taken")
+ .prereq(predictedBranches);
+
+ fetchCycles
+ .name(name() + ".fetchCycles")
+ .desc("Number of cycles fetch has run and was not squashing or"
+ " blocked")
+ .prereq(fetchCycles);
+
+ fetchIdleCycles
+ .name(name() + ".fetchIdleCycles")
+ .desc("Number of cycles fetch was idle")
+ .prereq(fetchIdleCycles);
+
+ fetchSquashCycles
+ .name(name() + ".fetchSquashCycles")
+ .desc("Number of cycles fetch has spent squashing")
+ .prereq(fetchSquashCycles);
+
+ fetchBlockedCycles
+ .name(name() + ".fetchBlockedCycles")
+ .desc("Number of cycles fetch has spent blocked")
+ .prereq(fetchBlockedCycles);
+
+ fetchedCacheLines
+ .name(name() + ".fetchedCacheLines")
+ .desc("Number of cache lines fetched")
+ .prereq(fetchedCacheLines);
+
+ fetchIcacheSquashes
+ .name(name() + ".fetchIcacheSquashes")
+ .desc("Number of outstanding Icache misses that were squashed")
+ .prereq(fetchIcacheSquashes);
+
+ fetchNisnDist
+ .init(/* base value */ 0,
+ /* last value */ width,
+ /* bucket size */ 1)
+ .name(name() + ".rateDist")
+ .desc("Number of instructions fetched each cycle (Total)")
+ .flags(Stats::pdf);
+
+ idleRate
+ .name(name() + ".idleRate")
+ .desc("Percent of cycles fetch was idle")
+ .prereq(idleRate);
+ idleRate = fetchIdleCycles * 100 / cpu->numCycles;
+
+ branchRate
+ .name(name() + ".branchRate")
+ .desc("Number of branch fetches per cycle")
+ .flags(Stats::total);
+ branchRate = fetchedBranches / cpu->numCycles;
+
+ fetchRate
+ .name(name() + ".rate")
+ .desc("Number of inst fetches per cycle")
+ .flags(Stats::total);
+ fetchRate = fetchedInsts / cpu->numCycles;
+
+ IFQCount
+ .name(name() + ".IFQ:count")
+ .desc("cumulative IFQ occupancy")
+ ;
+
+ IFQFcount
+ .name(name() + ".IFQ:fullCount")
+ .desc("cumulative IFQ full count")
+ .flags(Stats::total)
+ ;
+
+ IFQOccupancy
+ .name(name() + ".IFQ:occupancy")
+ .desc("avg IFQ occupancy (inst's)")
+ ;
+ IFQOccupancy = IFQCount / cpu->numCycles;
+
+ IFQLatency
+ .name(name() + ".IFQ:latency")
+ .desc("avg IFQ occupant latency (cycle's)")
+ .flags(Stats::total)
+ ;
+
+ IFQFullRate
+ .name(name() + ".IFQ:fullRate")
+ .desc("fraction of time (cycles) IFQ was full")
+ .flags(Stats::total);
+ ;
+ IFQFullRate = IFQFcount * Stats::constant(100) / cpu->numCycles;
+
+ dispatchCountStat
+ .name(name() + ".DIS:count")
+ .desc("cumulative count of dispatched insts")
+ .flags(Stats::total)
+ ;
+
+ dispatchedSerializing
+ .name(name() + ".DIS:serializingInsts")
+ .desc("count of serializing insts dispatched")
+ .flags(Stats::total)
+ ;
+
+ dispatchedTempSerializing
+ .name(name() + ".DIS:tempSerializingInsts")
+ .desc("count of temporary serializing insts dispatched")
+ .flags(Stats::total)
+ ;
+
+ dispatchSerializeStallCycles
+ .name(name() + ".DIS:serializeStallCycles")
+ .desc("count of cycles dispatch stalled for serializing inst")
+ .flags(Stats::total)
+ ;
+
+ dispatchRate
+ .name(name() + ".DIS:rate")
+ .desc("dispatched insts per cycle")
+ .flags(Stats::total)
+ ;
+ dispatchRate = dispatchCountStat / cpu->numCycles;
+
+ regIntFull
+ .name(name() + ".REG:int:full")
+ .desc("number of cycles where there were no INT registers")
+ ;
+
+ regFpFull
+ .name(name() + ".REG:fp:full")
+ .desc("number of cycles where there were no FP registers")
+ ;
+ IFQLatency = IFQOccupancy / dispatchRate;
+
+ branchPred.regStats();
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::tick()
+{
+ if (switchedOut)
+ return;
+
+ // @todo: Maybe I want to just have direct communication...
+ if (fromCommit->doneSeqNum) {
+ branchPred.update(fromCommit->doneSeqNum, 0);
+ }
+
+ IFQCount += instBufferSize;
+ IFQFcount += instBufferSize == maxInstBufferSize;
+
+ // Fetch cache line
+ if (status == IcacheAccessComplete) {
+ cacheBlkValid = true;
+
+ status = Running;
+ if (barrierInst)
+ status = SerializeBlocked;
+ if (freeRegs <= 0)
+ status = RenameBlocked;
+ checkBE();
+ } else if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
+ DPRINTF(FE, "Still in Icache wait.\n");
+ icacheStallCycles++;
+ return;
+ }
+
+ if (status == RenameBlocked || status == SerializeBlocked ||
+ status == TrapPending || status == BEBlocked) {
+ // Will cause a one cycle bubble between changing state and
+ // restarting.
+ DPRINTF(FE, "In blocked status.\n");
+
+ fetchBlockedCycles++;
+
+ if (status == SerializeBlocked) {
+ dispatchSerializeStallCycles++;
+ }
+ updateStatus();
+ return;
+ } else if (status == QuiescePending) {
+ DPRINTF(FE, "Waiting for quiesce to execute or get squashed.\n");
+ return;
+ } else if (status != IcacheAccessComplete) {
+ if (fetchCacheLineNextCycle) {
+ Fault fault = fetchCacheLine();
+ if (fault != NoFault) {
+ handleFault(fault);
+ fetchFault = fault;
+ return;
+ }
+ fetchCacheLineNextCycle = false;
+ }
+ // If miss, stall until it returns.
+ if (status == IcacheWaitResponse || status == IcacheWaitRetry) {
+ // Tell CPU to not tick me for now.
+ return;
+ }
+ }
+
+ fetchCycles++;
+
+ int num_inst = 0;
+
+ // Otherwise loop and process instructions.
+ // One way to hack infinite width is to set width and maxInstBufferSize
+ // both really high. Inelegant, but probably will work.
+ while (num_inst < width &&
+ instBufferSize < maxInstBufferSize) {
+ // Get instruction from cache line.
+ DynInstPtr inst = getInstFromCacheline();
+
+ if (!inst) {
+ // PC is no longer in the cache line, end fetch.
+ // Might want to check this at the end of the cycle so that
+ // there's no cycle lost to checking for a new cache line.
+ DPRINTF(FE, "Need to get new cache line\n");
+ fetchCacheLineNextCycle = true;
+ break;
+ }
+
+ processInst(inst);
+
+ if (status == SerializeBlocked) {
+ break;
+ }
+
+ // Possibly push into a time buffer that estimates the front end
+ // latency
+ instBuffer.push_back(inst);
+ ++instBufferSize;
+ ++num_inst;
+
+#if FULL_SYSTEM
+ if (inst->isQuiesce()) {
+ warn("%lli: Quiesce instruction encountered, halting fetch!", curTick);
+ status = QuiescePending;
+ break;
+ }
+#endif
+
+ if (inst->predTaken()) {
+ // Start over with tick?
+ break;
+ } else if (freeRegs <= 0) {
+ DPRINTF(FE, "Ran out of free registers to rename to!\n");
+ status = RenameBlocked;
+ break;
+ } else if (serializeNext) {
+ break;
+ }
+ }
+
+ fetchNisnDist.sample(num_inst);
+ checkBE();
+
+ DPRINTF(FE, "Num insts processed: %i, Inst Buffer size: %i, Free "
+ "Regs %i\n", num_inst, instBufferSize, freeRegs);
+}
+
+template <class Impl>
+Fault
+FrontEnd<Impl>::fetchCacheLine()
+{
+ // Read a cache line, based on the current PC.
+#if FULL_SYSTEM
+ // Flag to say whether or not address is physical addr.
+ unsigned flags = cpu->inPalMode(PC) ? PHYSICAL : 0;
+#else
+ unsigned flags = 0;
+#endif // FULL_SYSTEM
+ Fault fault = NoFault;
+
+ if (interruptPending && flags == 0) {
+ return fault;
+ }
+
+ // Align the fetch PC so it's at the start of a cache block.
+ Addr fetch_PC = icacheBlockAlignPC(PC);
+
+ DPRINTF(FE, "Fetching cache line starting at %#x.\n", fetch_PC);
+
+ // 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, flags,
+ fetch_PC, cpu->readCpuId(), 0);
+
+ // Translate the instruction request.
+ fault = cpu->translateInstReq(memReq, thread);
+
+ // Now do the timing access to see whether or not the instruction
+ // exists within the cache.
+ if (fault == NoFault) {
+#if 0
+ if (cpu->system->memctrl->badaddr(memReq->paddr) ||
+ memReq->flags & UNCACHEABLE) {
+ DPRINTF(FE, "Fetch: Bad address %#x (hopefully on a "
+ "misspeculating path!",
+ memReq->paddr);
+ return TheISA::genMachineCheckFault();
+ }
+#endif
+
+ // Build packet here.
+ PacketPtr data_pkt = new Packet(memReq,
+ Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(cacheData);
+
+ if (!icachePort.sendTiming(data_pkt)) {
+ assert(retryPkt == NULL);
+ DPRINTF(Fetch, "Out of MSHRs!\n");
+ status = IcacheWaitRetry;
+ retryPkt = data_pkt;
+ cacheBlocked = true;
+ return NoFault;
+ }
+
+ status = IcacheWaitResponse;
+ }
+
+ // Note that this will set the cache block PC a bit earlier than it should
+ // be set.
+ cacheBlkPC = fetch_PC;
+
+ ++fetchedCacheLines;
+
+ DPRINTF(FE, "Done fetching cache line.\n");
+
+ return fault;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::processInst(DynInstPtr &inst)
+{
+ if (processBarriers(inst)) {
+ return;
+ }
+
+ Addr inst_PC = inst->readPC();
+
+ if (!inst->isControl()) {
+ inst->setPredTarg(inst->readNextPC());
+ } else {
+ fetchedBranches++;
+ if (branchPred.predict(inst, inst_PC, inst->threadNumber)) {
+ predictedBranches++;
+ }
+ }
+
+ Addr next_PC = inst->readPredTarg();
+
+ DPRINTF(FE, "[sn:%lli] Predicted and processed inst PC %#x, next PC "
+ "%#x\n", inst->seqNum, inst_PC, next_PC);
+
+// inst->setNextPC(next_PC);
+
+ // Not sure where I should set this
+ PC = next_PC;
+
+ renameInst(inst);
+}
+
+template <class Impl>
+bool
+FrontEnd<Impl>::processBarriers(DynInstPtr &inst)
+{
+ if (serializeNext) {
+ inst->setSerializeBefore();
+ serializeNext = false;
+ } else if (!inst->isSerializing() &&
+ !inst->isIprAccess() &&
+ !inst->isStoreConditional()) {
+ return false;
+ }
+
+ if ((inst->isIprAccess() || inst->isSerializeBefore()) &&
+ !inst->isSerializeHandled()) {
+ DPRINTF(FE, "Serialize before instruction encountered.\n");
+
+ if (!inst->isTempSerializeBefore()) {
+ dispatchedSerializing++;
+ inst->setSerializeHandled();
+ } else {
+ dispatchedTempSerializing++;
+ }
+
+ // Change status over to SerializeBlocked so that other stages know
+ // what this is blocked on.
+ status = SerializeBlocked;
+
+ barrierInst = inst;
+ return true;
+ } else if ((inst->isStoreConditional() || inst->isSerializeAfter())
+ && !inst->isSerializeHandled()) {
+ DPRINTF(FE, "Serialize after instruction encountered.\n");
+
+ inst->setSerializeHandled();
+
+ dispatchedSerializing++;
+
+ serializeNext = true;
+ return false;
+ }
+ return false;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::handleFault(Fault &fault)
+{
+ DPRINTF(FE, "Fault at fetch, telling commit\n");
+
+ // We're blocked on the back end until it handles this fault.
+ status = TrapPending;
+
+ // Get a sequence number.
+ InstSeqNum inst_seq = getAndIncrementInstSeq();
+ // We will use a nop in order to carry the fault.
+ ExtMachInst ext_inst = TheISA::NoopMachInst;
+
+ // Create a new DynInst from the dummy nop.
+ DynInstPtr instruction = new DynInst(ext_inst, PC,
+ PC+sizeof(MachInst),
+ inst_seq, cpu);
+ instruction->setPredTarg(instruction->readNextPC());
+// instruction->setThread(tid);
+
+// instruction->setASID(tid);
+
+ instruction->setThreadState(thread);
+
+ instruction->traceData = NULL;
+
+ instruction->fault = fault;
+ instruction->setCanIssue();
+ instBuffer.push_back(instruction);
+ ++instBufferSize;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC,
+ const bool is_branch, const bool branch_taken)
+{
+ DPRINTF(FE, "Squashing from [sn:%lli], setting PC to %#x\n",
+ squash_num, next_PC);
+
+ if (fetchFault != NoFault)
+ fetchFault = NoFault;
+
+ while (!instBuffer.empty() &&
+ instBuffer.back()->seqNum > squash_num) {
+ DynInstPtr inst = instBuffer.back();
+
+ DPRINTF(FE, "Squashing instruction [sn:%lli] PC %#x\n",
+ inst->seqNum, inst->readPC());
+
+ inst->clearDependents();
+
+ instBuffer.pop_back();
+ --instBufferSize;
+
+ freeRegs+= inst->numDestRegs();
+ }
+
+ // Copy over rename table from the back end.
+ renameTable.copyFrom(backEnd->renameTable);
+
+ PC = next_PC;
+
+ // Update BP with proper information.
+ if (is_branch) {
+ branchPred.squash(squash_num, next_PC, branch_taken, 0);
+ } else {
+ branchPred.squash(squash_num, 0);
+ }
+
+ // Clear the icache miss if it's outstanding.
+ if (status == IcacheWaitResponse) {
+ DPRINTF(FE, "Squashing outstanding Icache access.\n");
+ memReq = NULL;
+ }
+
+ if (status == SerializeBlocked) {
+ assert(barrierInst->seqNum > squash_num);
+ barrierInst = NULL;
+ }
+
+ // Unless this squash originated from the front end, we're probably
+ // in running mode now.
+ // Actually might want to make this latency dependent.
+ status = Running;
+ fetchCacheLineNextCycle = true;
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+FrontEnd<Impl>::getInst()
+{
+ if (instBufferSize == 0) {
+ return NULL;
+ }
+
+ DynInstPtr inst = instBuffer.front();
+
+ instBuffer.pop_front();
+
+ --instBufferSize;
+
+ dispatchCountStat++;
+
+ return inst;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::processCacheCompletion(PacketPtr pkt)
+{
+ DPRINTF(FE, "Processing cache completion\n");
+
+ // Do something here.
+ if (status != IcacheWaitResponse ||
+ pkt->req != memReq ||
+ switchedOut) {
+ DPRINTF(FE, "Previous fetch was squashed.\n");
+ fetchIcacheSquashes++;
+ delete pkt->req;
+ delete pkt;
+ return;
+ }
+
+ status = IcacheAccessComplete;
+
+/* if (checkStall(tid)) {
+ fetchStatus[tid] = Blocked;
+ } else {
+ fetchStatus[tid] = IcacheMissComplete;
+ }
+*/
+// memcpy(cacheData, memReq->data, memReq->size);
+
+ // Reset the completion event to NULL.
+// memReq->completionEvent = NULL;
+ delete pkt->req;
+ delete pkt;
+ memReq = NULL;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::addFreeRegs(int num_freed)
+{
+ if (status == RenameBlocked && freeRegs + num_freed > 0) {
+ status = Running;
+ }
+
+ DPRINTF(FE, "Adding %i freed registers\n", num_freed);
+
+ freeRegs+= num_freed;
+
+// assert(freeRegs <= numPhysRegs);
+ if (freeRegs > numPhysRegs)
+ freeRegs = numPhysRegs;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::recvRetry()
+{
+ assert(cacheBlocked);
+ if (retryPkt != NULL) {
+ assert(status == IcacheWaitRetry);
+
+ if (icachePort.sendTiming(retryPkt)) {
+ status = IcacheWaitResponse;
+ retryPkt = NULL;
+ cacheBlocked = false;
+ }
+ } else {
+ // Access has been squashed since it was sent out. Just clear
+ // the cache being blocked.
+ cacheBlocked = false;
+ }
+
+}
+
+template <class Impl>
+bool
+FrontEnd<Impl>::updateStatus()
+{
+ bool serialize_block = !backEnd->robEmpty() || instBufferSize;
+ bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
+ bool ret_val = false;
+
+ if (status == SerializeBlocked && !serialize_block) {
+ status = SerializeComplete;
+ ret_val = true;
+ }
+
+ if (status == BEBlocked && !be_block) {
+ if (barrierInst) {
+ status = SerializeBlocked;
+ } else {
+ status = Running;
+ }
+ ret_val = true;
+ }
+ return ret_val;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::checkBE()
+{
+ bool be_block = cpu->decoupledFrontEnd ? false : backEnd->isBlocked();
+ if (be_block) {
+ if (status == Running || status == Idle) {
+ status = BEBlocked;
+ }
+ }
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+FrontEnd<Impl>::getInstFromCacheline()
+{
+ if (status == SerializeComplete) {
+ DynInstPtr inst = barrierInst;
+ status = Running;
+ barrierInst = NULL;
+ inst->clearSerializeBefore();
+ return inst;
+ }
+
+ InstSeqNum inst_seq;
+ MachInst inst;
+ // @todo: Fix this magic number used here to handle word offset (and
+ // getting rid of PAL bit)
+ unsigned offset = (PC & cacheBlkMask) & ~3;
+
+ // PC of inst is not in this cache block
+ if (PC >= (cacheBlkPC + cacheBlkSize) || PC < cacheBlkPC || !cacheBlkValid) {
+ return NULL;
+ }
+
+ //////////////////////////
+ // Fetch one instruction
+ //////////////////////////
+
+ // Get a sequence number.
+ inst_seq = getAndIncrementInstSeq();
+
+ // Make sure this is a valid index.
+ assert(offset <= cacheBlkSize - sizeof(MachInst));
+
+ // Get the instruction from the array of the cache line.
+ inst = htog(*reinterpret_cast<MachInst *>(&cacheData[offset]));
+
+ ExtMachInst decode_inst = TheISA::makeExtMI(inst, PC);
+
+ // Create a new DynInst from the instruction fetched.
+ DynInstPtr instruction = new DynInst(decode_inst, PC, PC+sizeof(MachInst),
+ inst_seq, cpu);
+
+ instruction->setThreadState(thread);
+
+ DPRINTF(FE, "Instruction [sn:%lli] created, with PC %#x\n%s\n",
+ inst_seq, instruction->readPC(),
+ instruction->staticInst->disassemble(PC));
+
+ instruction->traceData =
+ Trace::getInstRecord(curTick, tc, cpu,
+ instruction->staticInst,
+ instruction->readPC(), 0);
+
+ // Increment stat of fetched instructions.
+ ++fetchedInsts;
+
+ return instruction;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::renameInst(DynInstPtr &inst)
+{
+ DynInstPtr src_inst = NULL;
+ int num_src_regs = inst->numSrcRegs();
+ if (num_src_regs == 0) {
+ inst->setCanIssue();
+ } else {
+ for (int i = 0; i < num_src_regs; ++i) {
+ src_inst = renameTable[inst->srcRegIdx(i)];
+
+ inst->setSrcInst(src_inst, i);
+
+ DPRINTF(FE, "[sn:%lli]: Src reg %i is inst [sn:%lli]\n",
+ inst->seqNum, (int)inst->srcRegIdx(i), src_inst->seqNum);
+
+ if (src_inst->isResultReady()) {
+ DPRINTF(FE, "Reg ready.\n");
+ inst->markSrcRegReady(i);
+ } else {
+ DPRINTF(FE, "Adding to dependent list.\n");
+ src_inst->addDependent(inst);
+ }
+ }
+ }
+
+ for (int i = 0; i < inst->numDestRegs(); ++i) {
+ RegIndex idx = inst->destRegIdx(i);
+
+ DPRINTF(FE, "Dest reg %i is now inst [sn:%lli], was previously "
+ "[sn:%lli]\n",
+ (int)inst->destRegIdx(i), inst->seqNum,
+ renameTable[idx]->seqNum);
+
+ inst->setPrevDestInst(renameTable[idx], i);
+
+ renameTable[idx] = inst;
+ --freeRegs;
+ }
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::wakeFromQuiesce()
+{
+ DPRINTF(FE, "Waking up from quiesce\n");
+ // Hopefully this is safe
+ status = Running;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::switchOut()
+{
+ switchedOut = true;
+ cpu->signalSwitched();
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::doSwitchOut()
+{
+ memReq = NULL;
+ squash(0, 0);
+ instBuffer.clear();
+ instBufferSize = 0;
+ status = Idle;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::takeOverFrom(ThreadContext *old_tc)
+{
+ assert(freeRegs == numPhysRegs);
+ fetchCacheLineNextCycle = true;
+
+ cacheBlkValid = false;
+
+#if !FULL_SYSTEM
+// pTable = params->pTable;
+#endif
+ fetchFault = NoFault;
+ serializeNext = false;
+ barrierInst = NULL;
+ status = Running;
+ switchedOut = false;
+ interruptPending = false;
+}
+
+template <class Impl>
+void
+FrontEnd<Impl>::dumpInsts()
+{
+ cprintf("instBuffer size: %i\n", instBuffer.size());
+
+ InstBuffIt buff_it = instBuffer.begin();
+
+ for (int num = 0; buff_it != instBuffer.end(); num++) {
+ cprintf("Instruction:%i\nPC:%#x\n[tid:%i]\n[sn:%lli]\nIssued:%i\n"
+ "Squashed:%i\n\n",
+ num, (*buff_it)->readPC(), (*buff_it)->threadNumber,
+ (*buff_it)->seqNum, (*buff_it)->isIssued(),
+ (*buff_it)->isSquashed());
+ buff_it++;
+ }
+}
diff --git a/src/cpu/ozone/inorder_back_end.cc b/src/cpu/ozone/inorder_back_end.cc
new file mode 100644
index 000000000..bc6618e4a
--- /dev/null
+++ b/src/cpu/ozone/inorder_back_end.cc
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/inorder_back_end_impl.hh"
+#include "cpu/ozone/simple_impl.hh"
+
+template class InorderBackEnd<SimpleImpl>;
diff --git a/src/cpu/ozone/inorder_back_end.hh b/src/cpu/ozone/inorder_back_end.hh
new file mode 100644
index 000000000..ffdba2f6c
--- /dev/null
+++ b/src/cpu/ozone/inorder_back_end.hh
@@ -0,0 +1,478 @@
+/*
+ * 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_OZONE_INORDER_BACK_END_HH__
+#define __CPU_OZONE_INORDER_BACK_END_HH__
+
+#include <list>
+
+#include "arch/faults.hh"
+#include "base/timebuf.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/rename_table.hh"
+#include "cpu/ozone/thread_state.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+template <class Impl>
+class InorderBackEnd
+{
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::FrontEnd FrontEnd;
+
+ typedef typename FullCPU::OzoneTC OzoneTC;
+ typedef typename Impl::FullCPU::CommStruct CommStruct;
+
+ InorderBackEnd(Params *params);
+
+ std::string name() const;
+
+ void setCPU(FullCPU *cpu_ptr)
+ { cpu = cpu_ptr; }
+
+ void setFrontEnd(FrontEnd *front_end_ptr)
+ { frontEnd = front_end_ptr; }
+
+ void setCommBuffer(TimeBuffer<CommStruct> *_comm)
+ { comm = _comm; }
+
+ void setTC(ThreadContext *tc_ptr);
+
+ void setThreadState(OzoneThreadState<Impl> *thread_ptr);
+
+ void regStats() { }
+
+#if FULL_SYSTEM
+ void checkInterrupts();
+#endif
+
+ void tick();
+ void executeInsts();
+ void squash(const InstSeqNum &squash_num, const Addr &next_PC);
+
+ void squashFromXC();
+ void generateXCEvent() { }
+
+ bool robEmpty() { return instList.empty(); }
+
+ bool isFull() { return false; }
+ bool isBlocked() { return status == DcacheMissStoreStall ||
+ status == DcacheMissLoadStall ||
+ interruptBlocked; }
+
+ void fetchFault(Fault &fault);
+
+ void dumpInsts();
+
+ private:
+ void handleFault();
+
+ void setSquashInfoFromTC();
+
+ bool squashPending;
+ InstSeqNum squashSeqNum;
+ Addr squashNextPC;
+
+ Fault faultFromFetch;
+
+ bool interruptBlocked;
+
+ public:
+ template <class T>
+ Fault read(Addr addr, T &data, unsigned flags);
+
+ template <class T>
+ Fault read(RequestPtr req, T &data, int load_idx);
+
+ template <class T>
+ Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
+
+ template <class T>
+ Fault write(RequestPtr req, T &data, int store_idx);
+
+ Addr readCommitPC() { return commitPC; }
+
+ Addr commitPC;
+
+ void switchOut() { panic("Not implemented!"); }
+ void doSwitchOut() { panic("Not implemented!"); }
+ void takeOverFrom(ThreadContext *old_tc = NULL) { panic("Not implemented!"); }
+
+ public:
+ FullCPU *cpu;
+
+ FrontEnd *frontEnd;
+
+ ThreadContext *tc;
+
+ OzoneThreadState<Impl> *thread;
+
+ RenameTable<Impl> renameTable;
+
+ protected:
+ enum Status {
+ Running,
+ Idle,
+ DcacheMissLoadStall,
+ DcacheMissStoreStall,
+ DcacheMissComplete,
+ Blocked
+ };
+
+ Status status;
+
+ class DCacheCompletionEvent : public Event
+ {
+ private:
+ InorderBackEnd *be;
+
+ public:
+ DCacheCompletionEvent(InorderBackEnd *_be);
+
+ virtual void process();
+ virtual const char *description();
+
+ DynInstPtr inst;
+ };
+
+ friend class DCacheCompletionEvent;
+
+ DCacheCompletionEvent cacheCompletionEvent;
+
+// MemInterface *dcacheInterface;
+
+ RequestPtr memReq;
+
+ private:
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+
+ std::list<DynInstPtr> instList;
+
+ // General back end width. Used if the more specific isn't given.
+ int width;
+
+ int latency;
+
+ int squashLatency;
+
+ TimeBuffer<int> numInstsToWB;
+ TimeBuffer<int>::wire instsAdded;
+ TimeBuffer<int>::wire instsToExecute;
+
+ TimeBuffer<CommStruct> *comm;
+ // number of cycles stalled for D-cache misses
+ Stats::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+};
+
+template <class Impl>
+template <class T>
+Fault
+InorderBackEnd<Impl>::read(Addr addr, T &data, unsigned flags)
+{
+ memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+ Fault fault = cpu->translateDataReadReq(memReq);
+
+ // if we have a cache, do cache access too
+ if (fault == NoFault && dcacheInterface) {
+ memReq->cmd = Read;
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~INST_READ;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT) {
+ // Fix this hack for keeping funcExeInst correct with loads that
+ // are executed twice.
+ memReq->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+ status = DcacheMissLoadStall;
+ DPRINTF(IBE, "Dcache miss stall!\n");
+ } else {
+ // do functional access
+ DPRINTF(IBE, "Dcache hit!\n");
+ }
+ }
+/*
+ if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Read");
+*/
+ return fault;
+}
+#if 0
+template <class Impl>
+template <class T>
+Fault
+InorderBackEnd<Impl>::read(MemReqPtr &req, T &data)
+{
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ if (req->flags & LOCKED) {
+ req->xc->setMiscReg(TheISA::Lock_Addr_DepTag, req->paddr);
+ req->xc->setMiscReg(TheISA::Lock_Flag_DepTag, true);
+ }
+#endif
+
+ Fault error;
+ error = thread->mem->read(req, data);
+ data = LittleEndianGuest::gtoh(data);
+ return error;
+}
+#endif
+
+template <class Impl>
+template <class T>
+Fault
+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);
+
+ if (fault == NoFault && dcacheInterface) {
+ memReq->cmd = Write;
+// memcpy(memReq->data,(uint8_t *)&data,memReq->size);
+ memReq->completionEvent = NULL;
+ memReq->time = curTick;
+ memReq->flags &= ~INST_READ;
+ MemAccessResult result = dcacheInterface->access(memReq);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT) {
+ memReq->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+ status = DcacheMissStoreStall;
+ DPRINTF(IBE, "Dcache miss stall!\n");
+ } else {
+ DPRINTF(IBE, "Dcache hit!\n");
+ }
+ }
+
+ if (res && (fault == NoFault))
+ *res = memReq->result;
+/*
+ if (!dcacheInterface && (memReq->flags & UNCACHEABLE))
+ recordEvent("Uncached Write");
+*/
+ return fault;
+}
+#if 0
+template <class Impl>
+template <class T>
+Fault
+InorderBackEnd<Impl>::write(MemReqPtr &req, T &data)
+{
+#if FULL_SYSTEM && defined(TARGET_ALPHA)
+ ExecContext *xc;
+
+ // If this is a store conditional, act appropriately
+ if (req->flags & LOCKED) {
+ xc = req->xc;
+
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ xc->setStCondFailures(0);//Needed? [RGD]
+ } else {
+ bool lock_flag = xc->readMiscReg(TheISA::Lock_Flag_DepTag);
+ Addr lock_addr = xc->readMiscReg(TheISA::Lock_Addr_DepTag);
+ req->result = lock_flag;
+ if (!lock_flag ||
+ ((lock_addr & ~0xf) != (req->paddr & ~0xf))) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ xc->setStCondFailures(xc->readStCondFailures() + 1);
+ if (((xc->readStCondFailures()) % 100000) == 0) {
+ std::cerr << "Warning: "
+ << xc->readStCondFailures()
+ << " consecutive store conditional failures "
+ << "on cpu " << req->xc->readCpuId()
+ << std::endl;
+ }
+ return NoFault;
+ }
+ else xc->setStCondFailures(0);
+ }
+ }
+
+ // Need to clear any locked flags on other proccessors for
+ // this address. Only do this for succsful Store Conditionals
+ // and all other stores (WH64?). Unsuccessful Store
+ // Conditionals would have returned above, and wouldn't fall
+ // through.
+ for (int i = 0; i < cpu->system->execContexts.size(); i++){
+ xc = cpu->system->execContexts[i];
+ if ((xc->readMiscReg(TheISA::Lock_Addr_DepTag) & ~0xf) ==
+ (req->paddr & ~0xf)) {
+ xc->setMiscReg(TheISA::Lock_Flag_DepTag, false);
+ }
+ }
+
+#endif
+ return thread->mem->write(req, (T)LittleEndianGuest::htog(data));
+}
+#endif
+
+template <class Impl>
+template <class T>
+Fault
+InorderBackEnd<Impl>::read(MemReqPtr &req, T &data, int load_idx)
+{
+// panic("Unimplemented!");
+// memReq->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+// Fault fault = cpu->translateDataReadReq(req);
+ req->cmd = Read;
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+ req->flags &= ~INST_READ;
+ Fault fault = cpu->read(req, data);
+ memcpy(req->data, &data, sizeof(T));
+
+ // if we have a cache, do cache access too
+ if (dcacheInterface) {
+ MemAccessResult result = dcacheInterface->access(req);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT) {
+ req->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+ status = DcacheMissLoadStall;
+ DPRINTF(IBE, "Dcache miss load stall!\n");
+ } else {
+ DPRINTF(IBE, "Dcache hit!\n");
+
+ }
+ }
+
+/*
+ if (!dcacheInterface && (req->flags & UNCACHEABLE))
+ recordEvent("Uncached Read");
+*/
+ return NoFault;
+}
+
+template <class Impl>
+template <class T>
+Fault
+InorderBackEnd<Impl>::write(MemReqPtr &req, T &data, int store_idx)
+{
+// req->reset(addr, sizeof(T), flags);
+
+ // translate to physical address
+// Fault fault = cpu->translateDataWriteReq(req);
+
+ req->cmd = Write;
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+ memcpy(req->data, (uint8_t *)&data, req->size);
+
+ switch(req->size) {
+ case 1:
+ cpu->write(req, (uint8_t &)data);
+ break;
+ case 2:
+ cpu->write(req, (uint16_t &)data);
+ break;
+ case 4:
+ cpu->write(req, (uint32_t &)data);
+ break;
+ case 8:
+ cpu->write(req, (uint64_t &)data);
+ break;
+ default:
+ panic("Unexpected store size!\n");
+ }
+
+ if (dcacheInterface) {
+ req->cmd = Write;
+ req->data = new uint8_t[64];
+ memcpy(req->data,(uint8_t *)&data,req->size);
+ req->completionEvent = NULL;
+ req->time = curTick;
+ req->flags &= ~INST_READ;
+ MemAccessResult result = dcacheInterface->access(req);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ if (result != MA_HIT) {
+ req->completionEvent = &cacheCompletionEvent;
+ lastDcacheStall = curTick;
+// unscheduleTickEvent();
+ status = DcacheMissStoreStall;
+ DPRINTF(IBE, "Dcache miss store stall!\n");
+ } else {
+ DPRINTF(IBE, "Dcache hit!\n");
+
+ }
+ }
+/*
+ if (req->flags & LOCKED) {
+ if (req->flags & UNCACHEABLE) {
+ // Don't update result register (see stq_c in isa_desc)
+ req->result = 2;
+ } else {
+ req->result = 1;
+ }
+ }
+*/
+/*
+ if (res && (fault == NoFault))
+ *res = req->result;
+ */
+/*
+ if (!dcacheInterface && (req->flags & UNCACHEABLE))
+ recordEvent("Uncached Write");
+*/
+ return NoFault;
+}
+
+#endif // __CPU_OZONE_INORDER_BACK_END_HH__
diff --git a/src/cpu/ozone/inorder_back_end_impl.hh b/src/cpu/ozone/inorder_back_end_impl.hh
new file mode 100644
index 000000000..cbb73364e
--- /dev/null
+++ b/src/cpu/ozone/inorder_back_end_impl.hh
@@ -0,0 +1,548 @@
+/*
+ * 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
+ */
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/ozone/inorder_back_end.hh"
+#include "cpu/ozone/thread_state.hh"
+
+using namespace TheISA;
+
+template <class Impl>
+InorderBackEnd<Impl>::InorderBackEnd(Params *params)
+ : squashPending(false),
+ squashSeqNum(0),
+ squashNextPC(0),
+ faultFromFetch(NoFault),
+ interruptBlocked(false),
+ cacheCompletionEvent(this),
+ dcacheInterface(params->dcacheInterface),
+ width(params->backEndWidth),
+ latency(params->backEndLatency),
+ squashLatency(params->backEndSquashLatency),
+ numInstsToWB(0, latency + 1)
+{
+ instsAdded = numInstsToWB.getWire(latency);
+ instsToExecute = numInstsToWB.getWire(0);
+
+ memReq = new MemReq;
+ memReq->data = new uint8_t[64];
+ status = Running;
+}
+
+template <class Impl>
+std::string
+InorderBackEnd<Impl>::name() const
+{
+ return cpu->name() + ".inorderbackend";
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::setXC(ExecContext *xc_ptr)
+{
+ xc = xc_ptr;
+ memReq->xc = xc;
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::setThreadState(OzoneThreadState<Impl> *thread_ptr)
+{
+ thread = thread_ptr;
+ thread->setFuncExeInst(0);
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+InorderBackEnd<Impl>::checkInterrupts()
+{
+ //Check if there are any outstanding interrupts
+ //Handle the interrupts
+ int ipl = 0;
+ int summary = 0;
+
+ cpu->checkInterrupts = false;
+
+ if (thread->readMiscReg(IPR_ASTRR))
+ panic("asynchronous traps not implemented\n");
+
+ if (thread->readMiscReg(IPR_SIRR)) {
+ for (int i = INTLEVEL_SOFTWARE_MIN;
+ i < INTLEVEL_SOFTWARE_MAX; i++) {
+ if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ uint64_t interrupts = cpu->intr_status();
+
+ if (interrupts) {
+ for (int i = INTLEVEL_EXTERNAL_MIN;
+ i < INTLEVEL_EXTERNAL_MAX; i++) {
+ if (interrupts & (ULL(1) << i)) {
+ // See table 4-19 of the 21164 hardware reference
+ ipl = i;
+ summary |= (ULL(1) << i);
+ }
+ }
+ }
+
+ if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) {
+ thread->inSyscall = true;
+
+ thread->setMiscReg(IPR_ISR, summary);
+ thread->setMiscReg(IPR_INTID, ipl);
+ Fault(new InterruptFault)->invoke(xc);
+ DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
+ thread->readMiscReg(IPR_IPLR), ipl, summary);
+
+ // May need to go 1 inst prior
+ squashPending = true;
+
+ thread->inSyscall = false;
+
+ setSquashInfoFromXC();
+ }
+}
+#endif
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::tick()
+{
+ // Squash due to an external source
+ // Not sure if this or an interrupt has higher priority
+ if (squashPending) {
+ squash(squashSeqNum, squashNextPC);
+ return;
+ }
+
+ // 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->checkInterrupts &&
+ cpu->check_interrupts() &&
+ !cpu->inPalMode())) {
+ if (!robEmpty()) {
+ interruptBlocked = true;
+ } else if (robEmpty() && cpu->inPalMode()) {
+ // Will need to let the front end continue a bit until
+ // we're out of pal mode. Hopefully we never get into an
+ // infinite loop...
+ interruptBlocked = false;
+ } else {
+ interruptBlocked = false;
+ checkInterrupts();
+ return;
+ }
+ }
+#endif
+
+ if (status != DcacheMissLoadStall &&
+ status != DcacheMissStoreStall) {
+ for (int i = 0; i < width && (*instsAdded) < width; ++i) {
+ DynInstPtr inst = frontEnd->getInst();
+
+ if (!inst)
+ break;
+
+ instList.push_back(inst);
+
+ (*instsAdded)++;
+ }
+
+#if FULL_SYSTEM
+ if (faultFromFetch && robEmpty() && frontEnd->isEmpty()) {
+ handleFault();
+ } else {
+ executeInsts();
+ }
+#else
+ executeInsts();
+#endif
+ }
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::executeInsts()
+{
+ bool completed_last_inst = true;
+ int insts_to_execute = *instsToExecute;
+ int freed_regs = 0;
+
+ while (insts_to_execute > 0) {
+ assert(!instList.empty());
+ DynInstPtr inst = instList.front();
+
+ commitPC = inst->readPC();
+
+ thread->setPC(commitPC);
+ thread->setNextPC(inst->readNextPC());
+
+#if FULL_SYSTEM
+ int count = 0;
+ Addr oldpc;
+ do {
+ if (count == 0)
+ assert(!thread->inSyscall && !thread->trapPending);
+ oldpc = thread->readPC();
+ cpu->system->pcEventQueue.service(
+ thread->getXCProxy());
+ count++;
+ } while (oldpc != thread->readPC());
+ if (count > 1) {
+ DPRINTF(IBE, "PC skip function event, stopping commit\n");
+ completed_last_inst = false;
+ squashPending = true;
+ break;
+ }
+#endif
+
+ Fault inst_fault = NoFault;
+
+ if (status == DcacheMissComplete) {
+ DPRINTF(IBE, "Completing inst [sn:%lli]\n", inst->seqNum);
+ status = Running;
+ } else if (inst->isMemRef() && status != DcacheMissComplete &&
+ (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
+ DPRINTF(IBE, "Initiating mem op inst [sn:%lli] PC: %#x\n",
+ inst->seqNum, inst->readPC());
+
+ cacheCompletionEvent.inst = inst;
+ inst_fault = inst->initiateAcc();
+ if (inst_fault == NoFault &&
+ status != DcacheMissLoadStall &&
+ status != DcacheMissStoreStall) {
+ inst_fault = inst->completeAcc();
+ }
+ ++thread->funcExeInst;
+ } else {
+ DPRINTF(IBE, "Executing inst [sn:%lli] PC: %#x\n",
+ inst->seqNum, inst->readPC());
+ inst_fault = inst->execute();
+ ++thread->funcExeInst;
+ }
+
+ // Will need to be able to break this loop in case the load
+ // misses. Split access/complete ops would be useful here
+ // with writeback events.
+ if (status == DcacheMissLoadStall) {
+ *instsToExecute = insts_to_execute;
+
+ completed_last_inst = false;
+ break;
+ } else if (status == DcacheMissStoreStall) {
+ // Figure out how to fix this hack. Probably have DcacheMissLoad
+ // vs DcacheMissStore.
+ *instsToExecute = insts_to_execute;
+ completed_last_inst = false;
+/*
+ instList.pop_front();
+ --insts_to_execute;
+ if (inst->traceData) {
+ inst->traceData->finalize();
+ }
+*/
+
+ // Don't really need to stop for a store stall as long as
+ // the memory system is able to handle store forwarding
+ // and such. Breaking out might help avoid the cache
+ // interface becoming blocked.
+ break;
+ }
+
+ inst->setExecuted();
+ inst->setCompleted();
+ inst->setCanCommit();
+
+ instList.pop_front();
+
+ --insts_to_execute;
+ --(*instsToExecute);
+
+ if (inst->traceData) {
+ inst->traceData->finalize();
+ inst->traceData = NULL;
+ }
+
+ if (inst_fault != NoFault) {
+#if FULL_SYSTEM
+ DPRINTF(IBE, "Inst [sn:%lli] PC %#x has a fault\n",
+ inst->seqNum, inst->readPC());
+
+ assert(!thread->inSyscall);
+
+ thread->inSyscall = true;
+
+ // Hack for now; DTB will sometimes need the machine instruction
+ // for when faults happen. So we will set it here, prior to the
+ // DTB possibly needing it for this translation.
+ thread->setInst(
+ static_cast<TheISA::MachInst>(inst->staticInst->machInst));
+
+ // Consider holding onto the trap and waiting until the trap event
+ // happens for this to be executed.
+ inst_fault->invoke(xc);
+
+ // Exit state update mode to avoid accidental updating.
+ thread->inSyscall = false;
+
+ squashPending = true;
+
+ // Generate trap squash event.
+// generateTrapEvent(tid);
+ completed_last_inst = false;
+ break;
+#else // !FULL_SYSTEM
+ panic("fault (%d) detected @ PC %08p", inst_fault,
+ inst->PC);
+#endif // FULL_SYSTEM
+ }
+
+ for (int i = 0; i < inst->numDestRegs(); ++i) {
+ renameTable[inst->destRegIdx(i)] = inst;
+ thread->renameTable[inst->destRegIdx(i)] = inst;
+ ++freed_regs;
+ }
+
+ inst->clearDependents();
+
+ comm->access(0)->doneSeqNum = inst->seqNum;
+
+ if (inst->mispredicted()) {
+ squash(inst->seqNum, inst->readNextPC());
+
+ thread->setNextPC(inst->readNextPC());
+
+ break;
+ } else if (squashPending) {
+ // Something external happened that caused the CPU to squash.
+ // Break out of commit and handle the squash next cycle.
+ break;
+ }
+ // If it didn't mispredict, then it executed fine. Send back its
+ // registers and BP info? What about insts that may still have
+ // latency, like loads? Probably can send back the information after
+ // it is completed.
+
+ // keep an instruction count
+ cpu->numInst++;
+ thread->numInsts++;
+ }
+
+ frontEnd->addFreeRegs(freed_regs);
+
+ assert(insts_to_execute >= 0);
+
+ // Should only advance this if I have executed all instructions.
+ if (insts_to_execute == 0) {
+ numInstsToWB.advance();
+ }
+
+ // Should I set the PC to the next PC here? What do I set next PC to?
+ if (completed_last_inst) {
+ thread->setPC(thread->readNextPC());
+ thread->setNextPC(thread->readPC() + sizeof(MachInst));
+ }
+
+ if (squashPending) {
+ setSquashInfoFromXC();
+ }
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::handleFault()
+{
+ DPRINTF(Commit, "Handling fault from fetch\n");
+
+ assert(!thread->inSyscall);
+
+ thread->inSyscall = true;
+
+ // Consider holding onto the trap and waiting until the trap event
+ // happens for this to be executed.
+ faultFromFetch->invoke(xc);
+
+ // Exit state update mode to avoid accidental updating.
+ thread->inSyscall = false;
+
+ squashPending = true;
+
+ setSquashInfoFromXC();
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::squash(const InstSeqNum &squash_num, const Addr &next_PC)
+{
+ DPRINTF(IBE, "Squashing from [sn:%lli], setting PC to %#x\n",
+ squash_num, next_PC);
+
+ InstListIt squash_it = --(instList.end());
+
+ int freed_regs = 0;
+
+ while (!instList.empty() && (*squash_it)->seqNum > squash_num) {
+ DynInstPtr inst = *squash_it;
+
+ DPRINTF(IBE, "Squashing instruction PC %#x, [sn:%lli].\n",
+ inst->readPC(),
+ inst->seqNum);
+
+ // May cause problems with misc regs
+ freed_regs+= inst->numDestRegs();
+ inst->clearDependents();
+ squash_it--;
+ instList.pop_back();
+ }
+
+ frontEnd->addFreeRegs(freed_regs);
+
+ for (int i = 0; i < latency+1; ++i) {
+ numInstsToWB.advance();
+ }
+
+ squashPending = false;
+
+ // Probably want to make sure that this squash is the one that set the
+ // thread into inSyscall mode.
+ thread->inSyscall = false;
+
+ // Tell front end to squash, reset PC to new one.
+ frontEnd->squash(squash_num, next_PC);
+
+ faultFromFetch = NULL;
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::squashFromXC()
+{
+ // Record that I need to squash
+ squashPending = true;
+
+ thread->inSyscall = true;
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::setSquashInfoFromXC()
+{
+ // Need to handle the case of the instList being empty. In that case
+ // probably any number works, except maybe with stores in the store buffer.
+ squashSeqNum = instList.empty() ? 0 : instList.front()->seqNum - 1;
+
+ squashNextPC = thread->PC;
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::fetchFault(Fault &fault)
+{
+ faultFromFetch = fault;
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::dumpInsts()
+{
+ int num = 0;
+ int valid_num = 0;
+
+ InstListIt inst_list_it = instList.begin();
+
+ cprintf("Inst list size: %i\n", instList.size());
+
+ while (inst_list_it != instList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it++;
+ ++num;
+ }
+}
+
+template <class Impl>
+InorderBackEnd<Impl>::DCacheCompletionEvent::DCacheCompletionEvent(
+ InorderBackEnd *_be)
+ : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
+{
+// this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+InorderBackEnd<Impl>::DCacheCompletionEvent::process()
+{
+ inst->completeAcc();
+ be->status = DcacheMissComplete;
+}
+
+template <class Impl>
+const char *
+InorderBackEnd<Impl>::DCacheCompletionEvent::description()
+{
+ return "DCache completion event";
+}
diff --git a/src/cpu/ozone/inst_queue.cc b/src/cpu/ozone/inst_queue.cc
new file mode 100644
index 000000000..7ce5d67ad
--- /dev/null
+++ b/src/cpu/ozone/inst_queue.cc
@@ -0,0 +1,38 @@
+/*
+ * 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/ozone/dyn_inst.hh"
+#include "cpu/ozone/ozone_impl.hh"
+#include "cpu/ozone/simple_impl.hh"
+#include "cpu/ozone/inst_queue_impl.hh"
+
+// Force instantiation of InstructionQueue.
+template class InstQueue<SimpleImpl>;
+template class InstQueue<OzoneImpl>;
diff --git a/src/cpu/ozone/inst_queue.hh b/src/cpu/ozone/inst_queue.hh
new file mode 100644
index 000000000..0158fd2d2
--- /dev/null
+++ b/src/cpu/ozone/inst_queue.hh
@@ -0,0 +1,508 @@
+/*
+ * 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_OZONE_INST_QUEUE_HH__
+#define __CPU_OZONE_INST_QUEUE_HH__
+
+#include <list>
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "base/timebuf.hh"
+#include "cpu/inst_seq.hh"
+#include "sim/host.hh"
+
+class FUPool;
+class MemInterface;
+
+/**
+ * A standard instruction queue class. It holds ready instructions, in
+ * order, in seperate priority queues to facilitate the scheduling of
+ * instructions. The IQ uses a separate linked list to track dependencies.
+ * Similar to the rename map and the free list, it expects that
+ * floating point registers have their indices start after the integer
+ * registers (ie with 96 int and 96 fp registers, regs 0-95 are integer
+ * and 96-191 are fp). This remains true even for both logical and
+ * physical register indices. The IQ depends on the memory dependence unit to
+ * track when memory operations are ready in terms of ordering; register
+ * dependencies are tracked normally. Right now the IQ also handles the
+ * execution timing; this is mainly to allow back-to-back scheduling without
+ * requiring IEW to be able to peek into the IQ. At the end of the execution
+ * latency, the instruction is put into the queue to execute, where it will
+ * have the execute() function called on it.
+ * @todo: Make IQ able to handle multiple FU pools.
+ */
+template <class Impl>
+class InstQueue
+{
+ public:
+ //Typedefs from the Impl.
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::Params Params;
+ typedef typename Impl::IssueStruct IssueStruct;
+/*
+ typedef typename Impl::CPUPol::IEW IEW;
+ typedef typename Impl::CPUPol::MemDepUnit MemDepUnit;
+ typedef typename Impl::CPUPol::IssueStruct IssueStruct;
+ typedef typename Impl::CPUPol::TimeStruct TimeStruct;
+*/
+ // Typedef of iterator through the list of instructions.
+ typedef typename std::list<DynInstPtr>::iterator ListIt;
+
+ friend class Impl::FullCPU;
+#if 0
+ /** FU completion event class. */
+ class FUCompletion : public Event {
+ private:
+ /** Executing instruction. */
+ DynInstPtr inst;
+
+ /** Index of the FU used for executing. */
+ int fuIdx;
+
+ /** Pointer back to the instruction queue. */
+ InstQueue<Impl> *iqPtr;
+
+ public:
+ /** Construct a FU completion event. */
+ FUCompletion(DynInstPtr &_inst, int fu_idx,
+ InstQueue<Impl> *iq_ptr);
+
+ virtual void process();
+ virtual const char *description();
+ };
+#endif
+ /** Constructs an IQ. */
+ InstQueue(Params *params);
+
+ /** Destructs the IQ. */
+ ~InstQueue();
+
+ /** Returns the name of the IQ. */
+ std::string name() const;
+
+ /** Registers statistics. */
+ void regStats();
+
+ /** Sets CPU pointer. */
+ void setCPU(FullCPU *_cpu) { cpu = _cpu; }
+#if 0
+ /** Sets active threads list. */
+ void setActiveThreads(list<unsigned> *at_ptr);
+
+ /** Sets the IEW pointer. */
+ void setIEW(IEW *iew_ptr) { iewStage = iew_ptr; }
+#endif
+ /** Sets the timer buffer between issue and execute. */
+ void setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2eQueue);
+#if 0
+ /** Sets the global time buffer. */
+ void setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr);
+
+ /** Number of entries needed for given amount of threads. */
+ int entryAmount(int num_threads);
+
+ /** Resets max entries for all threads. */
+ void resetEntries();
+#endif
+ /** Returns total number of free entries. */
+ unsigned numFreeEntries();
+
+ /** Returns number of free entries for a thread. */
+ unsigned numFreeEntries(unsigned tid);
+
+ /** Returns whether or not the IQ is full. */
+ bool isFull();
+
+ /** Returns whether or not the IQ is full for a specific thread. */
+ bool isFull(unsigned tid);
+
+ /** Returns if there are any ready instructions in the IQ. */
+ bool hasReadyInsts();
+
+ /** Inserts a new instruction into the IQ. */
+ void insert(DynInstPtr &new_inst);
+
+ /** Inserts a new, non-speculative instruction into the IQ. */
+ void insertNonSpec(DynInstPtr &new_inst);
+#if 0
+ /**
+ * Advances the tail of the IQ, used if an instruction is not added to the
+ * IQ for scheduling.
+ * @todo: Rename this function.
+ */
+ void advanceTail(DynInstPtr &inst);
+
+ /** Process FU completion event. */
+ void processFUCompletion(DynInstPtr &inst, int fu_idx);
+#endif
+ /**
+ * Schedules ready instructions, adding the ready ones (oldest first) to
+ * the queue to execute.
+ */
+ void scheduleReadyInsts();
+
+ /** Schedules a single specific non-speculative instruction. */
+ void scheduleNonSpec(const InstSeqNum &inst);
+
+ /**
+ * Commits all instructions up to and including the given sequence number,
+ * for a specific thread.
+ */
+ void commit(const InstSeqNum &inst, unsigned tid = 0);
+
+ /** Wakes all dependents of a completed instruction. */
+ void wakeDependents(DynInstPtr &completed_inst);
+
+ /** Adds a ready memory instruction to the ready list. */
+ void addReadyMemInst(DynInstPtr &ready_inst);
+#if 0
+ /**
+ * Reschedules a memory instruction. It will be ready to issue once
+ * replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &resched_inst);
+
+ /** Replays a memory instruction. It must be rescheduled first. */
+ void replayMemInst(DynInstPtr &replay_inst);
+#endif
+ /** Completes a memory operation. */
+ void completeMemInst(DynInstPtr &completed_inst);
+#if 0
+ /** Indicates an ordering violation between a store and a load. */
+ void violation(DynInstPtr &store, DynInstPtr &faulting_load);
+#endif
+ /**
+ * Squashes instructions for a thread. Squashing information is obtained
+ * from the time buffer.
+ */
+ void squash(unsigned tid); // Probably want the ISN
+
+ /** Returns the number of used entries for a thread. */
+ unsigned getCount(unsigned tid) { return count[tid]; };
+
+ /** Updates the number of free entries. */
+ void updateFreeEntries(int num) { freeEntries += num; }
+
+ /** Debug function to print all instructions. */
+ void printInsts();
+
+ private:
+ /** Does the actual squashing. */
+ void doSquash(unsigned tid);
+
+ /////////////////////////
+ // Various pointers
+ /////////////////////////
+
+ /** Pointer to the CPU. */
+ FullCPU *cpu;
+
+ /** Cache interface. */
+ MemInterface *dcacheInterface;
+#if 0
+ /** Pointer to IEW stage. */
+ IEW *iewStage;
+
+ /** The memory dependence unit, which tracks/predicts memory dependences
+ * between instructions.
+ */
+ MemDepUnit memDepUnit[Impl::MaxThreads];
+#endif
+ /** The queue to the execute stage. Issued instructions will be written
+ * into it.
+ */
+ TimeBuffer<IssueStruct> *issueToExecuteQueue;
+#if 0
+ /** The backwards time buffer. */
+ TimeBuffer<TimeStruct> *timeBuffer;
+
+ /** Wire to read information from timebuffer. */
+ typename TimeBuffer<TimeStruct>::wire fromCommit;
+
+ /** Function unit pool. */
+ FUPool *fuPool;
+#endif
+ //////////////////////////////////////
+ // Instruction lists, ready queues, and ordering
+ //////////////////////////////////////
+
+ /** List of all the instructions in the IQ (some of which may be issued). */
+ std::list<DynInstPtr> instList[Impl::MaxThreads];
+
+ /**
+ * Struct for comparing entries to be added to the priority queue. This
+ * gives reverse ordering to the instructions in terms of sequence
+ * numbers: the instructions with smaller sequence numbers (and hence
+ * are older) will be at the top of the priority queue.
+ */
+ struct pqCompare {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum > rhs->seqNum;
+ }
+ };
+
+ /**
+ * Struct for an IQ entry. It includes the instruction and an iterator
+ * to the instruction's spot in the IQ.
+ */
+ struct IQEntry {
+ DynInstPtr inst;
+ ListIt iqIt;
+ };
+
+ typedef std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare>
+ ReadyInstQueue;
+
+ typedef std::map<DynInstPtr, pqCompare> ReadyInstMap;
+ typedef typename std::map<DynInstPtr, pqCompare>::iterator ReadyMapIt;
+
+ /** List of ready instructions.
+ */
+ ReadyInstQueue readyInsts;
+
+ /** List of non-speculative instructions that will be scheduled
+ * once the IQ gets a signal from commit. While it's redundant to
+ * have the key be a part of the value (the sequence number is stored
+ * inside of DynInst), when these instructions are woken up only
+ * the sequence number will be available. Thus it is most efficient to be
+ * able to search by the sequence number alone.
+ */
+ std::map<InstSeqNum, DynInstPtr> nonSpecInsts;
+
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator NonSpecMapIt;
+#if 0
+ /** Entry for the list age ordering by op class. */
+ struct ListOrderEntry {
+ OpClass queueType;
+ InstSeqNum oldestInst;
+ };
+
+ /** List that contains the age order of the oldest instruction of each
+ * ready queue. Used to select the oldest instruction available
+ * among op classes.
+ */
+ std::list<ListOrderEntry> listOrder;
+
+ typedef typename std::list<ListOrderEntry>::iterator ListOrderIt;
+
+ /** Tracks if each ready queue is on the age order list. */
+ bool queueOnList[Num_OpClasses];
+
+ /** Iterators of each ready queue. Points to their spot in the age order
+ * list.
+ */
+ ListOrderIt readyIt[Num_OpClasses];
+
+ /** Add an op class to the age order list. */
+ void addToOrderList(OpClass op_class);
+
+ /**
+ * Called when the oldest instruction has been removed from a ready queue;
+ * this places that ready queue into the proper spot in the age order list.
+ */
+ void moveToYoungerInst(ListOrderIt age_order_it);
+#endif
+ //////////////////////////////////////
+ // Various parameters
+ //////////////////////////////////////
+#if 0
+ /** IQ Resource Sharing Policy */
+ enum IQPolicy {
+ Dynamic,
+ Partitioned,
+ Threshold
+ };
+
+ /** IQ sharing policy for SMT. */
+ IQPolicy iqPolicy;
+#endif
+ /** Number of Total Threads*/
+ unsigned numThreads;
+#if 0
+ /** Pointer to list of active threads. */
+ list<unsigned> *activeThreads;
+#endif
+ /** Per Thread IQ count */
+ unsigned count[Impl::MaxThreads];
+
+ /** Max IQ Entries Per Thread */
+ unsigned maxEntries[Impl::MaxThreads];
+
+ /** Number of free IQ entries left. */
+ unsigned freeEntries;
+
+ /** The number of entries in the instruction queue. */
+ unsigned numEntries;
+
+ /** The total number of instructions that can be issued in one cycle. */
+ unsigned totalWidth;
+#if 0
+ /** The number of physical registers in the CPU. */
+ unsigned numPhysRegs;
+
+ /** The number of physical integer registers in the CPU. */
+ unsigned numPhysIntRegs;
+
+ /** The number of floating point registers in the CPU. */
+ unsigned numPhysFloatRegs;
+#endif
+ /** Delay between commit stage and the IQ.
+ * @todo: Make there be a distinction between the delays within IEW.
+ */
+ unsigned commitToIEWDelay;
+
+ //////////////////////////////////
+ // Variables needed for squashing
+ //////////////////////////////////
+
+ /** The sequence number of the squashed instruction. */
+ InstSeqNum squashedSeqNum[Impl::MaxThreads];
+
+ /** Iterator that points to the last instruction that has been squashed.
+ * This will not be valid unless the IQ is in the process of squashing.
+ */
+ ListIt squashIt[Impl::MaxThreads];
+#if 0
+ ///////////////////////////////////
+ // Dependency graph stuff
+ ///////////////////////////////////
+
+ class DependencyEntry
+ {
+ public:
+ DependencyEntry()
+ : inst(NULL), next(NULL)
+ { }
+
+ DynInstPtr inst;
+ //Might want to include data about what arch. register the
+ //dependence is waiting on.
+ DependencyEntry *next;
+
+ //This function, and perhaps this whole class, stand out a little
+ //bit as they don't fit a classification well. I want access
+ //to the underlying structure of the linked list, yet at
+ //the same time it feels like this should be something abstracted
+ //away. So for now it will sit here, within the IQ, until
+ //a better implementation is decided upon.
+ // This function probably shouldn't be within the entry...
+ void insert(DynInstPtr &new_inst);
+
+ void remove(DynInstPtr &inst_to_remove);
+
+ // Debug variable, remove when done testing.
+ static unsigned mem_alloc_counter;
+ };
+
+ /** Array of linked lists. Each linked list is a list of all the
+ * instructions that depend upon a given register. The actual
+ * register's index is used to index into the graph; ie all
+ * instructions in flight that are dependent upon r34 will be
+ * in the linked list of dependGraph[34].
+ */
+ DependencyEntry *dependGraph;
+
+ /** A cache of the recently woken registers. It is 1 if the register
+ * has been woken up recently, and 0 if the register has been added
+ * to the dependency graph and has not yet received its value. It
+ * is basically a secondary scoreboard, and should pretty much mirror
+ * the scoreboard that exists in the rename map.
+ */
+ vector<bool> regScoreboard;
+
+ /** Adds an instruction to the dependency graph, as a producer. */
+ bool addToDependents(DynInstPtr &new_inst);
+
+ /** Adds an instruction to the dependency graph, as a consumer. */
+ void createDependency(DynInstPtr &new_inst);
+#endif
+ /** Moves an instruction to the ready queue if it is ready. */
+ void addIfReady(DynInstPtr &inst);
+
+ /** Debugging function to count how many entries are in the IQ. It does
+ * a linear walk through the instructions, so do not call this function
+ * during normal execution.
+ */
+ int countInsts();
+#if 0
+ /** Debugging function to dump out the dependency graph.
+ */
+ void dumpDependGraph();
+#endif
+ /** Debugging function to dump all the list sizes, as well as print
+ * out the list of nonspeculative instructions. Should not be used
+ * in any other capacity, but it has no harmful sideaffects.
+ */
+ void dumpLists();
+
+ /** Debugging function to dump out all instructions that are in the
+ * IQ.
+ */
+ void dumpInsts();
+
+ /** Stat for number of instructions added. */
+ Stats::Scalar<> iqInstsAdded;
+ /** Stat for number of non-speculative instructions added. */
+ Stats::Scalar<> iqNonSpecInstsAdded;
+// Stats::Scalar<> iqIntInstsAdded;
+ /** Stat for number of integer instructions issued. */
+ Stats::Scalar<> iqIntInstsIssued;
+// Stats::Scalar<> iqFloatInstsAdded;
+ /** Stat for number of floating point instructions issued. */
+ Stats::Scalar<> iqFloatInstsIssued;
+// Stats::Scalar<> iqBranchInstsAdded;
+ /** Stat for number of branch instructions issued. */
+ Stats::Scalar<> iqBranchInstsIssued;
+// Stats::Scalar<> iqMemInstsAdded;
+ /** Stat for number of memory instructions issued. */
+ Stats::Scalar<> iqMemInstsIssued;
+// Stats::Scalar<> iqMiscInstsAdded;
+ /** Stat for number of miscellaneous instructions issued. */
+ Stats::Scalar<> iqMiscInstsIssued;
+ /** Stat for number of squashed instructions that were ready to issue. */
+ Stats::Scalar<> iqSquashedInstsIssued;
+ /** Stat for number of squashed instructions examined when squashing. */
+ Stats::Scalar<> iqSquashedInstsExamined;
+ /** Stat for number of squashed instruction operands examined when
+ * squashing.
+ */
+ Stats::Scalar<> iqSquashedOperandsExamined;
+ /** Stat for number of non-speculative instructions removed due to a squash.
+ */
+ Stats::Scalar<> iqSquashedNonSpecRemoved;
+
+};
+
+#endif //__CPU_OZONE_INST_QUEUE_HH__
diff --git a/src/cpu/ozone/inst_queue_impl.hh b/src/cpu/ozone/inst_queue_impl.hh
new file mode 100644
index 000000000..f2d80e621
--- /dev/null
+++ b/src/cpu/ozone/inst_queue_impl.hh
@@ -0,0 +1,1343 @@
+/*
+ * 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
+ */
+
+// Todo:
+// Current ordering allows for 0 cycle added-to-scheduled. Could maybe fake
+// it; either do in reverse order, or have added instructions put into a
+// different ready queue that, in scheduleRreadyInsts(), gets put onto the
+// normal ready queue. This would however give only a one cycle delay,
+// but probably is more flexible to actually add in a delay parameter than
+// just running it backwards.
+
+#include <vector>
+
+#include "sim/root.hh"
+
+#include "cpu/ozone/inst_queue.hh"
+#if 0
+template <class Impl>
+InstQueue<Impl>::FUCompletion::FUCompletion(DynInstPtr &_inst,
+ int fu_idx,
+ InstQueue<Impl> *iq_ptr)
+ : Event(&mainEventQueue, Stat_Event_Pri),
+ inst(_inst), fuIdx(fu_idx), iqPtr(iq_ptr)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::FUCompletion::process()
+{
+ iqPtr->processFUCompletion(inst, fuIdx);
+}
+
+
+template <class Impl>
+const char *
+InstQueue<Impl>::FUCompletion::description()
+{
+ return "Functional unit completion event";
+}
+#endif
+template <class Impl>
+InstQueue<Impl>::InstQueue(Params *params)
+ : dcacheInterface(params->dcacheInterface),
+// fuPool(params->fuPool),
+ numEntries(params->numIQEntries),
+ totalWidth(params->issueWidth),
+// numPhysIntRegs(params->numPhysIntRegs),
+// numPhysFloatRegs(params->numPhysFloatRegs),
+ commitToIEWDelay(params->commitToIEWDelay)
+{
+// assert(fuPool);
+
+// numThreads = params->numberOfThreads;
+ numThreads = 1;
+
+ //Initialize thread IQ counts
+ for (int i = 0; i <numThreads; i++) {
+ count[i] = 0;
+ }
+
+ // Initialize the number of free IQ entries.
+ freeEntries = numEntries;
+
+ // Set the number of physical registers as the number of int + float
+// numPhysRegs = numPhysIntRegs + numPhysFloatRegs;
+
+// DPRINTF(IQ, "There are %i physical registers.\n", numPhysRegs);
+
+ //Create an entry for each physical register within the
+ //dependency graph.
+// dependGraph = new DependencyEntry[numPhysRegs];
+
+ // Resize the register scoreboard.
+// regScoreboard.resize(numPhysRegs);
+/*
+ //Initialize Mem Dependence Units
+ for (int i = 0; i < numThreads; i++) {
+ memDepUnit[i].init(params,i);
+ memDepUnit[i].setIQ(this);
+ }
+
+ // Initialize all the head pointers to point to NULL, and all the
+ // entries as unready.
+ // Note that in actuality, the registers corresponding to the logical
+ // registers start off as ready. However this doesn't matter for the
+ // IQ as the instruction should have been correctly told if those
+ // registers are ready in rename. Thus it can all be initialized as
+ // unready.
+ for (int i = 0; i < numPhysRegs; ++i) {
+ dependGraph[i].next = NULL;
+ dependGraph[i].inst = NULL;
+ regScoreboard[i] = false;
+ }
+*/
+ for (int i = 0; i < numThreads; ++i) {
+ squashedSeqNum[i] = 0;
+ }
+/*
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ queueOnList[i] = false;
+ readyIt[i] = listOrder.end();
+ }
+
+ string policy = params->smtIQPolicy;
+
+ //Convert string to lowercase
+ std::transform(policy.begin(), policy.end(), policy.begin(),
+ (int(*)(int)) tolower);
+
+ //Figure out resource sharing policy
+ if (policy == "dynamic") {
+ iqPolicy = Dynamic;
+
+ //Set Max Entries to Total ROB Capacity
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = numEntries;
+ }
+
+ } else if (policy == "partitioned") {
+ iqPolicy = Partitioned;
+
+ //@todo:make work if part_amt doesnt divide evenly.
+ int part_amt = numEntries / numThreads;
+
+ //Divide ROB up evenly
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = part_amt;
+ }
+
+ DPRINTF(Fetch, "IQ sharing policy set to Partitioned:"
+ "%i entries per thread.\n",part_amt);
+
+ } else if (policy == "threshold") {
+ iqPolicy = Threshold;
+
+ double threshold = (double)params->smtIQThreshold / 100;
+
+ int thresholdIQ = (int)((double)threshold * numEntries);
+
+ //Divide up by threshold amount
+ for (int i = 0; i < numThreads; i++) {
+ maxEntries[i] = thresholdIQ;
+ }
+
+ DPRINTF(Fetch, "IQ sharing policy set to Threshold:"
+ "%i entries per thread.\n",thresholdIQ);
+ } else {
+ assert(0 && "Invalid IQ Sharing Policy.Options Are:{Dynamic,"
+ "Partitioned, Threshold}");
+ }
+*/
+}
+
+template <class Impl>
+InstQueue<Impl>::~InstQueue()
+{
+ // Clear the dependency graph
+/*
+ DependencyEntry *curr;
+ DependencyEntry *prev;
+
+ for (int i = 0; i < numPhysRegs; ++i) {
+ curr = dependGraph[i].next;
+
+ while (curr) {
+ DependencyEntry::mem_alloc_counter--;
+
+ prev = curr;
+ curr = prev->next;
+ prev->inst = NULL;
+
+ delete prev;
+ }
+
+ if (dependGraph[i].inst) {
+ dependGraph[i].inst = NULL;
+ }
+
+ dependGraph[i].next = NULL;
+ }
+
+ assert(DependencyEntry::mem_alloc_counter == 0);
+
+ delete [] dependGraph;
+*/
+}
+
+template <class Impl>
+std::string
+InstQueue<Impl>::name() const
+{
+ return cpu->name() + ".iq";
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::regStats()
+{
+ iqInstsAdded
+ .name(name() + ".iqInstsAdded")
+ .desc("Number of instructions added to the IQ (excludes non-spec)")
+ .prereq(iqInstsAdded);
+
+ iqNonSpecInstsAdded
+ .name(name() + ".iqNonSpecInstsAdded")
+ .desc("Number of non-speculative instructions added to the IQ")
+ .prereq(iqNonSpecInstsAdded);
+
+// iqIntInstsAdded;
+
+ iqIntInstsIssued
+ .name(name() + ".iqIntInstsIssued")
+ .desc("Number of integer instructions issued")
+ .prereq(iqIntInstsIssued);
+
+// iqFloatInstsAdded;
+
+ iqFloatInstsIssued
+ .name(name() + ".iqFloatInstsIssued")
+ .desc("Number of float instructions issued")
+ .prereq(iqFloatInstsIssued);
+
+// iqBranchInstsAdded;
+
+ iqBranchInstsIssued
+ .name(name() + ".iqBranchInstsIssued")
+ .desc("Number of branch instructions issued")
+ .prereq(iqBranchInstsIssued);
+
+// iqMemInstsAdded;
+
+ iqMemInstsIssued
+ .name(name() + ".iqMemInstsIssued")
+ .desc("Number of memory instructions issued")
+ .prereq(iqMemInstsIssued);
+
+// iqMiscInstsAdded;
+
+ iqMiscInstsIssued
+ .name(name() + ".iqMiscInstsIssued")
+ .desc("Number of miscellaneous instructions issued")
+ .prereq(iqMiscInstsIssued);
+
+ iqSquashedInstsIssued
+ .name(name() + ".iqSquashedInstsIssued")
+ .desc("Number of squashed instructions issued")
+ .prereq(iqSquashedInstsIssued);
+
+ iqSquashedInstsExamined
+ .name(name() + ".iqSquashedInstsExamined")
+ .desc("Number of squashed instructions iterated over during squash;"
+ " mainly for profiling")
+ .prereq(iqSquashedInstsExamined);
+
+ iqSquashedOperandsExamined
+ .name(name() + ".iqSquashedOperandsExamined")
+ .desc("Number of squashed operands that are examined and possibly "
+ "removed from graph")
+ .prereq(iqSquashedOperandsExamined);
+
+ iqSquashedNonSpecRemoved
+ .name(name() + ".iqSquashedNonSpecRemoved")
+ .desc("Number of squashed non-spec instructions that were removed")
+ .prereq(iqSquashedNonSpecRemoved);
+/*
+ for ( int i=0; i < numThreads; i++) {
+ // Tell mem dependence unit to reg stats as well.
+ memDepUnit[i].regStats();
+ }
+*/
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::setActiveThreads(list<unsigned> *at_ptr)
+{
+ DPRINTF(IQ, "Setting active threads list pointer.\n");
+ activeThreads = at_ptr;
+}
+*/
+template <class Impl>
+void
+InstQueue<Impl>::setIssueToExecuteQueue(TimeBuffer<IssueStruct> *i2e_ptr)
+{
+ DPRINTF(IQ, "Set the issue to execute queue.\n");
+ issueToExecuteQueue = i2e_ptr;
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
+{
+ DPRINTF(IQ, "Set the time buffer.\n");
+ timeBuffer = tb_ptr;
+
+ fromCommit = timeBuffer->getWire(-commitToIEWDelay);
+}
+
+template <class Impl>
+int
+InstQueue<Impl>::entryAmount(int num_threads)
+{
+ if (iqPolicy == Partitioned) {
+ return numEntries / num_threads;
+ } else {
+ return 0;
+ }
+}
+
+
+template <class Impl>
+void
+InstQueue<Impl>::resetEntries()
+{
+ if (iqPolicy != Dynamic || numThreads > 1) {
+ int active_threads = (*activeThreads).size();
+
+ list<unsigned>::iterator threads = (*activeThreads).begin();
+ list<unsigned>::iterator list_end = (*activeThreads).end();
+
+ while (threads != list_end) {
+ if (iqPolicy == Partitioned) {
+ maxEntries[*threads++] = numEntries / active_threads;
+ } else if(iqPolicy == Threshold && active_threads == 1) {
+ maxEntries[*threads++] = numEntries;
+ }
+ }
+ }
+}
+*/
+template <class Impl>
+unsigned
+InstQueue<Impl>::numFreeEntries()
+{
+ return freeEntries;
+}
+
+template <class Impl>
+unsigned
+InstQueue<Impl>::numFreeEntries(unsigned tid)
+{
+ return maxEntries[tid] - count[tid];
+}
+
+// Might want to do something more complex if it knows how many instructions
+// will be issued this cycle.
+template <class Impl>
+bool
+InstQueue<Impl>::isFull()
+{
+ if (freeEntries == 0) {
+ return(true);
+ } else {
+ return(false);
+ }
+}
+
+template <class Impl>
+bool
+InstQueue<Impl>::isFull(unsigned tid)
+{
+ if (numFreeEntries(tid) == 0) {
+ return(true);
+ } else {
+ return(false);
+ }
+}
+
+template <class Impl>
+bool
+InstQueue<Impl>::hasReadyInsts()
+{
+/*
+ if (!listOrder.empty()) {
+ return true;
+ }
+
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ if (!readyInsts[i].empty()) {
+ return true;
+ }
+ }
+
+ return false;
+*/
+ return readyInsts.empty();
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::insert(DynInstPtr &new_inst)
+{
+ // Make sure the instruction is valid
+ assert(new_inst);
+
+ DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n",
+ new_inst->readPC());
+
+ // Check if there are any free entries. Panic if there are none.
+ // Might want to have this return a fault in the future instead of
+ // panicing.
+ assert(freeEntries != 0);
+
+ instList[new_inst->threadNumber].push_back(new_inst);
+
+ // Decrease the number of free entries.
+ --freeEntries;
+
+ //Mark Instruction as in IQ
+// new_inst->setInIQ();
+/*
+ // Look through its source registers (physical regs), and mark any
+ // dependencies.
+ addToDependents(new_inst);
+
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(new_inst);
+*/
+ // If it's a memory instruction, add it to the memory dependency
+ // unit.
+// if (new_inst->isMemRef()) {
+// memDepUnit[new_inst->threadNumber].insert(new_inst);
+// } else {
+ // If the instruction is ready then add it to the ready list.
+ addIfReady(new_inst);
+// }
+
+ ++iqInstsAdded;
+
+
+ //Update Thread IQ Count
+ count[new_inst->threadNumber]++;
+
+ assert(freeEntries == (numEntries - countInsts()));
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::insertNonSpec(DynInstPtr &new_inst)
+{
+ nonSpecInsts[new_inst->seqNum] = new_inst;
+
+ // @todo: Clean up this code; can do it by setting inst as unable
+ // to issue, then calling normal insert on the inst.
+
+ // Make sure the instruction is valid
+ assert(new_inst);
+
+ DPRINTF(IQ, "Adding instruction PC %#x to the IQ.\n",
+ new_inst->readPC());
+
+ // Check if there are any free entries. Panic if there are none.
+ // Might want to have this return a fault in the future instead of
+ // panicing.
+ assert(freeEntries != 0);
+
+ instList[new_inst->threadNumber].push_back(new_inst);
+
+ // Decrease the number of free entries.
+ --freeEntries;
+
+ //Mark Instruction as in IQ
+// new_inst->setInIQ();
+/*
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(new_inst);
+
+ // If it's a memory instruction, add it to the memory dependency
+ // unit.
+ if (new_inst->isMemRef()) {
+ memDepUnit[new_inst->threadNumber].insertNonSpec(new_inst);
+ }
+*/
+ ++iqNonSpecInstsAdded;
+
+ //Update Thread IQ Count
+ count[new_inst->threadNumber]++;
+
+ assert(freeEntries == (numEntries - countInsts()));
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::advanceTail(DynInstPtr &inst)
+{
+ // Have this instruction set itself as the producer of its destination
+ // register(s).
+ createDependency(inst);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::addToOrderList(OpClass op_class)
+{
+ assert(!readyInsts[op_class].empty());
+
+ ListOrderEntry queue_entry;
+
+ queue_entry.queueType = op_class;
+
+ queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
+
+ ListOrderIt list_it = listOrder.begin();
+ ListOrderIt list_end_it = listOrder.end();
+
+ while (list_it != list_end_it) {
+ if ((*list_it).oldestInst > queue_entry.oldestInst) {
+ break;
+ }
+
+ list_it++;
+ }
+
+ readyIt[op_class] = listOrder.insert(list_it, queue_entry);
+ queueOnList[op_class] = true;
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::moveToYoungerInst(ListOrderIt list_order_it)
+{
+ // Get iterator of next item on the list
+ // Delete the original iterator
+ // Determine if the next item is either the end of the list or younger
+ // than the new instruction. If so, then add in a new iterator right here.
+ // If not, then move along.
+ ListOrderEntry queue_entry;
+ OpClass op_class = (*list_order_it).queueType;
+ ListOrderIt next_it = list_order_it;
+
+ ++next_it;
+
+ queue_entry.queueType = op_class;
+ queue_entry.oldestInst = readyInsts[op_class].top()->seqNum;
+
+ while (next_it != listOrder.end() &&
+ (*next_it).oldestInst < queue_entry.oldestInst) {
+ ++next_it;
+ }
+
+ readyIt[op_class] = listOrder.insert(next_it, queue_entry);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::processFUCompletion(DynInstPtr &inst, int fu_idx)
+{
+ // The CPU could have been sleeping until this op completed (*extremely*
+ // long latency op). Wake it if it was. This may be overkill.
+ iewStage->wakeCPU();
+
+ fuPool->freeUnit(fu_idx);
+
+ int &size = issueToExecuteQueue->access(0)->size;
+
+ issueToExecuteQueue->access(0)->insts[size++] = inst;
+}
+*/
+// @todo: Figure out a better way to remove the squashed items from the
+// lists. Checking the top item of each list to see if it's squashed
+// wastes time and forces jumps.
+template <class Impl>
+void
+InstQueue<Impl>::scheduleReadyInsts()
+{
+ DPRINTF(IQ, "Attempting to schedule ready instructions from "
+ "the IQ.\n");
+
+// IssueStruct *i2e_info = issueToExecuteQueue->access(0);
+/*
+ // Will need to reorder the list if either a queue is not on the list,
+ // or it has an older instruction than last time.
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ if (!readyInsts[i].empty()) {
+ if (!queueOnList[i]) {
+ addToOrderList(OpClass(i));
+ } else if (readyInsts[i].top()->seqNum <
+ (*readyIt[i]).oldestInst) {
+ listOrder.erase(readyIt[i]);
+ addToOrderList(OpClass(i));
+ }
+ }
+ }
+
+ // Have iterator to head of the list
+ // While I haven't exceeded bandwidth or reached the end of the list,
+ // Try to get a FU that can do what this op needs.
+ // If successful, change the oldestInst to the new top of the list, put
+ // the queue in the proper place in the list.
+ // Increment the iterator.
+ // This will avoid trying to schedule a certain op class if there are no
+ // FUs that handle it.
+ ListOrderIt order_it = listOrder.begin();
+ ListOrderIt order_end_it = listOrder.end();
+ int total_issued = 0;
+ int exec_queue_slot = i2e_info->size;
+
+ while (exec_queue_slot < totalWidth && order_it != order_end_it) {
+ OpClass op_class = (*order_it).queueType;
+
+ assert(!readyInsts[op_class].empty());
+
+ DynInstPtr issuing_inst = readyInsts[op_class].top();
+
+ assert(issuing_inst->seqNum == (*order_it).oldestInst);
+
+ if (issuing_inst->isSquashed()) {
+ readyInsts[op_class].pop();
+
+ if (!readyInsts[op_class].empty()) {
+ moveToYoungerInst(order_it);
+ } else {
+ readyIt[op_class] = listOrder.end();
+ queueOnList[op_class] = false;
+ }
+
+ listOrder.erase(order_it++);
+
+ ++iqSquashedInstsIssued;
+
+ continue;
+ }
+
+ int idx = fuPool->getUnit(op_class);
+
+ if (idx != -1) {
+ int op_latency = fuPool->getOpLatency(op_class);
+
+ if (op_latency == 1) {
+ i2e_info->insts[exec_queue_slot++] = issuing_inst;
+ i2e_info->size++;
+
+ // Add the FU onto the list of FU's to be freed next cycle.
+ fuPool->freeUnit(idx);
+ } else {
+ int issue_latency = fuPool->getIssueLatency(op_class);
+
+ if (issue_latency > 1) {
+ // Generate completion event for the FU
+ FUCompletion *execution = new FUCompletion(issuing_inst,
+ idx, this);
+
+ execution->schedule(curTick + issue_latency - 1);
+ } else {
+ i2e_info->insts[exec_queue_slot++] = issuing_inst;
+ i2e_info->size++;
+
+ // Add the FU onto the list of FU's to be freed next cycle.
+ fuPool->freeUnit(idx);
+ }
+ }
+
+ DPRINTF(IQ, "Thread %i: Issuing instruction PC %#x "
+ "[sn:%lli]\n",
+ issuing_inst->threadNumber, issuing_inst->readPC(),
+ issuing_inst->seqNum);
+
+ readyInsts[op_class].pop();
+
+ if (!readyInsts[op_class].empty()) {
+ moveToYoungerInst(order_it);
+ } else {
+ readyIt[op_class] = listOrder.end();
+ queueOnList[op_class] = false;
+ }
+
+ issuing_inst->setIssued();
+ ++total_issued;
+
+ if (!issuing_inst->isMemRef()) {
+ // Memory instructions can not be freed from the IQ until they
+ // complete.
+ ++freeEntries;
+ count[issuing_inst->threadNumber]--;
+ issuing_inst->removeInIQ();
+ } else {
+ memDepUnit[issuing_inst->threadNumber].issue(issuing_inst);
+ }
+
+ listOrder.erase(order_it++);
+ } else {
+ ++order_it;
+ }
+ }
+
+ if (total_issued) {
+ cpu->activityThisCycle();
+ } else {
+ DPRINTF(IQ, "Not able to schedule any instructions.\n");
+ }
+*/
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::scheduleNonSpec(const InstSeqNum &inst)
+{
+ DPRINTF(IQ, "Marking nonspeculative instruction with sequence "
+ "number %i as ready to execute.\n", inst);
+
+ NonSpecMapIt inst_it = nonSpecInsts.find(inst);
+
+ assert(inst_it != nonSpecInsts.end());
+
+// unsigned tid = (*inst_it).second->threadNumber;
+
+ // Mark this instruction as ready to issue.
+ (*inst_it).second->setCanIssue();
+
+ // Now schedule the instruction.
+// if (!(*inst_it).second->isMemRef()) {
+ addIfReady((*inst_it).second);
+// } else {
+// memDepUnit[tid].nonSpecInstReady((*inst_it).second);
+// }
+
+ nonSpecInsts.erase(inst_it);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::commit(const InstSeqNum &inst, unsigned tid)
+{
+ /*Need to go through each thread??*/
+ DPRINTF(IQ, "[tid:%i]: Committing instructions older than [sn:%i]\n",
+ tid,inst);
+
+ ListIt iq_it = instList[tid].begin();
+
+ while (iq_it != instList[tid].end() &&
+ (*iq_it)->seqNum <= inst) {
+ ++iq_it;
+ instList[tid].pop_front();
+ }
+
+ assert(freeEntries == (numEntries - countInsts()));
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::wakeDependents(DynInstPtr &completed_inst)
+{
+ DPRINTF(IQ, "Waking dependents of completed instruction.\n");
+ // Look at the physical destination register of the DynInst
+ // and look it up on the dependency graph. Then mark as ready
+ // any instructions within the instruction queue.
+/*
+ DependencyEntry *curr;
+ DependencyEntry *prev;
+*/
+ // Tell the memory dependence unit to wake any dependents on this
+ // instruction if it is a memory instruction. Also complete the memory
+ // instruction at this point since we know it executed fine.
+ // @todo: Might want to rename "completeMemInst" to
+ // something that indicates that it won't need to be replayed, and call
+ // this earlier. Might not be a big deal.
+ if (completed_inst->isMemRef()) {
+// memDepUnit[completed_inst->threadNumber].wakeDependents(completed_inst);
+ completeMemInst(completed_inst);
+ }
+ completed_inst->wakeDependents();
+/*
+ for (int dest_reg_idx = 0;
+ dest_reg_idx < completed_inst->numDestRegs();
+ dest_reg_idx++)
+ {
+ PhysRegIndex dest_reg =
+ completed_inst->renamedDestRegIdx(dest_reg_idx);
+
+ // Special case of uniq or control registers. They are not
+ // handled by the IQ and thus have no dependency graph entry.
+ // @todo Figure out a cleaner way to handle this.
+ if (dest_reg >= numPhysRegs) {
+ continue;
+ }
+
+ DPRINTF(IQ, "Waking any dependents on register %i.\n",
+ (int) dest_reg);
+
+ //Maybe abstract this part into a function.
+ //Go through the dependency chain, marking the registers as ready
+ //within the waiting instructions.
+
+ curr = dependGraph[dest_reg].next;
+
+ while (curr) {
+ DPRINTF(IQ, "Waking up a dependent instruction, PC%#x.\n",
+ curr->inst->readPC());
+
+ // Might want to give more information to the instruction
+ // so that it knows which of its source registers is ready.
+ // However that would mean that the dependency graph entries
+ // would need to hold the src_reg_idx.
+ curr->inst->markSrcRegReady();
+
+ addIfReady(curr->inst);
+
+ DependencyEntry::mem_alloc_counter--;
+
+ prev = curr;
+ curr = prev->next;
+ prev->inst = NULL;
+
+ delete prev;
+ }
+
+ // Reset the head node now that all of its dependents have been woken
+ // up.
+ dependGraph[dest_reg].next = NULL;
+ dependGraph[dest_reg].inst = NULL;
+
+ // Mark the scoreboard as having that register ready.
+ regScoreboard[dest_reg] = true;
+ }
+*/
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::addReadyMemInst(DynInstPtr &ready_inst)
+{
+ OpClass op_class = ready_inst->opClass();
+
+ readyInsts.push(ready_inst);
+
+ DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
+ "the ready list, PC %#x opclass:%i [sn:%lli].\n",
+ ready_inst->readPC(), op_class, ready_inst->seqNum);
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::rescheduleMemInst(DynInstPtr &resched_inst)
+{
+ memDepUnit[resched_inst->threadNumber].reschedule(resched_inst);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::replayMemInst(DynInstPtr &replay_inst)
+{
+ memDepUnit[replay_inst->threadNumber].replay(replay_inst);
+}
+*/
+template <class Impl>
+void
+InstQueue<Impl>::completeMemInst(DynInstPtr &completed_inst)
+{
+ int tid = completed_inst->threadNumber;
+
+ DPRINTF(IQ, "Completing mem instruction PC:%#x [sn:%lli]\n",
+ completed_inst->readPC(), completed_inst->seqNum);
+
+ ++freeEntries;
+
+// completed_inst->memOpDone = true;
+
+// memDepUnit[tid].completed(completed_inst);
+
+ count[tid]--;
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::violation(DynInstPtr &store,
+ DynInstPtr &faulting_load)
+{
+ memDepUnit[store->threadNumber].violation(store, faulting_load);
+}
+*/
+template <class Impl>
+void
+InstQueue<Impl>::squash(unsigned tid)
+{
+ DPRINTF(IQ, "[tid:%i]: Starting to squash instructions in "
+ "the IQ.\n", tid);
+
+ // Read instruction sequence number of last instruction out of the
+ // time buffer.
+// squashedSeqNum[tid] = fromCommit->commitInfo[tid].doneSeqNum;
+
+ // Setup the squash iterator to point to the tail.
+ squashIt[tid] = instList[tid].end();
+ --squashIt[tid];
+
+ // Call doSquash if there are insts in the IQ
+ if (count[tid] > 0) {
+ doSquash(tid);
+ }
+
+ // Also tell the memory dependence unit to squash.
+// memDepUnit[tid].squash(squashedSeqNum[tid], tid);
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::doSquash(unsigned tid)
+{
+ // Make sure the squashed sequence number is valid.
+ assert(squashedSeqNum[tid] != 0);
+
+ DPRINTF(IQ, "[tid:%i]: Squashing until sequence number %i!\n",
+ tid, squashedSeqNum[tid]);
+
+ // Squash any instructions younger than the squashed sequence number
+ // given.
+ while (squashIt[tid] != instList[tid].end() &&
+ (*squashIt[tid])->seqNum > squashedSeqNum[tid]) {
+
+ DynInstPtr squashed_inst = (*squashIt[tid]);
+
+ // Only handle the instruction if it actually is in the IQ and
+ // hasn't already been squashed in the IQ.
+ if (squashed_inst->threadNumber != tid ||
+ squashed_inst->isSquashedInIQ()) {
+ --squashIt[tid];
+ continue;
+ }
+
+ if (!squashed_inst->isIssued() ||
+ (squashed_inst->isMemRef()/* &&
+ !squashed_inst->memOpDone*/)) {
+
+ // Remove the instruction from the dependency list.
+ if (!squashed_inst->isNonSpeculative()) {
+/*
+ for (int src_reg_idx = 0;
+ src_reg_idx < squashed_inst->numSrcRegs();
+ src_reg_idx++)
+ {
+ PhysRegIndex src_reg =
+ squashed_inst->renamedSrcRegIdx(src_reg_idx);
+
+ // Only remove it from the dependency graph if it was
+ // placed there in the first place.
+ // HACK: This assumes that instructions woken up from the
+ // dependency chain aren't informed that a specific src
+ // register has become ready. This may not always be true
+ // in the future.
+ // Instead of doing a linked list traversal, we can just
+ // remove these squashed instructions either at issue time,
+ // or when the register is overwritten. The only downside
+ // to this is it leaves more room for error.
+
+ if (!squashed_inst->isReadySrcRegIdx(src_reg_idx) &&
+ src_reg < numPhysRegs) {
+ dependGraph[src_reg].remove(squashed_inst);
+ }
+
+
+ ++iqSquashedOperandsExamined;
+ }
+*/
+ // Might want to remove producers as well.
+ } else {
+ nonSpecInsts[squashed_inst->seqNum] = NULL;
+
+ nonSpecInsts.erase(squashed_inst->seqNum);
+
+ ++iqSquashedNonSpecRemoved;
+ }
+
+ // Might want to also clear out the head of the dependency graph.
+
+ // Mark it as squashed within the IQ.
+ squashed_inst->setSquashedInIQ();
+
+ // @todo: Remove this hack where several statuses are set so the
+ // inst will flow through the rest of the pipeline.
+ squashed_inst->setIssued();
+ squashed_inst->setCanCommit();
+// squashed_inst->removeInIQ();
+
+ //Update Thread IQ Count
+ count[squashed_inst->threadNumber]--;
+
+ ++freeEntries;
+
+ if (numThreads > 1) {
+ DPRINTF(IQ, "[tid:%i]: Instruction PC %#x squashed.\n",
+ tid, squashed_inst->readPC());
+ } else {
+ DPRINTF(IQ, "Instruction PC %#x squashed.\n",
+ squashed_inst->readPC());
+ }
+ }
+
+ --squashIt[tid];
+ ++iqSquashedInstsExamined;
+ }
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::DependencyEntry::insert(DynInstPtr &new_inst)
+{
+ //Add this new, dependent instruction at the head of the dependency
+ //chain.
+
+ // First create the entry that will be added to the head of the
+ // dependency chain.
+ DependencyEntry *new_entry = new DependencyEntry;
+ new_entry->next = this->next;
+ new_entry->inst = new_inst;
+
+ // Then actually add it to the chain.
+ this->next = new_entry;
+
+ ++mem_alloc_counter;
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::DependencyEntry::remove(DynInstPtr &inst_to_remove)
+{
+ DependencyEntry *prev = this;
+ DependencyEntry *curr = this->next;
+
+ // Make sure curr isn't NULL. Because this instruction is being
+ // removed from a dependency list, it must have been placed there at
+ // an earlier time. The dependency chain should not be empty,
+ // unless the instruction dependent upon it is already ready.
+ if (curr == NULL) {
+ return;
+ }
+
+ // Find the instruction to remove within the dependency linked list.
+ while (curr->inst != inst_to_remove) {
+ prev = curr;
+ curr = curr->next;
+
+ assert(curr != NULL);
+ }
+
+ // Now remove this instruction from the list.
+ prev->next = curr->next;
+
+ --mem_alloc_counter;
+
+ // Could push this off to the destructor of DependencyEntry
+ curr->inst = NULL;
+
+ delete curr;
+}
+
+template <class Impl>
+bool
+InstQueue<Impl>::addToDependents(DynInstPtr &new_inst)
+{
+ // Loop through the instruction's source registers, adding
+ // them to the dependency list if they are not ready.
+ int8_t total_src_regs = new_inst->numSrcRegs();
+ bool return_val = false;
+
+ for (int src_reg_idx = 0;
+ src_reg_idx < total_src_regs;
+ src_reg_idx++)
+ {
+ // Only add it to the dependency graph if it's not ready.
+ if (!new_inst->isReadySrcRegIdx(src_reg_idx)) {
+ PhysRegIndex src_reg = new_inst->renamedSrcRegIdx(src_reg_idx);
+
+ // Check the IQ's scoreboard to make sure the register
+ // hasn't become ready while the instruction was in flight
+ // between stages. Only if it really isn't ready should
+ // it be added to the dependency graph.
+ if (src_reg >= numPhysRegs) {
+ continue;
+ } else if (regScoreboard[src_reg] == false) {
+ DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
+ "is being added to the dependency chain.\n",
+ new_inst->readPC(), src_reg);
+
+ dependGraph[src_reg].insert(new_inst);
+
+ // Change the return value to indicate that something
+ // was added to the dependency graph.
+ return_val = true;
+ } else {
+ DPRINTF(IQ, "Instruction PC %#x has src reg %i that "
+ "became ready before it reached the IQ.\n",
+ new_inst->readPC(), src_reg);
+ // Mark a register ready within the instruction.
+ new_inst->markSrcRegReady();
+ }
+ }
+ }
+
+ return return_val;
+}
+
+template <class Impl>
+void
+InstQueue<Impl>::createDependency(DynInstPtr &new_inst)
+{
+ //Actually nothing really needs to be marked when an
+ //instruction becomes the producer of a register's value,
+ //but for convenience a ptr to the producing instruction will
+ //be placed in the head node of the dependency links.
+ int8_t total_dest_regs = new_inst->numDestRegs();
+
+ for (int dest_reg_idx = 0;
+ dest_reg_idx < total_dest_regs;
+ dest_reg_idx++)
+ {
+ PhysRegIndex dest_reg = new_inst->renamedDestRegIdx(dest_reg_idx);
+
+ // Instructions that use the misc regs will have a reg number
+ // higher than the normal physical registers. In this case these
+ // registers are not renamed, and there is no need to track
+ // dependencies as these instructions must be executed at commit.
+ if (dest_reg >= numPhysRegs) {
+ continue;
+ }
+
+ if (dependGraph[dest_reg].next) {
+ dumpDependGraph();
+ panic("Dependency graph %i not empty!", dest_reg);
+ }
+
+ dependGraph[dest_reg].inst = new_inst;
+
+ // Mark the scoreboard to say it's not yet ready.
+ regScoreboard[dest_reg] = false;
+ }
+}
+*/
+template <class Impl>
+void
+InstQueue<Impl>::addIfReady(DynInstPtr &inst)
+{
+ //If the instruction now has all of its source registers
+ // available, then add it to the list of ready instructions.
+ if (inst->readyToIssue()) {
+
+ //Add the instruction to the proper ready list.
+ if (inst->isMemRef()) {
+
+ DPRINTF(IQ, "Checking if memory instruction can issue.\n");
+
+ // Message to the mem dependence unit that this instruction has
+ // its registers ready.
+
+// memDepUnit[inst->threadNumber].regsReady(inst);
+
+ return;
+ }
+
+ OpClass op_class = inst->opClass();
+
+ DPRINTF(IQ, "Instruction is ready to issue, putting it onto "
+ "the ready list, PC %#x opclass:%i [sn:%lli].\n",
+ inst->readPC(), op_class, inst->seqNum);
+
+ readyInsts.push(inst);
+ }
+}
+
+template <class Impl>
+int
+InstQueue<Impl>::countInsts()
+{
+ //ksewell:This works but definitely could use a cleaner write
+ //with a more intuitive way of counting. Right now it's
+ //just brute force ....
+
+#if 0
+ int total_insts = 0;
+
+ for (int i = 0; i < numThreads; ++i) {
+ ListIt count_it = instList[i].begin();
+
+ while (count_it != instList[i].end()) {
+ if (!(*count_it)->isSquashed() && !(*count_it)->isSquashedInIQ()) {
+ if (!(*count_it)->isIssued()) {
+ ++total_insts;
+ } else if ((*count_it)->isMemRef() &&
+ !(*count_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++total_insts;
+ }
+ }
+
+ ++count_it;
+ }
+ }
+
+ return total_insts;
+#else
+ return numEntries - freeEntries;
+#endif
+}
+/*
+template <class Impl>
+void
+InstQueue<Impl>::dumpDependGraph()
+{
+ DependencyEntry *curr;
+
+ for (int i = 0; i < numPhysRegs; ++i)
+ {
+ curr = &dependGraph[i];
+
+ if (curr->inst) {
+ cprintf("dependGraph[%i]: producer: %#x [sn:%lli] consumer: ",
+ i, curr->inst->readPC(), curr->inst->seqNum);
+ } else {
+ cprintf("dependGraph[%i]: No producer. consumer: ", i);
+ }
+
+ while (curr->next != NULL) {
+ curr = curr->next;
+
+ cprintf("%#x [sn:%lli] ",
+ curr->inst->readPC(), curr->inst->seqNum);
+ }
+
+ cprintf("\n");
+ }
+}
+*/
+template <class Impl>
+void
+InstQueue<Impl>::dumpLists()
+{
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ cprintf("Ready list %i size: %i\n", i, readyInsts.size());
+
+ cprintf("\n");
+ }
+
+ cprintf("Non speculative list size: %i\n", nonSpecInsts.size());
+
+ NonSpecMapIt non_spec_it = nonSpecInsts.begin();
+ NonSpecMapIt non_spec_end_it = nonSpecInsts.end();
+
+ cprintf("Non speculative list: ");
+
+ while (non_spec_it != non_spec_end_it) {
+ cprintf("%#x [sn:%lli]", (*non_spec_it).second->readPC(),
+ (*non_spec_it).second->seqNum);
+ ++non_spec_it;
+ }
+
+ cprintf("\n");
+/*
+ ListOrderIt list_order_it = listOrder.begin();
+ ListOrderIt list_order_end_it = listOrder.end();
+ int i = 1;
+
+ cprintf("List order: ");
+
+ while (list_order_it != list_order_end_it) {
+ cprintf("%i OpClass:%i [sn:%lli] ", i, (*list_order_it).queueType,
+ (*list_order_it).oldestInst);
+
+ ++list_order_it;
+ ++i;
+ }
+*/
+ cprintf("\n");
+}
+
+
+template <class Impl>
+void
+InstQueue<Impl>::dumpInsts()
+{
+ for (int i = 0; i < numThreads; ++i) {
+// int num = 0;
+// int valid_num = 0;
+/*
+ ListIt inst_list_it = instList[i].begin();
+
+ while (inst_list_it != instList[i].end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it++;
+ ++num;
+ }
+*/
+ }
+}
diff --git a/src/cpu/ozone/lsq_unit.cc b/src/cpu/ozone/lsq_unit.cc
new file mode 100644
index 000000000..e37971dba
--- /dev/null
+++ b/src/cpu/ozone/lsq_unit.cc
@@ -0,0 +1,36 @@
+/*
+ * 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/ozone/ozone_impl.hh"
+#include "cpu/ozone/lsq_unit_impl.hh"
+
+// Force the instantiation of LDSTQ for all the implementations we care about.
+template class OzoneLSQ<OzoneImpl>;
+
diff --git a/src/cpu/ozone/lsq_unit.hh b/src/cpu/ozone/lsq_unit.hh
new file mode 100644
index 000000000..1b5340e55
--- /dev/null
+++ b/src/cpu/ozone/lsq_unit.hh
@@ -0,0 +1,636 @@
+/*
+ * 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_OZONE_LSQ_UNIT_HH__
+#define __CPU_OZONE_LSQ_UNIT_HH__
+
+#include <map>
+#include <queue>
+#include <algorithm>
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "config/full_system.hh"
+#include "base/hashmap.hh"
+#include "cpu/inst_seq.hh"
+#include "mem/mem_interface.hh"
+//#include "mem/page_table.hh"
+#include "sim/sim_object.hh"
+
+class PageTable;
+
+/**
+ * Class that implements the actual LQ and SQ for each specific thread.
+ * Both are circular queues; load entries are freed upon committing, while
+ * store entries are freed once they writeback. The LSQUnit tracks if there
+ * are memory ordering violations, and also detects partial load to store
+ * forwarding cases (a store only has part of a load's data) that requires
+ * the load to wait until the store writes back. In the former case it
+ * holds onto the instruction until the dependence unit looks at it, and
+ * in the latter it stalls the LSQ until the store writes back. At that
+ * point the load is replayed.
+ */
+template <class Impl>
+class OzoneLSQ {
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::FullCPU FullCPU;
+ typedef typename Impl::BackEnd BackEnd;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::IssueStruct IssueStruct;
+
+ typedef TheISA::IntReg IntReg;
+
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt;
+
+ private:
+ class StoreCompletionEvent : public Event {
+ public:
+ /** Constructs a store completion event. */
+ StoreCompletionEvent(int store_idx, Event *wb_event, OzoneLSQ *lsq_ptr);
+
+ /** Processes the store completion event. */
+ void process();
+
+ /** Returns the description of this event. */
+ const char *description();
+
+ private:
+ /** The store index of the store being written back. */
+ int storeIdx;
+ /** The writeback event for the store. Needed for store
+ * conditionals.
+ */
+ Event *wbEvent;
+ /** The pointer to the LSQ unit that issued the store. */
+ OzoneLSQ<Impl> *lsqPtr;
+ };
+
+ friend class StoreCompletionEvent;
+
+ public:
+ /** Constructs an LSQ unit. init() must be called prior to use. */
+ OzoneLSQ();
+
+ /** Initializes the LSQ unit with the specified number of entries. */
+ void init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id);
+
+ /** Returns the name of the LSQ unit. */
+ std::string name() const;
+
+ /** Sets the CPU pointer. */
+ void setCPU(FullCPU *cpu_ptr)
+ { cpu = cpu_ptr; }
+
+ /** Sets the back-end stage pointer. */
+ void setBE(BackEnd *be_ptr)
+ { be = be_ptr; }
+
+ /** Ticks the LSQ unit, which in this case only resets the number of
+ * used cache ports.
+ * @todo: Move the number of used ports up to the LSQ level so it can
+ * be shared by all LSQ units.
+ */
+ void tick() { usedPorts = 0; }
+
+ /** Inserts an instruction. */
+ void insert(DynInstPtr &inst);
+ /** Inserts a load instruction. */
+ void insertLoad(DynInstPtr &load_inst);
+ /** Inserts a store instruction. */
+ void insertStore(DynInstPtr &store_inst);
+
+ /** Executes a load instruction. */
+ Fault executeLoad(DynInstPtr &inst);
+
+ Fault executeLoad(int lq_idx);
+ /** Executes a store instruction. */
+ Fault executeStore(DynInstPtr &inst);
+
+ /** Commits the head load. */
+ void commitLoad();
+ /** Commits a specific load, given by the sequence number. */
+ void commitLoad(InstSeqNum &inst);
+ /** Commits loads older than a specific sequence number. */
+ void commitLoads(InstSeqNum &youngest_inst);
+
+ /** Commits stores older than a specific sequence number. */
+ void commitStores(InstSeqNum &youngest_inst);
+
+ /** Writes back stores. */
+ void writebackStores();
+
+ // @todo: Include stats in the LSQ unit.
+ //void regStats();
+
+ /** Clears all the entries in the LQ. */
+ void clearLQ();
+
+ /** Clears all the entries in the SQ. */
+ void clearSQ();
+
+ /** Resizes the LQ to a given size. */
+ void resizeLQ(unsigned size);
+
+ /** Resizes the SQ to a given size. */
+ void resizeSQ(unsigned size);
+
+ /** Squashes all instructions younger than a specific sequence number. */
+ void squash(const InstSeqNum &squashed_num);
+
+ /** Returns if there is a memory ordering violation. Value is reset upon
+ * call to getMemDepViolator().
+ */
+ bool violation() { return memDepViolator; }
+
+ /** Returns the memory ordering violator. */
+ DynInstPtr getMemDepViolator();
+
+ /** Returns if a load became blocked due to the memory system. It clears
+ * the bool's value upon this being called.
+ */
+ inline bool loadBlocked();
+
+ /** Returns the number of free entries (min of free LQ and SQ entries). */
+ unsigned numFreeEntries();
+
+ /** Returns the number of loads ready to execute. */
+ int numLoadsReady();
+
+ /** Returns the number of loads in the LQ. */
+ int numLoads() { return loads; }
+
+ /** Returns the number of stores in the SQ. */
+ int numStores() { return stores; }
+
+ /** Returns if either the LQ or SQ is full. */
+ bool isFull() { return lqFull() || sqFull(); }
+
+ /** Returns if the LQ is full. */
+ bool lqFull() { return loads >= (LQEntries - 1); }
+
+ /** Returns if the SQ is full. */
+ bool sqFull() { return stores >= (SQEntries - 1); }
+
+ /** Debugging function to dump instructions in the LSQ. */
+ void dumpInsts();
+
+ /** Returns the number of instructions in the LSQ. */
+ unsigned getCount() { return loads + stores; }
+
+ /** Returns if there are any stores to writeback. */
+ bool hasStoresToWB() { return storesToWB; }
+
+ /** Returns the number of stores to writeback. */
+ int numStoresToWB() { return storesToWB; }
+
+ /** Returns if the LSQ unit will writeback on this cycle. */
+ bool willWB() { return storeQueue[storeWBIdx].canWB &&
+ !storeQueue[storeWBIdx].completed &&
+ !dcacheInterface->isBlocked(); }
+
+ private:
+ /** Completes the store at the specified index. */
+ void completeStore(int store_idx);
+
+ /** Increments the given store index (circular queue). */
+ inline void incrStIdx(int &store_idx);
+ /** Decrements the given store index (circular queue). */
+ inline void decrStIdx(int &store_idx);
+ /** Increments the given load index (circular queue). */
+ inline void incrLdIdx(int &load_idx);
+ /** Decrements the given load index (circular queue). */
+ inline void decrLdIdx(int &load_idx);
+
+ private:
+ /** Pointer to the CPU. */
+ FullCPU *cpu;
+
+ /** Pointer to the back-end stage. */
+ BackEnd *be;
+
+ /** Pointer to the D-cache. */
+ MemInterface *dcacheInterface;
+
+ /** Pointer to the page table. */
+ PageTable *pTable;
+
+ public:
+ struct SQEntry {
+ /** Constructs an empty store queue entry. */
+ SQEntry()
+ : inst(NULL), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0)
+ { }
+
+ /** Constructs a store queue entry for a given instruction. */
+ SQEntry(DynInstPtr &_inst)
+ : inst(_inst), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0)
+ { }
+
+ /** The store instruction. */
+ DynInstPtr inst;
+ /** The memory request for the store. */
+ MemReqPtr req;
+ /** The size of the store. */
+ int size;
+ /** The store data. */
+ IntReg data;
+ /** Whether or not the store can writeback. */
+ bool canWB;
+ /** Whether or not the store is committed. */
+ bool committed;
+ /** Whether or not the store is completed. */
+ bool completed;
+ };
+
+ enum Status {
+ Running,
+ Idle,
+ DcacheMissStall,
+ DcacheMissSwitch
+ };
+
+ private:
+ /** The OzoneLSQ thread id. */
+ unsigned lsqID;
+
+ /** The status of the LSQ unit. */
+ Status _status;
+
+ /** The store queue. */
+ std::vector<SQEntry> storeQueue;
+
+ /** The load queue. */
+ std::vector<DynInstPtr> loadQueue;
+
+ // Consider making these 16 bits
+ /** The number of LQ entries. */
+ unsigned LQEntries;
+ /** The number of SQ entries. */
+ unsigned SQEntries;
+
+ /** The number of load instructions in the LQ. */
+ int loads;
+ /** The number of store instructions in the SQ (excludes those waiting to
+ * writeback).
+ */
+ int stores;
+ /** The number of store instructions in the SQ waiting to writeback. */
+ int storesToWB;
+
+ /** The index of the head instruction in the LQ. */
+ int loadHead;
+ /** The index of the tail instruction in the LQ. */
+ int loadTail;
+
+ /** The index of the head instruction in the SQ. */
+ int storeHead;
+ /** The index of the first instruction that is ready to be written back,
+ * and has not yet been written back.
+ */
+ int storeWBIdx;
+ /** The index of the tail instruction in the SQ. */
+ int storeTail;
+
+ /// @todo Consider moving to a more advanced model with write vs read ports
+ /** The number of cache ports available each cycle. */
+ int cachePorts;
+
+ /** The number of used cache ports in this cycle. */
+ int usedPorts;
+
+ //list<InstSeqNum> mshrSeqNums;
+
+ //Stats::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ /** Wire to read information from the issue stage time queue. */
+ typename TimeBuffer<IssueStruct>::wire fromIssue;
+
+ // Make these per thread?
+ /** Whether or not the LSQ is stalled. */
+ bool stalled;
+ /** The store that causes the stall due to partial store to load
+ * forwarding.
+ */
+ InstSeqNum stallingStoreIsn;
+ /** The index of the above store. */
+ int stallingLoadIdx;
+
+ /** Whether or not a load is blocked due to the memory system. It is
+ * cleared when this value is checked via loadBlocked().
+ */
+ bool isLoadBlocked;
+
+ /** The oldest faulting load instruction. */
+ DynInstPtr loadFaultInst;
+ /** The oldest faulting store instruction. */
+ DynInstPtr storeFaultInst;
+
+ /** The oldest load that caused a memory ordering violation. */
+ DynInstPtr memDepViolator;
+
+ // Will also need how many read/write ports the Dcache has. Or keep track
+ // of that in stage that is one level up, and only call executeLoad/Store
+ // the appropriate number of times.
+
+ public:
+ /** Executes the load at the given index. */
+ template <class T>
+ Fault read(MemReqPtr &req, T &data, int load_idx);
+
+ /** Executes the store at the given index. */
+ template <class T>
+ Fault write(MemReqPtr &req, T &data, int store_idx);
+
+ /** Returns the index of the head load instruction. */
+ int getLoadHead() { return loadHead; }
+ /** Returns the sequence number of the head load instruction. */
+ InstSeqNum getLoadHeadSeqNum()
+ {
+ if (loadQueue[loadHead]) {
+ return loadQueue[loadHead]->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns the index of the head store instruction. */
+ int getStoreHead() { return storeHead; }
+ /** Returns the sequence number of the head store instruction. */
+ InstSeqNum getStoreHeadSeqNum()
+ {
+ if (storeQueue[storeHead].inst) {
+ return storeQueue[storeHead].inst->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns whether or not the LSQ unit is stalled. */
+ bool isStalled() { return stalled; }
+};
+
+template <class Impl>
+template <class T>
+Fault
+OzoneLSQ<Impl>::read(MemReqPtr &req, T &data, int load_idx)
+{
+ //Depending on issue2execute delay a squashed load could
+ //execute if it is found to be squashed in the same
+ //cycle it is scheduled to execute
+ assert(loadQueue[load_idx]);
+
+ if (loadQueue[load_idx]->isExecuted()) {
+ panic("Should not reach this point with split ops!");
+
+ memcpy(&data,req->data,req->size);
+
+ return NoFault;
+ }
+
+ // Make sure this isn't an uncacheable access
+ // A bit of a hackish way to get uncached accesses to work only if they're
+ // at the head of the LSQ and are ready to commit (at the head of the ROB
+ // too).
+ // @todo: Fix uncached accesses.
+ if (req->flags & UNCACHEABLE &&
+ (load_idx != loadHead || !loadQueue[load_idx]->readyToCommit())) {
+
+ return TheISA::genMachineCheckFault();
+ }
+
+ // Check the SQ for any previous stores that might lead to forwarding
+ int store_idx = loadQueue[load_idx]->sqIdx;
+
+ int store_size = 0;
+
+ DPRINTF(OzoneLSQ, "Read called, load idx: %i, store idx: %i, "
+ "storeHead: %i addr: %#x\n",
+ load_idx, store_idx, storeHead, req->paddr);
+
+ while (store_idx != -1) {
+ // End once we've reached the top of the LSQ
+ if (store_idx == storeWBIdx) {
+ break;
+ }
+
+ // Move the index to one younger
+ if (--store_idx < 0)
+ store_idx += SQEntries;
+
+ assert(storeQueue[store_idx].inst);
+
+ store_size = storeQueue[store_idx].size;
+
+ if (store_size == 0)
+ continue;
+
+ // Check if the store data is within the lower and upper bounds of
+ // addresses that the request needs.
+ bool store_has_lower_limit =
+ req->vaddr >= storeQueue[store_idx].inst->effAddr;
+ bool store_has_upper_limit =
+ (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr +
+ store_size);
+ bool lower_load_has_store_part =
+ req->vaddr < (storeQueue[store_idx].inst->effAddr +
+ store_size);
+ bool upper_load_has_store_part =
+ (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr;
+
+ // If the store's data has all of the data needed, we can forward.
+ if (store_has_lower_limit && store_has_upper_limit) {
+
+ int shift_amt = req->vaddr & (store_size - 1);
+ // Assumes byte addressing
+ shift_amt = shift_amt << 3;
+
+ // Cast this to type T?
+ data = storeQueue[store_idx].data >> shift_amt;
+
+ req->cmd = Read;
+ assert(!req->completionEvent);
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+
+ memcpy(req->data, &data, req->size);
+
+ DPRINTF(OzoneLSQ, "Forwarding from store idx %i to load to "
+ "addr %#x, data %#x\n",
+ store_idx, req->vaddr, *(req->data));
+
+ typename BackEnd::LdWritebackEvent *wb =
+ new typename BackEnd::LdWritebackEvent(loadQueue[load_idx],
+ be);
+
+ // We'll say this has a 1 cycle load-store forwarding latency
+ // for now.
+ // FIXME - Need to make this a parameter.
+ wb->schedule(curTick);
+
+ // Should keep track of stat for forwarded data
+ return NoFault;
+ } else if ((store_has_lower_limit && lower_load_has_store_part) ||
+ (store_has_upper_limit && upper_load_has_store_part) ||
+ (lower_load_has_store_part && upper_load_has_store_part)) {
+ // This is the partial store-load forwarding case where a store
+ // has only part of the load's data.
+
+ // If it's already been written back, then don't worry about
+ // stalling on it.
+ if (storeQueue[store_idx].completed) {
+ continue;
+ }
+
+ // Must stall load and force it to retry, so long as it's the oldest
+ // load that needs to do so.
+ if (!stalled ||
+ (stalled &&
+ loadQueue[load_idx]->seqNum <
+ loadQueue[stallingLoadIdx]->seqNum)) {
+ stalled = true;
+ stallingStoreIsn = storeQueue[store_idx].inst->seqNum;
+ stallingLoadIdx = load_idx;
+ }
+
+ // Tell IQ/mem dep unit that this instruction will need to be
+ // rescheduled eventually
+ be->rescheduleMemInst(loadQueue[load_idx]);
+
+ DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. "
+ "Store idx %i to load addr %#x\n",
+ store_idx, req->vaddr);
+
+ return NoFault;
+ }
+ }
+
+
+ // If there's no forwarding case, then go access memory
+ DynInstPtr inst = loadQueue[load_idx];
+
+ ++usedPorts;
+
+ // if we have a cache, do cache access too
+ if (dcacheInterface) {
+ if (dcacheInterface->isBlocked()) {
+ isLoadBlocked = true;
+ // No fault occurred, even though the interface is blocked.
+ return NoFault;
+ }
+
+ DPRINTF(OzoneLSQ, "D-cache: PC:%#x reading from paddr:%#x "
+ "vaddr:%#x flags:%i\n",
+ inst->readPC(), req->paddr, req->vaddr, req->flags);
+
+ // Setup MemReq pointer
+ req->cmd = Read;
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+
+ assert(!req->completionEvent);
+ typedef typename BackEnd::LdWritebackEvent LdWritebackEvent;
+
+ LdWritebackEvent *wb = new LdWritebackEvent(loadQueue[load_idx], be);
+
+ req->completionEvent = wb;
+
+ // Do Cache Access
+ MemAccessResult result = dcacheInterface->access(req);
+
+ // Ugly hack to get an event scheduled *only* if the access is
+ // a miss. We really should add first-class support for this
+ // at some point.
+ // @todo: Probably should support having no events
+ if (result != MA_HIT) {
+ DPRINTF(OzoneLSQ, "D-cache miss!\n");
+ DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
+ inst->seqNum);
+
+ lastDcacheStall = curTick;
+
+ _status = DcacheMissStall;
+
+ wb->setDcacheMiss();
+
+ } else {
+// DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
+// inst->seqNum);
+
+ DPRINTF(OzoneLSQ, "D-cache hit!\n");
+ }
+ } else {
+ fatal("Must use D-cache with new memory system");
+ }
+
+ return NoFault;
+}
+
+template <class Impl>
+template <class T>
+Fault
+OzoneLSQ<Impl>::write(MemReqPtr &req, T &data, int store_idx)
+{
+ assert(storeQueue[store_idx].inst);
+
+ DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x"
+ " | storeHead:%i [sn:%i]\n",
+ store_idx, req->paddr, data, storeHead,
+ storeQueue[store_idx].inst->seqNum);
+
+ storeQueue[store_idx].req = req;
+ storeQueue[store_idx].size = sizeof(T);
+ storeQueue[store_idx].data = data;
+
+ // This function only writes the data to the store queue, so no fault
+ // can happen here.
+ return NoFault;
+}
+
+template <class Impl>
+inline bool
+OzoneLSQ<Impl>::loadBlocked()
+{
+ bool ret_val = isLoadBlocked;
+ isLoadBlocked = false;
+ return ret_val;
+}
+
+#endif // __CPU_OZONE_LSQ_UNIT_HH__
diff --git a/src/cpu/ozone/lsq_unit_impl.hh b/src/cpu/ozone/lsq_unit_impl.hh
new file mode 100644
index 000000000..f8cb18634
--- /dev/null
+++ b/src/cpu/ozone/lsq_unit_impl.hh
@@ -0,0 +1,840 @@
+/*
+ * 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 "arch/isa_traits.hh"
+#include "base/str.hh"
+#include "cpu/ozone/lsq_unit.hh"
+
+template <class Impl>
+OzoneLSQ<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
+ Event *wb_event,
+ OzoneLSQ<Impl> *lsq_ptr)
+ : Event(&mainEventQueue),
+ storeIdx(store_idx),
+ wbEvent(wb_event),
+ lsqPtr(lsq_ptr)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::StoreCompletionEvent::process()
+{
+ DPRINTF(OzoneLSQ, "Cache miss complete for store idx:%i\n", storeIdx);
+
+ //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
+
+// lsqPtr->cpu->wakeCPU();
+ if (wbEvent)
+ wbEvent->process();
+ lsqPtr->completeStore(storeIdx);
+}
+
+template <class Impl>
+const char *
+OzoneLSQ<Impl>::StoreCompletionEvent::description()
+{
+ return "LSQ store completion event";
+}
+
+template <class Impl>
+OzoneLSQ<Impl>::OzoneLSQ()
+ : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false)
+{
+}
+
+template<class Impl>
+void
+OzoneLSQ<Impl>::init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id)
+
+{
+ DPRINTF(OzoneLSQ, "Creating OzoneLSQ%i object.\n",id);
+
+ lsqID = id;
+
+ LQEntries = maxLQEntries;
+ SQEntries = maxSQEntries;
+
+ loadQueue.resize(LQEntries);
+ storeQueue.resize(SQEntries);
+
+
+ // May want to initialize these entries to NULL
+
+ loadHead = loadTail = 0;
+
+ storeHead = storeWBIdx = storeTail = 0;
+
+ usedPorts = 0;
+ cachePorts = params->cachePorts;
+
+ dcacheInterface = params->dcacheInterface;
+
+ loadFaultInst = storeFaultInst = memDepViolator = NULL;
+}
+
+template<class Impl>
+std::string
+OzoneLSQ<Impl>::name() const
+{
+ return "lsqunit";
+}
+
+template<class Impl>
+void
+OzoneLSQ<Impl>::clearLQ()
+{
+ loadQueue.clear();
+}
+
+template<class Impl>
+void
+OzoneLSQ<Impl>::clearSQ()
+{
+ storeQueue.clear();
+}
+
+template<class Impl>
+void
+OzoneLSQ<Impl>::resizeLQ(unsigned size)
+{
+ assert( size >= LQEntries);
+
+ if (size > LQEntries) {
+ while (size > loadQueue.size()) {
+ DynInstPtr dummy;
+ loadQueue.push_back(dummy);
+ LQEntries++;
+ }
+ } else {
+ LQEntries = size;
+ }
+
+}
+
+template<class Impl>
+void
+OzoneLSQ<Impl>::resizeSQ(unsigned size)
+{
+ if (size > SQEntries) {
+ while (size > storeQueue.size()) {
+ SQEntry dummy;
+ storeQueue.push_back(dummy);
+ SQEntries++;
+ }
+ } else {
+ SQEntries = size;
+ }
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::insert(DynInstPtr &inst)
+{
+ // Make sure we really have a memory reference.
+ assert(inst->isMemRef());
+
+ // Make sure it's one of the two classes of memory references.
+ assert(inst->isLoad() || inst->isStore());
+
+ if (inst->isLoad()) {
+ insertLoad(inst);
+ } else {
+ insertStore(inst);
+ }
+
+// inst->setInLSQ();
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::insertLoad(DynInstPtr &load_inst)
+{
+ assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries);
+
+ DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
+ load_inst->readPC(), loadTail, load_inst->seqNum);
+
+ load_inst->lqIdx = loadTail;
+
+ if (stores == 0) {
+ load_inst->sqIdx = -1;
+ } else {
+ load_inst->sqIdx = storeTail;
+ }
+
+ loadQueue[loadTail] = load_inst;
+
+ incrLdIdx(loadTail);
+
+ ++loads;
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::insertStore(DynInstPtr &store_inst)
+{
+ // Make sure it is not full before inserting an instruction.
+ assert((storeTail + 1) % SQEntries != storeHead);
+ assert(stores < SQEntries);
+
+ DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
+ store_inst->readPC(), storeTail, store_inst->seqNum);
+
+ store_inst->sqIdx = storeTail;
+ store_inst->lqIdx = loadTail;
+
+ storeQueue[storeTail] = SQEntry(store_inst);
+
+ incrStIdx(storeTail);
+
+ ++stores;
+
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+OzoneLSQ<Impl>::getMemDepViolator()
+{
+ DynInstPtr temp = memDepViolator;
+
+ memDepViolator = NULL;
+
+ return temp;
+}
+
+template <class Impl>
+unsigned
+OzoneLSQ<Impl>::numFreeEntries()
+{
+ unsigned free_lq_entries = LQEntries - loads;
+ unsigned free_sq_entries = SQEntries - stores;
+
+ // Both the LQ and SQ entries have an extra dummy entry to differentiate
+ // empty/full conditions. Subtract 1 from the free entries.
+ if (free_lq_entries < free_sq_entries) {
+ return free_lq_entries - 1;
+ } else {
+ return free_sq_entries - 1;
+ }
+}
+
+template <class Impl>
+int
+OzoneLSQ<Impl>::numLoadsReady()
+{
+ int load_idx = loadHead;
+ int retval = 0;
+
+ while (load_idx != loadTail) {
+ assert(loadQueue[load_idx]);
+
+ if (loadQueue[load_idx]->readyToIssue()) {
+ ++retval;
+ }
+ }
+
+ return retval;
+}
+
+#if 0
+template <class Impl>
+Fault
+OzoneLSQ<Impl>::executeLoad()
+{
+ Fault load_fault = NoFault;
+ DynInstPtr load_inst;
+
+ assert(readyLoads.size() != 0);
+
+ // Execute a ready load.
+ LdMapIt ready_it = readyLoads.begin();
+
+ load_inst = (*ready_it).second;
+
+ // Execute the instruction, which is held in the data portion of the
+ // iterator.
+ load_fault = load_inst->execute();
+
+ // If it executed successfully, then switch it over to the executed
+ // loads list.
+ if (load_fault == NoFault) {
+ executedLoads[load_inst->seqNum] = load_inst;
+
+ readyLoads.erase(ready_it);
+ } else {
+ loadFaultInst = load_inst;
+ }
+
+ return load_fault;
+}
+#endif
+
+template <class Impl>
+Fault
+OzoneLSQ<Impl>::executeLoad(DynInstPtr &inst)
+{
+ // Execute a specific load.
+ Fault load_fault = NoFault;
+
+ DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n",
+ inst->readPC(),inst->seqNum);
+
+ // Make sure it's really in the list.
+ // Normally it should always be in the list. However,
+ /* due to a syscall it may not be the list.
+#ifdef DEBUG
+ int i = loadHead;
+ while (1) {
+ if (i == loadTail && !find(inst)) {
+ assert(0 && "Load not in the queue!");
+ } else if (loadQueue[i] == inst) {
+ break;
+ }
+
+ i = i + 1;
+ if (i >= LQEntries) {
+ i = 0;
+ }
+ }
+#endif // DEBUG*/
+
+ load_fault = inst->initiateAcc();
+
+ // Might want to make sure that I'm not overwriting a previously faulting
+ // instruction that hasn't been checked yet.
+ // Actually probably want the oldest faulting load
+ if (load_fault != NoFault) {
+ // Maybe just set it as can commit here, although that might cause
+ // some other problems with sending traps to the ROB too quickly.
+// iewStage->instToCommit(inst);
+// iewStage->activityThisCycle();
+ }
+
+ return load_fault;
+}
+
+template <class Impl>
+Fault
+OzoneLSQ<Impl>::executeLoad(int lq_idx)
+{
+ // Very hackish. Not sure the best way to check that this
+ // instruction is at the head of the ROB. I should have some sort
+ // of extra information here so that I'm not overloading the
+ // canCommit signal for 15 different things.
+ loadQueue[lq_idx]->setCanCommit();
+ Fault ret_fault = executeLoad(loadQueue[lq_idx]);
+ loadQueue[lq_idx]->clearCanCommit();
+ return ret_fault;
+}
+
+template <class Impl>
+Fault
+OzoneLSQ<Impl>::executeStore(DynInstPtr &store_inst)
+{
+ // Make sure that a store exists.
+ assert(stores != 0);
+
+ int store_idx = store_inst->sqIdx;
+
+ DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n",
+ store_inst->readPC(), store_inst->seqNum);
+
+ // Check the recently completed loads to see if any match this store's
+ // address. If so, then we have a memory ordering violation.
+ int load_idx = store_inst->lqIdx;
+
+ Fault store_fault = store_inst->initiateAcc();
+
+ // Store size should now be available. Use it to get proper offset for
+ // addr comparisons.
+ int size = storeQueue[store_idx].size;
+
+ if (size == 0) {
+ DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
+ store_inst->readPC(),store_inst->seqNum);
+
+ return store_fault;
+ }
+
+ assert(store_fault == NoFault);
+
+ if (!storeFaultInst) {
+ if (store_fault != NoFault) {
+ panic("Fault in a store instruction!");
+ storeFaultInst = store_inst;
+ } else if (store_inst->isNonSpeculative()) {
+ // Nonspeculative accesses (namely store conditionals)
+ // need to set themselves as able to writeback if we
+ // haven't had a fault by here.
+ storeQueue[store_idx].canWB = true;
+
+ ++storesToWB;
+ }
+ }
+
+ if (!memDepViolator) {
+ while (load_idx != loadTail) {
+ // Actually should only check loads that have actually executed
+ // Might be safe because effAddr is set to InvalAddr when the
+ // dyn inst is created.
+
+ // Must actually check all addrs in the proper size range
+ // Which is more correct than needs to be. What if for now we just
+ // assume all loads are quad-word loads, and do the addr based
+ // on that.
+ // @todo: Fix this, magic number being used here
+ if ((loadQueue[load_idx]->effAddr >> 8) ==
+ (store_inst->effAddr >> 8)) {
+ // A load incorrectly passed this store. Squash and refetch.
+ // For now return a fault to show that it was unsuccessful.
+ memDepViolator = loadQueue[load_idx];
+
+ return TheISA::genMachineCheckFault();
+ }
+
+ incrLdIdx(load_idx);
+ }
+
+ // If we've reached this point, there was no violation.
+ memDepViolator = NULL;
+ }
+
+ return store_fault;
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::commitLoad()
+{
+ assert(loadQueue[loadHead]);
+
+ DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n",
+ loadQueue[loadHead]->seqNum, loadQueue[loadHead]->readPC());
+
+
+ loadQueue[loadHead] = NULL;
+
+ incrLdIdx(loadHead);
+
+ --loads;
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::commitLoad(InstSeqNum &inst)
+{
+ // Hopefully I don't use this function too much
+ panic("Don't use this function!");
+
+ int i = loadHead;
+ while (1) {
+ if (i == loadTail) {
+ assert(0 && "Load not in the queue!");
+ } else if (loadQueue[i]->seqNum == inst) {
+ break;
+ }
+
+ ++i;
+ if (i >= LQEntries) {
+ i = 0;
+ }
+ }
+
+// loadQueue[i]->removeInLSQ();
+ loadQueue[i] = NULL;
+ --loads;
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst)
+{
+ assert(loads == 0 || loadQueue[loadHead]);
+
+ while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
+ commitLoad();
+ }
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::commitStores(InstSeqNum &youngest_inst)
+{
+ assert(stores == 0 || storeQueue[storeHead].inst);
+
+ int store_idx = storeHead;
+
+ while (store_idx != storeTail) {
+ assert(storeQueue[store_idx].inst);
+ if (!storeQueue[store_idx].canWB) {
+ if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
+ break;
+ }
+ DPRINTF(OzoneLSQ, "Marking store as able to write back, PC "
+ "%#x [sn:%lli]\n",
+ storeQueue[store_idx].inst->readPC(),
+ storeQueue[store_idx].inst->seqNum);
+
+ storeQueue[store_idx].canWB = true;
+
+// --stores;
+ ++storesToWB;
+ }
+
+ incrStIdx(store_idx);
+ }
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::writebackStores()
+{
+ while (storesToWB > 0 &&
+ storeWBIdx != storeTail &&
+ storeQueue[storeWBIdx].inst &&
+ storeQueue[storeWBIdx].canWB &&
+ usedPorts < cachePorts) {
+
+ if (storeQueue[storeWBIdx].size == 0) {
+ completeStore(storeWBIdx);
+
+ incrStIdx(storeWBIdx);
+
+ continue;
+ }
+
+ if (dcacheInterface && dcacheInterface->isBlocked()) {
+ DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
+ " is blocked!\n");
+ break;
+ }
+
+ ++usedPorts;
+
+ if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
+ incrStIdx(storeWBIdx);
+
+ continue;
+ }
+
+ assert(storeQueue[storeWBIdx].req);
+ assert(!storeQueue[storeWBIdx].committed);
+
+ MemReqPtr req = storeQueue[storeWBIdx].req;
+ storeQueue[storeWBIdx].committed = true;
+
+// Fault fault = cpu->translateDataReadReq(req);
+ req->cmd = Write;
+ req->completionEvent = NULL;
+ req->time = curTick;
+ assert(!req->data);
+ req->data = new uint8_t[64];
+ memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
+
+ DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x "
+ "to Addr:%#x, data:%#x [sn:%lli]\n",
+ storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
+ req->paddr, *(req->data),
+ storeQueue[storeWBIdx].inst->seqNum);
+
+// if (fault != NoFault) {
+ //What should we do if there is a fault???
+ //for now panic
+// panic("Page Table Fault!!!!!\n");
+// }
+
+ if (dcacheInterface) {
+ MemAccessResult result = dcacheInterface->access(req);
+
+ //@todo temp fix for LL/SC (works fine for 1 CPU)
+ if (req->flags & LOCKED) {
+ req->result=1;
+ panic("LL/SC! oh no no support!!!");
+ }
+
+ if (isStalled() &&
+ storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load idx:%i\n",
+ stallingStoreIsn, stallingLoadIdx);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst(loadQueue[stallingLoadIdx]);
+ }
+
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
+ Event *wb = NULL;
+/*
+ typename IEW::LdWritebackEvent *wb = NULL;
+ if (req->flags & LOCKED) {
+ // Stx_C does not generate a system port transaction.
+ req->result=0;
+ wb = new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
+ iewStage);
+ }
+*/
+ DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n");
+
+// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
+// storeQueue[storeWBIdx].inst->seqNum);
+
+ // Will stores need their own kind of writeback events?
+ // Do stores even need writeback events?
+ assert(!req->completionEvent);
+ req->completionEvent = new
+ StoreCompletionEvent(storeWBIdx, wb, this);
+
+ lastDcacheStall = curTick;
+
+ _status = DcacheMissStall;
+
+ //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
+
+ //DPRINTF(OzoneLSQ, "Added MSHR. count = %i\n",mshrSeqNums.size());
+
+ // Increment stat here or something
+ } else {
+ DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n",
+ storeWBIdx);
+
+// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
+// storeQueue[storeWBIdx].inst->seqNum);
+
+ if (req->flags & LOCKED) {
+ // Stx_C does not generate a system port transaction.
+ req->result=1;
+ typename BackEnd::LdWritebackEvent *wb =
+ new typename BackEnd::LdWritebackEvent(storeQueue[storeWBIdx].inst,
+ be);
+ wb->schedule(curTick);
+ }
+
+ completeStore(storeWBIdx);
+ }
+
+ incrStIdx(storeWBIdx);
+ } else {
+ panic("Must HAVE DCACHE!!!!!\n");
+ }
+ }
+
+ // Not sure this should set it to 0.
+ usedPorts = 0;
+
+ assert(stores >= 0 && storesToWB >= 0);
+}
+
+/*template <class Impl>
+void
+OzoneLSQ<Impl>::removeMSHR(InstSeqNum seqNum)
+{
+ list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
+ mshrSeqNums.end(),
+ seqNum);
+
+ if (mshr_it != mshrSeqNums.end()) {
+ mshrSeqNums.erase(mshr_it);
+ DPRINTF(OzoneLSQ, "Removing MSHR. count = %i\n",mshrSeqNums.size());
+ }
+}*/
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::squash(const InstSeqNum &squashed_num)
+{
+ DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!"
+ "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
+
+ int load_idx = loadTail;
+ decrLdIdx(load_idx);
+
+ while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
+
+ // Clear the smart pointer to make sure it is decremented.
+ DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, "
+ "[sn:%lli]\n",
+ loadQueue[load_idx]->readPC(),
+ loadQueue[load_idx]->seqNum);
+
+ if (isStalled() && load_idx == stallingLoadIdx) {
+ stalled = false;
+ stallingStoreIsn = 0;
+ stallingLoadIdx = 0;
+ }
+
+// loadQueue[load_idx]->squashed = true;
+ loadQueue[load_idx] = NULL;
+ --loads;
+
+ // Inefficient!
+ loadTail = load_idx;
+
+ decrLdIdx(load_idx);
+ }
+
+ int store_idx = storeTail;
+ decrStIdx(store_idx);
+
+ while (stores != 0 && storeQueue[store_idx].inst->seqNum > squashed_num) {
+
+ // Clear the smart pointer to make sure it is decremented.
+ DPRINTF(OzoneLSQ,"Store Instruction PC %#x squashed, "
+ "idx:%i [sn:%lli]\n",
+ storeQueue[store_idx].inst->readPC(),
+ store_idx, storeQueue[store_idx].inst->seqNum);
+
+ // I don't think this can happen. It should have been cleared by the
+ // stalling load.
+ if (isStalled() &&
+ storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
+ panic("Is stalled should have been cleared by stalling load!\n");
+ stalled = false;
+ stallingStoreIsn = 0;
+ }
+
+// storeQueue[store_idx].inst->squashed = true;
+ storeQueue[store_idx].inst = NULL;
+ storeQueue[store_idx].canWB = 0;
+
+ if (storeQueue[store_idx].req) {
+ assert(!storeQueue[store_idx].req->completionEvent);
+ }
+ storeQueue[store_idx].req = NULL;
+ --stores;
+
+ // Inefficient!
+ storeTail = store_idx;
+
+ decrStIdx(store_idx);
+ }
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::dumpInsts()
+{
+ cprintf("Load store queue: Dumping instructions.\n");
+ cprintf("Load queue size: %i\n", loads);
+ cprintf("Load queue: ");
+
+ int load_idx = loadHead;
+
+ while (load_idx != loadTail && loadQueue[load_idx]) {
+ cprintf("[sn:%lli] %#x ", loadQueue[load_idx]->seqNum,
+ loadQueue[load_idx]->readPC());
+
+ incrLdIdx(load_idx);
+ }
+
+ cprintf("\nStore queue size: %i\n", stores);
+ cprintf("Store queue: ");
+
+ int store_idx = storeHead;
+
+ while (store_idx != storeTail && storeQueue[store_idx].inst) {
+ cprintf("[sn:%lli] %#x ", storeQueue[store_idx].inst->seqNum,
+ storeQueue[store_idx].inst->readPC());
+
+ incrStIdx(store_idx);
+ }
+
+ cprintf("\n");
+}
+
+template <class Impl>
+void
+OzoneLSQ<Impl>::completeStore(int store_idx)
+{
+ assert(storeQueue[store_idx].inst);
+ storeQueue[store_idx].completed = true;
+ --storesToWB;
+ // A bit conservative because a store completion may not free up entries,
+ // but hopefully avoids two store completions in one cycle from making
+ // the CPU tick twice.
+// cpu->activityThisCycle();
+
+ if (store_idx == storeHead) {
+ do {
+ incrStIdx(storeHead);
+
+ --stores;
+ } while (storeQueue[storeHead].completed &&
+ storeHead != storeTail);
+
+// be->updateLSQNextCycle = true;
+ }
+
+ DPRINTF(OzoneLSQ, "Store head idx:%i\n", storeHead);
+
+ if (isStalled() &&
+ storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load idx:%i\n",
+ stallingStoreIsn, stallingLoadIdx);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst(loadQueue[stallingLoadIdx]);
+ }
+}
+
+template <class Impl>
+inline void
+OzoneLSQ<Impl>::incrStIdx(int &store_idx)
+{
+ if (++store_idx >= SQEntries)
+ store_idx = 0;
+}
+
+template <class Impl>
+inline void
+OzoneLSQ<Impl>::decrStIdx(int &store_idx)
+{
+ if (--store_idx < 0)
+ store_idx += SQEntries;
+}
+
+template <class Impl>
+inline void
+OzoneLSQ<Impl>::incrLdIdx(int &load_idx)
+{
+ if (++load_idx >= LQEntries)
+ load_idx = 0;
+}
+
+template <class Impl>
+inline void
+OzoneLSQ<Impl>::decrLdIdx(int &load_idx)
+{
+ if (--load_idx < 0)
+ load_idx += LQEntries;
+}
diff --git a/src/cpu/ozone/lw_back_end.cc b/src/cpu/ozone/lw_back_end.cc
new file mode 100644
index 000000000..71e51f038
--- /dev/null
+++ b/src/cpu/ozone/lw_back_end.cc
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/lw_back_end_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+
+template class LWBackEnd<OzoneImpl>;
diff --git a/src/cpu/ozone/lw_back_end.hh b/src/cpu/ozone/lw_back_end.hh
new file mode 100644
index 000000000..bb3ef3a72
--- /dev/null
+++ b/src/cpu/ozone/lw_back_end.hh
@@ -0,0 +1,431 @@
+/*
+ * 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_OZONE_LW_BACK_END_HH__
+#define __CPU_OZONE_LW_BACK_END_HH__
+
+#include <list>
+#include <queue>
+#include <set>
+#include <string>
+
+#include "arch/faults.hh"
+#include "base/timebuf.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/rename_table.hh"
+#include "cpu/ozone/thread_state.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+template <class>
+class Checker;
+class ThreadContext;
+
+template <class Impl>
+class OzoneThreadState;
+
+template <class Impl>
+class LWBackEnd
+{
+ public:
+ typedef OzoneThreadState<Impl> Thread;
+
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInst DynInst;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::OzoneCPU OzoneCPU;
+ typedef typename Impl::FrontEnd FrontEnd;
+ typedef typename Impl::OzoneCPU::CommStruct CommStruct;
+
+ struct SizeStruct {
+ int size;
+ };
+
+ typedef SizeStruct DispatchToIssue;
+ typedef SizeStruct IssueToExec;
+ typedef SizeStruct ExecToCommit;
+ typedef SizeStruct Writeback;
+
+ TimeBuffer<DispatchToIssue> d2i;
+ typename TimeBuffer<DispatchToIssue>::wire instsToDispatch;
+ TimeBuffer<IssueToExec> i2e;
+ typename TimeBuffer<IssueToExec>::wire instsToExecute;
+ TimeBuffer<ExecToCommit> e2c;
+ TimeBuffer<Writeback> numInstsToWB;
+
+ TimeBuffer<CommStruct> *comm;
+ typename TimeBuffer<CommStruct>::wire toIEW;
+ typename TimeBuffer<CommStruct>::wire fromCommit;
+
+ class TrapEvent : public Event {
+ private:
+ LWBackEnd<Impl> *be;
+
+ public:
+ TrapEvent(LWBackEnd<Impl> *_be);
+
+ void process();
+ const char *description();
+ };
+
+ LWBackEnd(Params *params);
+
+ std::string name() const;
+
+ void regStats();
+
+ void setCPU(OzoneCPU *cpu_ptr);
+
+ void setFrontEnd(FrontEnd *front_end_ptr)
+ { frontEnd = front_end_ptr; }
+
+ void setTC(ThreadContext *tc_ptr)
+ { tc = tc_ptr; }
+
+ void setThreadState(Thread *thread_ptr)
+ { thread = thread_ptr; }
+
+ void setCommBuffer(TimeBuffer<CommStruct> *_comm);
+
+ void tick();
+ void squash();
+ void generateTCEvent() { tcSquash = true; }
+ void squashFromTC();
+ void squashFromTrap();
+ void checkInterrupts();
+ bool trapSquash;
+ bool tcSquash;
+
+ template <class T>
+ Fault read(RequestPtr req, T &data, int load_idx);
+
+ template <class T>
+ Fault write(RequestPtr req, T &data, int store_idx);
+
+ Addr readCommitPC() { return commitPC; }
+
+ Addr commitPC;
+
+ Tick lastCommitCycle;
+
+ bool robEmpty() { return instList.empty(); }
+
+ bool isFull() { return numInsts >= numROBEntries; }
+ bool isBlocked() { return status == Blocked || dispatchStatus == Blocked; }
+
+ void fetchFault(Fault &fault);
+
+ int wakeDependents(DynInstPtr &inst, bool memory_deps = false);
+
+ /** Tells memory dependence unit that a memory instruction needs to be
+ * rescheduled. It will re-execute once replayMemInst() is called.
+ */
+ void rescheduleMemInst(DynInstPtr &inst);
+
+ /** Re-executes all rescheduled memory instructions. */
+ void replayMemInst(DynInstPtr &inst);
+
+ /** Completes memory instruction. */
+ void completeMemInst(DynInstPtr &inst) { }
+
+ void addDcacheMiss(DynInstPtr &inst)
+ {
+ waitingMemOps.insert(inst->seqNum);
+ numWaitingMemOps++;
+ DPRINTF(BE, "Adding a Dcache miss mem op [sn:%lli], total %i\n",
+ inst->seqNum, numWaitingMemOps);
+ }
+
+ void removeDcacheMiss(DynInstPtr &inst)
+ {
+ assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end());
+ waitingMemOps.erase(inst->seqNum);
+ numWaitingMemOps--;
+ DPRINTF(BE, "Removing a Dcache miss mem op [sn:%lli], total %i\n",
+ inst->seqNum, numWaitingMemOps);
+ }
+
+ void addWaitingMemOp(DynInstPtr &inst)
+ {
+ waitingMemOps.insert(inst->seqNum);
+ numWaitingMemOps++;
+ DPRINTF(BE, "Adding a waiting mem op [sn:%lli], total %i\n",
+ inst->seqNum, numWaitingMemOps);
+ }
+
+ void removeWaitingMemOp(DynInstPtr &inst)
+ {
+ assert(waitingMemOps.find(inst->seqNum) != waitingMemOps.end());
+ waitingMemOps.erase(inst->seqNum);
+ numWaitingMemOps--;
+ DPRINTF(BE, "Removing a waiting mem op [sn:%lli], total %i\n",
+ inst->seqNum, numWaitingMemOps);
+ }
+
+ void instToCommit(DynInstPtr &inst);
+
+ void switchOut();
+ void doSwitchOut();
+ void takeOverFrom(ThreadContext *old_tc = NULL);
+
+ bool isSwitchedOut() { return switchedOut; }
+
+ private:
+ void generateTrapEvent(Tick latency = 0);
+ void handleFault(Fault &fault, Tick latency = 0);
+ void updateStructures();
+ void dispatchInsts();
+ void dispatchStall();
+ void checkDispatchStatus();
+ void executeInsts();
+ void commitInsts();
+ void addToLSQ(DynInstPtr &inst);
+ void writebackInsts();
+ bool commitInst(int inst_num);
+ void squash(const InstSeqNum &sn);
+ void squashDueToBranch(DynInstPtr &inst);
+ void squashDueToMemViolation(DynInstPtr &inst);
+ void squashDueToMemBlocked(DynInstPtr &inst);
+ void updateExeInstStats(DynInstPtr &inst);
+ void updateComInstStats(DynInstPtr &inst);
+
+ public:
+ OzoneCPU *cpu;
+
+ FrontEnd *frontEnd;
+
+ ThreadContext *tc;
+
+ Thread *thread;
+
+ enum Status {
+ Running,
+ Idle,
+ DcacheMissStall,
+ DcacheMissComplete,
+ Blocked,
+ TrapPending
+ };
+
+ Status status;
+
+ Status dispatchStatus;
+
+ Status commitStatus;
+
+ Counter funcExeInst;
+
+ private:
+ typedef typename Impl::LdstQueue LdstQueue;
+
+ LdstQueue LSQ;
+ public:
+ RenameTable<Impl> commitRenameTable;
+
+ RenameTable<Impl> renameTable;
+ private:
+ // General back end width. Used if the more specific isn't given.
+ int width;
+
+ // Dispatch width.
+ int dispatchWidth;
+ int numDispatchEntries;
+ int dispatchSize;
+
+ int waitingInsts;
+
+ int issueWidth;
+
+ // Writeback width
+ int wbWidth;
+
+ // Commit width
+ int commitWidth;
+
+ /** Index into queue of instructions being written back. */
+ unsigned wbNumInst;
+
+ /** Cycle number within the queue of instructions being written
+ * back. Used in case there are too many instructions writing
+ * back at the current cycle and writesbacks need to be scheduled
+ * for the future. See comments in instToCommit().
+ */
+ unsigned wbCycle;
+
+ int numROBEntries;
+ int numInsts;
+
+ std::set<InstSeqNum> waitingMemOps;
+ typedef std::set<InstSeqNum>::iterator MemIt;
+ int numWaitingMemOps;
+ unsigned maxOutstandingMemOps;
+
+ bool squashPending;
+ InstSeqNum squashSeqNum;
+ Addr squashNextPC;
+
+ Fault faultFromFetch;
+ bool fetchHasFault;
+
+ bool switchedOut;
+ bool switchPending;
+
+ DynInstPtr memBarrier;
+
+ private:
+ struct pqCompare {
+ bool operator() (const DynInstPtr &lhs, const DynInstPtr &rhs) const
+ {
+ return lhs->seqNum > rhs->seqNum;
+ }
+ };
+
+ typedef typename std::priority_queue<DynInstPtr, std::vector<DynInstPtr>, pqCompare> ReadyInstQueue;
+ ReadyInstQueue exeList;
+
+ typedef typename std::list<DynInstPtr>::iterator InstListIt;
+
+ std::list<DynInstPtr> instList;
+ std::list<DynInstPtr> waitingList;
+ std::list<DynInstPtr> replayList;
+ std::list<DynInstPtr> writeback;
+
+ int latency;
+
+ int squashLatency;
+
+ bool exactFullStall;
+
+ // number of cycles stalled for D-cache misses
+/* 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;
+ // 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<> issued_ops;
+
+ // total number of loads forwaded from LSQ stores
+ Stats::Vector<> lsq_forw_loads;
+
+ // total number of loads ignored due to invalid addresses
+ Stats::Vector<> inv_addr_loads;
+
+ // total number of software prefetches ignored due to invalid addresses
+ Stats::Vector<> inv_addr_swpfs;
+ // ready loads blocked due to memory disambiguation
+ Stats::Vector<> lsq_blocked_loads;
+
+ Stats::Scalar<> lsqInversion;
+
+ Stats::Vector<> n_issued_dist;
+ Stats::VectorDistribution<> issue_delay_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::Formula misspec_cnt;
+ Stats::Formula misspec_ipc;
+ Stats::Formula issue_rate;
+ Stats::Formula issue_stores;
+ Stats::Formula issue_op_rate;
+ Stats::Formula fu_busy_rate;
+ Stats::Formula commit_stores;
+ Stats::Formula commit_ipc;
+ 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::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::Distribution<> n_committed_dist;
+
+ Stats::Scalar<> commit_eligible_samples;
+ Stats::Vector<> commit_eligible;
+
+ Stats::Vector<> squashedInsts;
+ Stats::Vector<> ROBSquashedInsts;
+
+ Stats::Scalar<> ROB_fcount;
+ Stats::Formula ROB_full_rate;
+
+ Stats::Vector<> ROB_count; // cumulative ROB occupancy
+ Stats::Formula ROB_occ_rate;
+ Stats::VectorDistribution<> ROB_occ_dist;
+ public:
+ void dumpInsts();
+
+ Checker<DynInstPtr> *checker;
+};
+
+template <class Impl>
+template <class T>
+Fault
+LWBackEnd<Impl>::read(RequestPtr req, T &data, int load_idx)
+{
+ return LSQ.read(req, data, load_idx);
+}
+
+template <class Impl>
+template <class T>
+Fault
+LWBackEnd<Impl>::write(RequestPtr req, T &data, int store_idx)
+{
+ return LSQ.write(req, data, store_idx);
+}
+
+#endif // __CPU_OZONE_LW_BACK_END_HH__
diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh
new file mode 100644
index 000000000..a73d3ee6e
--- /dev/null
+++ b/src/cpu/ozone/lw_back_end_impl.hh
@@ -0,0 +1,1626 @@
+/*
+ * 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
+ */
+
+#include "config/use_checker.hh"
+
+#include "cpu/ozone/lw_back_end.hh"
+#include "cpu/op_class.hh"
+
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
+template <class Impl>
+void
+LWBackEnd<Impl>::generateTrapEvent(Tick latency)
+{
+ DPRINTF(BE, "Generating trap event\n");
+
+ TrapEvent *trap = new TrapEvent(this);
+
+ trap->schedule(curTick + cpu->cycles(latency));
+
+ thread->trapPending = true;
+}
+
+template <class Impl>
+int
+LWBackEnd<Impl>::wakeDependents(DynInstPtr &inst, bool memory_deps)
+{
+ assert(!inst->isSquashed());
+ std::vector<DynInstPtr> &dependents = memory_deps ? inst->getMemDeps() :
+ inst->getDependents();
+ int num_outputs = dependents.size();
+
+ DPRINTF(BE, "Waking instruction [sn:%lli] dependents in IQ\n", inst->seqNum);
+
+ for (int i = 0; i < num_outputs; i++) {
+ DynInstPtr dep_inst = dependents[i];
+ if (!memory_deps) {
+ dep_inst->markSrcRegReady();
+ } else {
+ if (!dep_inst->isSquashed())
+ dep_inst->markMemInstReady(inst.get());
+ }
+
+ DPRINTF(BE, "Marking source reg ready [sn:%lli] in IQ\n", dep_inst->seqNum);
+
+ if (dep_inst->readyToIssue() && dep_inst->isInROB() &&
+ !dep_inst->isNonSpeculative() && !dep_inst->isStoreConditional() &&
+ dep_inst->memDepReady() && !dep_inst->isMemBarrier() &&
+ !dep_inst->isWriteBarrier()) {
+ DPRINTF(BE, "Adding instruction to exeList [sn:%lli]\n",
+ dep_inst->seqNum);
+ exeList.push(dep_inst);
+ if (dep_inst->iqItValid) {
+ DPRINTF(BE, "Removing instruction from waiting list\n");
+ waitingList.erase(dep_inst->iqIt);
+ waitingInsts--;
+ dep_inst->iqItValid = false;
+ assert(waitingInsts >= 0);
+ }
+ if (dep_inst->isMemRef()) {
+ removeWaitingMemOp(dep_inst);
+ DPRINTF(BE, "Issued a waiting mem op [sn:%lli]\n",
+ dep_inst->seqNum);
+ }
+ }
+ }
+ return num_outputs;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::rescheduleMemInst(DynInstPtr &inst)
+{
+ replayList.push_front(inst);
+}
+
+template <class Impl>
+LWBackEnd<Impl>::TrapEvent::TrapEvent(LWBackEnd<Impl> *_be)
+ : Event(&mainEventQueue, CPU_Tick_Pri), be(_be)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::TrapEvent::process()
+{
+ be->trapSquash = true;
+}
+
+template <class Impl>
+const char *
+LWBackEnd<Impl>::TrapEvent::description()
+{
+ return "Trap event";
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst)
+{
+ bool found_inst = false;
+ while (!replayList.empty()) {
+ exeList.push(replayList.front());
+ if (replayList.front() == inst) {
+ found_inst = true;
+ }
+ replayList.pop_front();
+ }
+ assert(found_inst);
+}
+
+template <class Impl>
+LWBackEnd<Impl>::LWBackEnd(Params *params)
+ : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5),
+ trapSquash(false), tcSquash(false), LSQ(params),
+ width(params->backEndWidth), exactFullStall(true)
+{
+ numROBEntries = params->numROBEntries;
+ numInsts = 0;
+ numDispatchEntries = 32;
+ maxOutstandingMemOps = params->maxOutstandingMemOps;
+ numWaitingMemOps = 0;
+ waitingInsts = 0;
+ switchedOut = false;
+ switchPending = false;
+
+ LSQ.setBE(this);
+
+ // Setup IQ and LSQ with their parameters here.
+ instsToDispatch = d2i.getWire(-1);
+
+ instsToExecute = i2e.getWire(-1);
+
+ dispatchWidth = params->dispatchWidth ? params->dispatchWidth : width;
+ issueWidth = params->issueWidth ? params->issueWidth : width;
+ wbWidth = params->wbWidth ? params->wbWidth : width;
+ commitWidth = params->commitWidth ? params->commitWidth : width;
+
+ LSQ.init(params, params->LQEntries, params->SQEntries, 0);
+
+ dispatchStatus = Running;
+ commitStatus = Running;
+}
+
+template <class Impl>
+std::string
+LWBackEnd<Impl>::name() const
+{
+ return cpu->name() + ".backend";
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::regStats()
+{
+ using namespace Stats;
+ rob_cap_events
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:cap_events")
+ .desc("number of cycles where ROB cap was active")
+ .flags(total)
+ ;
+
+ rob_cap_inst_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:cap_inst")
+ .desc("number of instructions held up by ROB cap")
+ .flags(total)
+ ;
+
+ iq_cap_events
+ .init(cpu->number_of_threads)
+ .name(name() +".IQ:cap_events" )
+ .desc("number of cycles where IQ cap was active")
+ .flags(total)
+ ;
+
+ iq_cap_inst_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".IQ:cap_inst")
+ .desc("number of instructions held up by IQ cap")
+ .flags(total)
+ ;
+
+
+ exe_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:count")
+ .desc("number of insts issued")
+ .flags(total)
+ ;
+
+ exe_swp
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:swp")
+ .desc("number of swp insts issued")
+ .flags(total)
+ ;
+
+ exe_nop
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:nop")
+ .desc("number of nop insts issued")
+ .flags(total)
+ ;
+
+ exe_refs
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:refs")
+ .desc("number of memory reference insts issued")
+ .flags(total)
+ ;
+
+ exe_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:loads")
+ .desc("number of load insts issued")
+ .flags(total)
+ ;
+
+ exe_branches
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:branches")
+ .desc("Number of branches issued")
+ .flags(total)
+ ;
+
+ issued_ops
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:op_count")
+ .desc("number of insts issued")
+ .flags(total)
+ ;
+
+/*
+ for (int i=0; i<Num_OpClasses; ++i) {
+ stringstream subname;
+ subname << opClassStrings[i] << "_delay";
+ issue_delay_dist.subname(i, subname.str());
+ }
+*/
+ //
+ // Other stats
+ //
+ lsq_forw_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".LSQ:forw_loads")
+ .desc("number of loads forwarded via LSQ")
+ .flags(total)
+ ;
+
+ inv_addr_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:addr_loads")
+ .desc("number of invalid-address loads")
+ .flags(total)
+ ;
+
+ inv_addr_swpfs
+ .init(cpu->number_of_threads)
+ .name(name() + ".ISSUE:addr_swpfs")
+ .desc("number of invalid-address SW prefetches")
+ .flags(total)
+ ;
+
+ lsq_blocked_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".LSQ:blocked_loads")
+ .desc("number of ready loads not issued due to memory disambiguation")
+ .flags(total)
+ ;
+
+ lsqInversion
+ .name(name() + ".ISSUE:lsq_invert")
+ .desc("Number of times LSQ instruction issued early")
+ ;
+
+ n_issued_dist
+ .init(issueWidth + 1)
+ .name(name() + ".ISSUE:issued_per_cycle")
+ .desc("Number of insts issued each cycle")
+ .flags(total | pdf | dist)
+ ;
+ issue_delay_dist
+ .init(Num_OpClasses,0,99,2)
+ .name(name() + ".ISSUE:")
+ .desc("cycles from operands ready to issue")
+ .flags(pdf | cdf)
+ ;
+
+ queue_res_dist
+ .init(Num_OpClasses, 0, 99, 2)
+ .name(name() + ".IQ:residence:")
+ .desc("cycles from dispatch to issue")
+ .flags(total | pdf | cdf )
+ ;
+ for (int i = 0; i < Num_OpClasses; ++i) {
+ queue_res_dist.subname(i, opClassStrings[i]);
+ }
+
+ writeback_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:count")
+ .desc("cumulative count of insts written-back")
+ .flags(total)
+ ;
+
+ producer_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:producers")
+ .desc("num instructions producing a value")
+ .flags(total)
+ ;
+
+ consumer_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:consumers")
+ .desc("num instructions consuming a value")
+ .flags(total)
+ ;
+
+ wb_penalized
+ .init(cpu->number_of_threads)
+ .name(name() + ".WB:penalized")
+ .desc("number of instrctions required to write to 'other' IQ")
+ .flags(total)
+ ;
+
+
+ wb_penalized_rate
+ .name(name() + ".WB:penalized_rate")
+ .desc ("fraction of instructions written-back that wrote to 'other' IQ")
+ .flags(total)
+ ;
+
+ wb_penalized_rate = wb_penalized / writeback_count;
+
+ wb_fanout
+ .name(name() + ".WB:fanout")
+ .desc("average fanout of values written-back")
+ .flags(total)
+ ;
+
+ wb_fanout = producer_inst / consumer_inst;
+
+ wb_rate
+ .name(name() + ".WB:rate")
+ .desc("insts written-back per cycle")
+ .flags(total)
+ ;
+ wb_rate = writeback_count / cpu->numCycles;
+
+ stat_com_inst
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:count")
+ .desc("Number of instructions committed")
+ .flags(total)
+ ;
+
+ stat_com_swp
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:swp_count")
+ .desc("Number of s/w prefetches committed")
+ .flags(total)
+ ;
+
+ stat_com_refs
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:refs")
+ .desc("Number of memory references committed")
+ .flags(total)
+ ;
+
+ stat_com_loads
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:loads")
+ .desc("Number of loads committed")
+ .flags(total)
+ ;
+
+ stat_com_membars
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:membars")
+ .desc("Number of memory barriers committed")
+ .flags(total)
+ ;
+
+ stat_com_branches
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:branches")
+ .desc("Number of branches committed")
+ .flags(total)
+ ;
+ n_committed_dist
+ .init(0,commitWidth,1)
+ .name(name() + ".COM:committed_per_cycle")
+ .desc("Number of insts commited each cycle")
+ .flags(pdf)
+ ;
+
+ //
+ // Commit-Eligible instructions...
+ //
+ // -> The number of instructions eligible to commit in those
+ // cycles where we reached our commit BW limit (less the number
+ // actually committed)
+ //
+ // -> The average value is computed over ALL CYCLES... not just
+ // the BW limited cycles
+ //
+ // -> The standard deviation is computed only over cycles where
+ // we reached the BW limit
+ //
+ commit_eligible
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:bw_limited")
+ .desc("number of insts not committed due to BW limits")
+ .flags(total)
+ ;
+
+ commit_eligible_samples
+ .name(name() + ".COM:bw_lim_events")
+ .desc("number cycles where commit BW limit reached")
+ ;
+
+ squashedInsts
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:squashed_insts")
+ .desc("Number of instructions removed from inst list")
+ ;
+
+ ROBSquashedInsts
+ .init(cpu->number_of_threads)
+ .name(name() + ".COM:rob_squashed_insts")
+ .desc("Number of instructions removed from inst list when they reached the head of the ROB")
+ ;
+
+ ROB_fcount
+ .name(name() + ".ROB:full_count")
+ .desc("number of cycles where ROB was full")
+ ;
+
+ ROB_count
+ .init(cpu->number_of_threads)
+ .name(name() + ".ROB:occupancy")
+ .desc(name() + ".ROB occupancy (cumulative)")
+ .flags(total)
+ ;
+
+ ROB_full_rate
+ .name(name() + ".ROB:full_rate")
+ .desc("ROB full per cycle")
+ ;
+ ROB_full_rate = ROB_fcount / cpu->numCycles;
+
+ ROB_occ_rate
+ .name(name() + ".ROB:occ_rate")
+ .desc("ROB occupancy rate")
+ .flags(total)
+ ;
+ ROB_occ_rate = ROB_count / cpu->numCycles;
+
+ ROB_occ_dist
+ .init(cpu->number_of_threads,0,numROBEntries,2)
+ .name(name() + ".ROB:occ_dist")
+ .desc("ROB Occupancy per cycle")
+ .flags(total | cdf)
+ ;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::setCPU(OzoneCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+ LSQ.setCPU(cpu_ptr);
+ checker = cpu->checker;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm)
+{
+ comm = _comm;
+ toIEW = comm->getWire(0);
+ fromCommit = comm->getWire(-1);
+}
+
+#if FULL_SYSTEM
+template <class Impl>
+void
+LWBackEnd<Impl>::checkInterrupts()
+{
+ if (cpu->checkInterrupts &&
+ cpu->check_interrupts() &&
+ !cpu->inPalMode(thread->readPC()) &&
+ !trapSquash &&
+ !tcSquash) {
+ frontEnd->interruptPending = true;
+ if (robEmpty() && !LSQ.hasStoresToWB()) {
+ // Will need to squash all instructions currently in flight and have
+ // the interrupt handler restart at the last non-committed inst.
+ // Most of that can be handled through the trap() function. The
+ // processInterrupts() function really just checks for interrupts
+ // and then calls trap() if there is an interrupt present.
+
+ // Not sure which thread should be the one to interrupt. For now
+ // always do thread 0.
+ assert(!thread->inSyscall);
+ thread->inSyscall = true;
+
+ // CPU will handle implementation of the interrupt.
+ cpu->processInterrupts();
+
+ // Now squash or record that I need to squash this cycle.
+ commitStatus = TrapPending;
+
+ // Exit state update mode to avoid accidental updating.
+ thread->inSyscall = false;
+
+ // Generate trap squash event.
+ generateTrapEvent();
+
+ DPRINTF(BE, "Interrupt detected.\n");
+ } else {
+ DPRINTF(BE, "Interrupt must wait for ROB to drain.\n");
+ }
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::handleFault(Fault &fault, Tick latency)
+{
+ DPRINTF(BE, "Handling fault!\n");
+
+ assert(!thread->inSyscall);
+
+ thread->inSyscall = true;
+
+ // Consider holding onto the trap and waiting until the trap event
+ // happens for this to be executed.
+ fault->invoke(thread->getTC());
+
+ // Exit state update mode to avoid accidental updating.
+ thread->inSyscall = false;
+
+ commitStatus = TrapPending;
+
+ // Generate trap squash event.
+ generateTrapEvent(latency);
+}
+#endif
+
+template <class Impl>
+void
+LWBackEnd<Impl>::tick()
+{
+ DPRINTF(BE, "Ticking back end\n");
+
+ if (switchPending && robEmpty() && !LSQ.hasStoresToWB()) {
+ cpu->signalSwitched();
+ return;
+ }
+
+ ROB_count[0]+= numInsts;
+
+ wbCycle = 0;
+
+ // Read in any done instruction information and update the IQ or LSQ.
+ updateStructures();
+
+#if FULL_SYSTEM
+ checkInterrupts();
+
+ if (trapSquash) {
+ assert(!tcSquash);
+ squashFromTrap();
+ } else if (tcSquash) {
+ squashFromTC();
+ }
+#endif
+
+ if (dispatchStatus != Blocked) {
+ dispatchInsts();
+ } else {
+ checkDispatchStatus();
+ }
+
+ if (commitStatus != TrapPending) {
+ executeInsts();
+
+ commitInsts();
+ }
+
+ LSQ.writebackStores();
+
+ DPRINTF(BE, "Waiting insts: %i, mem ops: %i, ROB entries in use: %i, "
+ "LSQ loads: %i, LSQ stores: %i\n",
+ waitingInsts, numWaitingMemOps, numInsts,
+ LSQ.numLoads(), LSQ.numStores());
+
+#ifdef DEBUG
+ assert(numInsts == instList.size());
+ assert(waitingInsts == waitingList.size());
+ assert(numWaitingMemOps == waitingMemOps.size());
+ assert(!switchedOut);
+#endif
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::updateStructures()
+{
+ if (fromCommit->doneSeqNum) {
+ LSQ.commitLoads(fromCommit->doneSeqNum);
+ LSQ.commitStores(fromCommit->doneSeqNum);
+ }
+
+ if (fromCommit->nonSpecSeqNum) {
+ if (fromCommit->uncached) {
+// LSQ.executeLoad(fromCommit->lqIdx);
+ } else {
+// IQ.scheduleNonSpec(
+// fromCommit->nonSpecSeqNum);
+ }
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::addToLSQ(DynInstPtr &inst)
+{
+ // Do anything LSQ specific here?
+ LSQ.insert(inst);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::dispatchInsts()
+{
+ DPRINTF(BE, "Trying to dispatch instructions.\n");
+
+ while (numInsts < numROBEntries &&
+ numWaitingMemOps < maxOutstandingMemOps) {
+ // Get instruction from front of time buffer
+ DynInstPtr inst = frontEnd->getInst();
+ if (!inst) {
+ break;
+ } else if (inst->isSquashed()) {
+ continue;
+ }
+
+ ++numInsts;
+ instList.push_front(inst);
+
+ inst->setInROB();
+
+ DPRINTF(BE, "Dispatching instruction [sn:%lli] PC:%#x\n",
+ inst->seqNum, inst->readPC());
+
+ for (int i = 0; i < inst->numDestRegs(); ++i)
+ renameTable[inst->destRegIdx(i)] = inst;
+
+ if (inst->isMemBarrier() || inst->isWriteBarrier()) {
+ if (memBarrier) {
+ DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
+ "barrier [sn:%lli].\n",
+ inst->seqNum, memBarrier->seqNum);
+ memBarrier->addMemDependent(inst);
+ inst->addSrcMemInst(memBarrier);
+ }
+ memBarrier = inst;
+ inst->setCanCommit();
+ } else if (inst->readyToIssue() &&
+ !inst->isNonSpeculative() &&
+ !inst->isStoreConditional()) {
+ if (inst->isMemRef()) {
+
+ LSQ.insert(inst);
+ if (memBarrier) {
+ DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
+ "barrier [sn:%lli].\n",
+ inst->seqNum, memBarrier->seqNum);
+ memBarrier->addMemDependent(inst);
+ inst->addSrcMemInst(memBarrier);
+ addWaitingMemOp(inst);
+
+ waitingList.push_front(inst);
+ inst->iqIt = waitingList.begin();
+ inst->iqItValid = true;
+ waitingInsts++;
+ } else {
+ DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
+ "exeList.\n",
+ inst->seqNum);
+ exeList.push(inst);
+ }
+ } else if (inst->isNop()) {
+ DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n",
+ inst->seqNum);
+ inst->setIssued();
+ inst->setExecuted();
+ inst->setCanCommit();
+ } else {
+ DPRINTF(BE, "Instruction [sn:%lli] ready, addding to "
+ "exeList.\n",
+ inst->seqNum);
+ exeList.push(inst);
+ }
+ } else {
+ if (inst->isNonSpeculative() || inst->isStoreConditional()) {
+ inst->setCanCommit();
+ DPRINTF(BE, "Adding non speculative instruction\n");
+ }
+
+ if (inst->isMemRef()) {
+ addWaitingMemOp(inst);
+ LSQ.insert(inst);
+ if (memBarrier) {
+ memBarrier->addMemDependent(inst);
+ inst->addSrcMemInst(memBarrier);
+
+ DPRINTF(BE, "Instruction [sn:%lli] is waiting on "
+ "barrier [sn:%lli].\n",
+ inst->seqNum, memBarrier->seqNum);
+ }
+ }
+
+ DPRINTF(BE, "Instruction [sn:%lli] not ready, addding to "
+ "waitingList.\n",
+ inst->seqNum);
+ waitingList.push_front(inst);
+ inst->iqIt = waitingList.begin();
+ inst->iqItValid = true;
+ waitingInsts++;
+ }
+ }
+
+ // Check if IQ or LSQ is full. If so we'll need to break and stop
+ // removing instructions. Also update the number of insts to remove
+ // from the queue. Check here if we don't care about exact stall
+ // conditions.
+/*
+ bool stall = false;
+ if (IQ.isFull()) {
+ DPRINTF(BE, "IQ is full!\n");
+ stall = true;
+ } else if (LSQ.isFull()) {
+ DPRINTF(BE, "LSQ is full!\n");
+ stall = true;
+ } else if (isFull()) {
+ DPRINTF(BE, "ROB is full!\n");
+ stall = true;
+ ROB_fcount++;
+ }
+ if (stall) {
+ d2i.advance();
+ dispatchStall();
+ return;
+ }
+*/
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::dispatchStall()
+{
+ dispatchStatus = Blocked;
+ if (!cpu->decoupledFrontEnd) {
+ // Tell front end to stall here through a timebuffer, or just tell
+ // it directly.
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::checkDispatchStatus()
+{
+ DPRINTF(BE, "Checking dispatch status\n");
+ assert(dispatchStatus == Blocked);
+ if (!LSQ.isFull() && !isFull()) {
+ DPRINTF(BE, "Dispatch no longer blocked\n");
+ dispatchStatus = Running;
+ dispatchInsts();
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::executeInsts()
+{
+ DPRINTF(BE, "Trying to execute instructions\n");
+
+ int num_executed = 0;
+ while (!exeList.empty() && num_executed < issueWidth) {
+ DynInstPtr inst = exeList.top();
+
+ DPRINTF(BE, "Executing inst [sn:%lli] PC: %#x\n",
+ inst->seqNum, inst->readPC());
+
+ // Check if the instruction is squashed; if so then skip it
+ // and don't count it towards the FU usage.
+ if (inst->isSquashed()) {
+ DPRINTF(BE, "Execute: Instruction was squashed.\n");
+
+ // Not sure how to handle this plus the method of sending # of
+ // instructions to use. Probably will just have to count it
+ // towards the bandwidth usage, but not the FU usage.
+ ++num_executed;
+
+ // Consider this instruction executed so that commit can go
+ // ahead and retire the instruction.
+ inst->setExecuted();
+
+ // Not sure if I should set this here or just let commit try to
+ // commit any squashed instructions. I like the latter a bit more.
+ inst->setCanCommit();
+
+// ++iewExecSquashedInsts;
+ exeList.pop();
+
+ continue;
+ }
+
+ Fault fault = NoFault;
+
+ // Execute instruction.
+ // Note that if the instruction faults, it will be handled
+ // at the commit stage.
+ if (inst->isMemRef() &&
+ (!inst->isDataPrefetch() && !inst->isInstPrefetch())) {
+ DPRINTF(BE, "Execute: Initiating access for memory "
+ "reference.\n");
+
+ if (inst->isLoad()) {
+ LSQ.executeLoad(inst);
+ } else if (inst->isStore()) {
+ LSQ.executeStore(inst);
+ if (inst->req && !(inst->req->getFlags() & LOCKED)) {
+ inst->setExecuted();
+
+ instToCommit(inst);
+ }
+ } else {
+ panic("Unknown mem type!");
+ }
+ } else {
+ inst->execute();
+
+ inst->setExecuted();
+
+ instToCommit(inst);
+ }
+
+ updateExeInstStats(inst);
+
+ ++funcExeInst;
+ ++num_executed;
+
+ exeList.pop();
+
+ if (inst->mispredicted()) {
+ squashDueToBranch(inst);
+ break;
+ } else if (LSQ.violation()) {
+ // Get the DynInst that caused the violation. Note that this
+ // clears the violation signal.
+ DynInstPtr violator;
+ violator = LSQ.getMemDepViolator();
+
+ DPRINTF(BE, "LDSTQ detected a violation. Violator PC: "
+ "%#x, inst PC: %#x. Addr is: %#x.\n",
+ violator->readPC(), inst->readPC(), inst->physEffAddr);
+
+ // Squash.
+ squashDueToMemViolation(inst);
+ }
+ }
+
+ issued_ops[0]+= num_executed;
+ n_issued_dist[num_executed]++;
+}
+
+template<class Impl>
+void
+LWBackEnd<Impl>::instToCommit(DynInstPtr &inst)
+{
+
+ DPRINTF(BE, "Sending instructions to commit [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ if (!inst->isSquashed()) {
+ DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ inst->setCanCommit();
+
+ if (inst->isExecuted()) {
+ inst->setResultReady();
+ int dependents = wakeDependents(inst);
+ if (dependents) {
+ producer_inst[0]++;
+ consumer_inst[0]+= dependents;
+ }
+ }
+ }
+
+ writeback_count[0]++;
+}
+#if 0
+template <class Impl>
+void
+LWBackEnd<Impl>::writebackInsts()
+{
+ int wb_width = wbWidth;
+ // Using this method I'm not quite sure how to prevent an
+ // instruction from waking its own dependents multiple times,
+ // without the guarantee that commit always has enough bandwidth
+ // to accept all instructions being written back. This guarantee
+ // might not be too unrealistic.
+ InstListIt wb_inst_it = writeback.begin();
+ InstListIt wb_end_it = writeback.end();
+ int inst_num = 0;
+ int consumer_insts = 0;
+
+ for (; inst_num < wb_width &&
+ wb_inst_it != wb_end_it; inst_num++) {
+ DynInstPtr inst = (*wb_inst_it);
+
+ // Some instructions will be sent to commit without having
+ // executed because they need commit to handle them.
+ // E.g. Uncached loads have not actually executed when they
+ // are first sent to commit. Instead commit must tell the LSQ
+ // when it's ready to execute the uncached load.
+ if (!inst->isSquashed()) {
+ DPRINTF(BE, "Writing back instruction [sn:%lli] PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ inst->setCanCommit();
+ inst->setResultReady();
+
+ if (inst->isExecuted()) {
+ int dependents = wakeDependents(inst);
+ if (dependents) {
+ producer_inst[0]++;
+ consumer_insts+= dependents;
+ }
+ }
+ }
+
+ writeback.erase(wb_inst_it++);
+ }
+ LSQ.writebackStores();
+ consumer_inst[0]+= consumer_insts;
+ writeback_count[0]+= inst_num;
+}
+#endif
+template <class Impl>
+bool
+LWBackEnd<Impl>::commitInst(int inst_num)
+{
+ // Read instruction from the head of the ROB
+ DynInstPtr inst = instList.back();
+
+ // Make sure instruction is valid
+ assert(inst);
+
+ if (!inst->readyToCommit())
+ return false;
+
+ DPRINTF(BE, "Trying to commit instruction [sn:%lli] PC:%#x\n",
+ inst->seqNum, inst->readPC());
+
+ thread->setPC(inst->readPC());
+ thread->setNextPC(inst->readNextPC());
+ inst->setAtCommit();
+
+ // If the instruction is not executed yet, then it is a non-speculative
+ // or store inst. Signal backwards that it should be executed.
+ if (!inst->isExecuted()) {
+ if (inst->isNonSpeculative() ||
+ inst->isStoreConditional() ||
+ inst->isMemBarrier() ||
+ inst->isWriteBarrier()) {
+#if !FULL_SYSTEM
+ // Hack to make sure syscalls aren't executed until all stores
+ // write back their data. This direct communication shouldn't
+ // be used for anything other than this.
+ if (inst_num > 0 || LSQ.hasStoresToWB())
+#else
+ if ((inst->isMemBarrier() || inst->isWriteBarrier() ||
+ inst->isQuiesce()) &&
+ LSQ.hasStoresToWB())
+#endif
+ {
+ DPRINTF(BE, "Waiting for all stores to writeback.\n");
+ return false;
+ }
+
+ DPRINTF(BE, "Encountered a store or non-speculative "
+ "instruction at the head of the ROB, PC %#x.\n",
+ inst->readPC());
+
+ if (inst->isMemBarrier() || inst->isWriteBarrier()) {
+ DPRINTF(BE, "Waking dependents on barrier [sn:%lli]\n",
+ inst->seqNum);
+ assert(memBarrier);
+ wakeDependents(inst, true);
+ if (memBarrier == inst)
+ memBarrier = NULL;
+ inst->clearMemDependents();
+ }
+
+ // Send back the non-speculative instruction's sequence number.
+ if (inst->iqItValid) {
+ DPRINTF(BE, "Removing instruction from waiting list\n");
+ waitingList.erase(inst->iqIt);
+ inst->iqItValid = false;
+ waitingInsts--;
+ assert(waitingInsts >= 0);
+ if (inst->isStore())
+ removeWaitingMemOp(inst);
+ }
+
+ exeList.push(inst);
+
+ // Change the instruction so it won't try to commit again until
+ // it is executed.
+ inst->clearCanCommit();
+
+// ++commitNonSpecStalls;
+
+ return false;
+ } else if (inst->isLoad()) {
+ DPRINTF(BE, "[sn:%lli]: Uncached load, PC %#x.\n",
+ inst->seqNum, inst->readPC());
+
+ // Send back the non-speculative instruction's sequence
+ // number. Maybe just tell the lsq to re-execute the load.
+
+ // Send back the non-speculative instruction's sequence number.
+ if (inst->iqItValid) {
+ DPRINTF(BE, "Removing instruction from waiting list\n");
+ waitingList.erase(inst->iqIt);
+ inst->iqItValid = false;
+ waitingInsts--;
+ assert(waitingInsts >= 0);
+ removeWaitingMemOp(inst);
+ }
+ replayMemInst(inst);
+
+ inst->clearCanCommit();
+
+ return false;
+ } else {
+ panic("Trying to commit un-executed instruction "
+ "of unknown type!\n");
+ }
+ }
+
+ // Not handled for now.
+ assert(!inst->isThreadSync());
+ assert(inst->memDepReady());
+ // Stores will mark themselves as totally completed as they need
+ // to wait to writeback to memory. @todo: Hack...attempt to fix
+ // having the checker be forced to wait until a store completes in
+ // order to check all of the instructions. If the store at the
+ // head of the check list misses, but a later store hits, then
+ // loads in the checker may see the younger store values instead
+ // of the store they should see. Either the checker needs its own
+ // memory (annoying to update), its own store buffer (how to tell
+ // which value is correct?), or something else...
+ if (!inst->isStore()) {
+ inst->setCompleted();
+ }
+ // Check if the instruction caused a fault. If so, trap.
+ Fault inst_fault = inst->getFault();
+
+ // Use checker prior to updating anything due to traps or PC
+ // based events.
+#if USE_CHECKER
+ if (checker) {
+ checker->verify(inst);
+ }
+#endif
+
+ if (inst_fault != NoFault) {
+ DPRINTF(BE, "Inst [sn:%lli] PC %#x has a fault\n",
+ inst->seqNum, inst->readPC());
+
+ // Instruction is completed as it has a fault.
+ inst->setCompleted();
+
+ if (LSQ.hasStoresToWB()) {
+ DPRINTF(BE, "Stores still in flight, will wait until drained.\n");
+ return false;
+ } else if (inst_num != 0) {
+ DPRINTF(BE, "Will wait until instruction is head of commit group.\n");
+ return false;
+ }
+#if USE_CHECKER
+ else if (checker && inst->isStore()) {
+ checker->verify(inst);
+ }
+#endif
+
+ thread->setInst(
+ static_cast<TheISA::MachInst>(inst->staticInst->machInst));
+#if FULL_SYSTEM
+ handleFault(inst_fault);
+ return false;
+#else // !FULL_SYSTEM
+ panic("fault (%d) detected @ PC %08p", inst_fault,
+ inst->PC);
+#endif // FULL_SYSTEM
+ }
+
+ int freed_regs = 0;
+
+ for (int i = 0; i < inst->numDestRegs(); ++i) {
+ DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n",
+ (int)inst->destRegIdx(i), inst->seqNum);
+ thread->renameTable[inst->destRegIdx(i)] = inst;
+ ++freed_regs;
+ }
+
+ if (inst->traceData) {
+ inst->traceData->setFetchSeq(inst->seqNum);
+ inst->traceData->setCPSeq(thread->numInst);
+ inst->traceData->finalize();
+ inst->traceData = NULL;
+ }
+
+ inst->clearDependents();
+
+ frontEnd->addFreeRegs(freed_regs);
+
+ instList.pop_back();
+
+ --numInsts;
+ ++thread->funcExeInst;
+ // Maybe move this to where the fault is handled; if the fault is
+ // handled, don't try to set this myself as the fault will set it.
+ // If not, then I set thread->PC = thread->nextPC and
+ // thread->nextPC = thread->nextPC + 4.
+ thread->setPC(thread->readNextPC());
+ thread->setNextPC(thread->readNextPC() + sizeof(TheISA::MachInst));
+ updateComInstStats(inst);
+
+ // Write the done sequence number here.
+ toIEW->doneSeqNum = inst->seqNum;
+ lastCommitCycle = curTick;
+
+#if FULL_SYSTEM
+ int count = 0;
+ Addr oldpc;
+ do {
+ if (count == 0)
+ assert(!thread->inSyscall && !thread->trapPending);
+ oldpc = thread->readPC();
+ cpu->system->pcEventQueue.service(
+ thread->getTC());
+ count++;
+ } while (oldpc != thread->readPC());
+ if (count > 1) {
+ DPRINTF(BE, "PC skip function event, stopping commit\n");
+ tcSquash = true;
+ return false;
+ }
+#endif
+ return true;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::commitInsts()
+{
+ // Not sure this should be a loop or not.
+ int inst_num = 0;
+ while (!instList.empty() && inst_num < commitWidth) {
+ if (instList.back()->isSquashed()) {
+ instList.back()->clearDependents();
+ instList.pop_back();
+ --numInsts;
+ ROBSquashedInsts[instList.back()->threadNumber]++;
+ continue;
+ }
+
+ if (!commitInst(inst_num++)) {
+ DPRINTF(BE, "Can't commit, Instruction [sn:%lli] PC "
+ "%#x is head of ROB and not ready\n",
+ instList.back()->seqNum, instList.back()->readPC());
+ --inst_num;
+ break;
+ }
+ }
+ n_committed_dist.sample(inst_num);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squash(const InstSeqNum &sn)
+{
+ LSQ.squash(sn);
+
+ int freed_regs = 0;
+ InstListIt waiting_list_end = waitingList.end();
+ InstListIt insts_it = waitingList.begin();
+
+ while (insts_it != waiting_list_end && (*insts_it)->seqNum > sn)
+ {
+ if ((*insts_it)->isSquashed()) {
+ ++insts_it;
+ continue;
+ }
+ DPRINTF(BE, "Squashing instruction on waitingList PC %#x, [sn:%lli].\n",
+ (*insts_it)->readPC(),
+ (*insts_it)->seqNum);
+
+ if ((*insts_it)->isMemRef()) {
+ DPRINTF(BE, "Squashing a waiting mem op [sn:%lli]\n",
+ (*insts_it)->seqNum);
+ removeWaitingMemOp((*insts_it));
+ }
+
+ waitingList.erase(insts_it++);
+ waitingInsts--;
+ }
+ assert(waitingInsts >= 0);
+
+ insts_it = instList.begin();
+
+ while (!instList.empty() && (*insts_it)->seqNum > sn)
+ {
+ if ((*insts_it)->isSquashed()) {
+ ++insts_it;
+ continue;
+ }
+ DPRINTF(BE, "Squashing instruction on inst list PC %#x, [sn:%lli].\n",
+ (*insts_it)->readPC(),
+ (*insts_it)->seqNum);
+
+ // Mark the instruction as squashed, and ready to commit so that
+ // it can drain out of the pipeline.
+ (*insts_it)->setSquashed();
+
+ (*insts_it)->setCanCommit();
+
+ (*insts_it)->clearInROB();
+
+ for (int i = 0; i < (*insts_it)->numDestRegs(); ++i) {
+ DynInstPtr prev_dest = (*insts_it)->getPrevDestInst(i);
+ DPRINTF(BE, "Commit rename map setting reg %i to [sn:%lli]\n",
+ (int)(*insts_it)->destRegIdx(i), prev_dest->seqNum);
+ renameTable[(*insts_it)->destRegIdx(i)] = prev_dest;
+ ++freed_regs;
+ }
+
+ (*insts_it)->clearDependents();
+
+ squashedInsts[(*insts_it)->threadNumber]++;
+
+ instList.erase(insts_it++);
+ --numInsts;
+ }
+
+ insts_it = waitingList.begin();
+ while (!waitingList.empty() && insts_it != waitingList.end()) {
+ if ((*insts_it)->seqNum < sn) {
+ ++insts_it;
+ continue;
+ }
+ assert((*insts_it)->isSquashed());
+
+ waitingList.erase(insts_it++);
+ waitingInsts--;
+ }
+
+ while (memBarrier && memBarrier->seqNum > sn) {
+ DPRINTF(BE, "[sn:%lli] Memory barrier squashed (or previously "
+ "squashed)\n", memBarrier->seqNum);
+ memBarrier->clearMemDependents();
+ if (memBarrier->memDepReady()) {
+ DPRINTF(BE, "No previous barrier\n");
+ memBarrier = NULL;
+ } else {
+ std::list<DynInstPtr> &srcs = memBarrier->getMemSrcs();
+ memBarrier = srcs.front();
+ srcs.pop_front();
+ assert(srcs.empty());
+ DPRINTF(BE, "Previous barrier: [sn:%lli]\n",
+ memBarrier->seqNum);
+ }
+ }
+
+ frontEnd->addFreeRegs(freed_regs);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squashFromTC()
+{
+ InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1;
+ squash(squashed_inst);
+ frontEnd->squash(squashed_inst, thread->readPC(),
+ false, false);
+ frontEnd->interruptPending = false;
+
+ thread->trapPending = false;
+ thread->inSyscall = false;
+ tcSquash = false;
+ commitStatus = Running;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squashFromTrap()
+{
+ InstSeqNum squashed_inst = robEmpty() ? 0 : instList.back()->seqNum - 1;
+ squash(squashed_inst);
+ frontEnd->squash(squashed_inst, thread->readPC(),
+ false, false);
+ frontEnd->interruptPending = false;
+
+ thread->trapPending = false;
+ thread->inSyscall = false;
+ trapSquash = false;
+ commitStatus = Running;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squashDueToBranch(DynInstPtr &inst)
+{
+ // Update the branch predictor state I guess
+ DPRINTF(BE, "Squashing due to branch [sn:%lli], will restart at PC %#x\n",
+ inst->seqNum, inst->readNextPC());
+ squash(inst->seqNum);
+ frontEnd->squash(inst->seqNum, inst->readNextPC(),
+ true, inst->mispredicted());
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squashDueToMemViolation(DynInstPtr &inst)
+{
+ // Update the branch predictor state I guess
+ DPRINTF(BE, "Squashing due to violation [sn:%lli], will restart at PC %#x\n",
+ inst->seqNum, inst->readNextPC());
+ squash(inst->seqNum);
+ frontEnd->squash(inst->seqNum, inst->readNextPC(),
+ false, inst->mispredicted());
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::squashDueToMemBlocked(DynInstPtr &inst)
+{
+ DPRINTF(IEW, "Memory blocked, squashing load and younger insts, "
+ "PC: %#x [sn:%i].\n", inst->readPC(), inst->seqNum);
+
+ squash(inst->seqNum - 1);
+ frontEnd->squash(inst->seqNum - 1, inst->readPC());
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::fetchFault(Fault &fault)
+{
+ faultFromFetch = fault;
+ fetchHasFault = true;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::switchOut()
+{
+ switchPending = true;
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::doSwitchOut()
+{
+ switchedOut = true;
+ switchPending = false;
+ // Need to get rid of all committed, non-speculative state and write it
+ // to memory/TC. In this case this is stores that have committed and not
+ // yet written back.
+ assert(robEmpty());
+ assert(!LSQ.hasStoresToWB());
+
+ LSQ.switchOut();
+
+ squash(0);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::takeOverFrom(ThreadContext *old_tc)
+{
+ switchedOut = false;
+ tcSquash = false;
+ trapSquash = false;
+
+ numInsts = 0;
+ numWaitingMemOps = 0;
+ waitingMemOps.clear();
+ waitingInsts = 0;
+ switchedOut = false;
+ dispatchStatus = Running;
+ commitStatus = Running;
+ LSQ.takeOverFrom(old_tc);
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::updateExeInstStats(DynInstPtr &inst)
+{
+ int thread_number = inst->threadNumber;
+
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch())
+ exe_swp[thread_number]++;
+ else
+ exe_inst[thread_number]++;
+#else
+ exe_inst[thread_number]++;
+#endif
+
+ //
+ // Control operations
+ //
+ if (inst->isControl())
+ exe_branches[thread_number]++;
+
+ //
+ // Memory operations
+ //
+ if (inst->isMemRef()) {
+ exe_refs[thread_number]++;
+
+ if (inst->isLoad())
+ exe_loads[thread_number]++;
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::updateComInstStats(DynInstPtr &inst)
+{
+ unsigned tid = inst->threadNumber;
+
+ // keep an instruction count
+ thread->numInst++;
+ thread->numInsts++;
+
+ cpu->numInst++;
+ //
+ // Pick off the software prefetches
+ //
+#ifdef TARGET_ALPHA
+ if (inst->isDataPrefetch()) {
+ stat_com_swp[tid]++;
+ } else {
+ stat_com_inst[tid]++;
+ }
+#else
+ stat_com_inst[tid]++;
+#endif
+
+ //
+ // Control Instructions
+ //
+ if (inst->isControl())
+ stat_com_branches[tid]++;
+
+ //
+ // Memory references
+ //
+ if (inst->isMemRef()) {
+ stat_com_refs[tid]++;
+
+ if (inst->isLoad()) {
+ stat_com_loads[tid]++;
+ }
+ }
+
+ if (inst->isMemBarrier()) {
+ stat_com_membars[tid]++;
+ }
+}
+
+template <class Impl>
+void
+LWBackEnd<Impl>::dumpInsts()
+{
+ int num = 0;
+ int valid_num = 0;
+
+ InstListIt inst_list_it = --(instList.end());
+
+ cprintf("ExeList size: %i\n", exeList.size());
+
+ cprintf("Inst list size: %i\n", instList.size());
+
+ while (inst_list_it != instList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+ cprintf("Waiting list size: %i\n", waitingList.size());
+
+ inst_list_it = --(waitingList.end());
+
+ while (inst_list_it != waitingList.end())
+ {
+ cprintf("Instruction:%i\n",
+ num);
+ if (!(*inst_list_it)->isSquashed()) {
+ if (!(*inst_list_it)->isIssued()) {
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ } else if ((*inst_list_it)->isMemRef() &&
+ !(*inst_list_it)->memOpDone) {
+ // Loads that have not been marked as executed still count
+ // towards the total instructions.
+ ++valid_num;
+ cprintf("Count:%i\n", valid_num);
+ }
+ }
+
+ cprintf("PC:%#x\n[sn:%lli]\n[tid:%i]\n"
+ "Issued:%i\nSquashed:%i\n",
+ (*inst_list_it)->readPC(),
+ (*inst_list_it)->seqNum,
+ (*inst_list_it)->threadNumber,
+ (*inst_list_it)->isIssued(),
+ (*inst_list_it)->isSquashed());
+
+ if ((*inst_list_it)->isMemRef()) {
+ cprintf("MemOpDone:%i\n", (*inst_list_it)->memOpDone);
+ }
+
+ cprintf("\n");
+
+ inst_list_it--;
+ ++num;
+ }
+
+ cprintf("waitingMemOps list size: %i\n", waitingMemOps.size());
+
+ MemIt waiting_it = waitingMemOps.begin();
+
+ while (waiting_it != waitingMemOps.end())
+ {
+ cprintf("[sn:%lli] ", (*waiting_it));
+ waiting_it++;
+ ++num;
+ }
+ cprintf("\n");
+}
diff --git a/src/cpu/ozone/lw_lsq.cc b/src/cpu/ozone/lw_lsq.cc
new file mode 100644
index 000000000..8674e83a0
--- /dev/null
+++ b/src/cpu/ozone/lw_lsq.cc
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/ozone_impl.hh"
+#include "cpu/ozone/lw_lsq_impl.hh"
+
+// Force the instantiation of LDSTQ for all the implementations we care about.
+template class OzoneLWLSQ<OzoneImpl>;
+
diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh
new file mode 100644
index 000000000..c749e3aee
--- /dev/null
+++ b/src/cpu/ozone/lw_lsq.hh
@@ -0,0 +1,703 @@
+/*
+ * 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_OZONE_LW_LSQ_HH__
+#define __CPU_OZONE_LW_LSQ_HH__
+
+#include <list>
+#include <map>
+#include <queue>
+#include <algorithm>
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "config/full_system.hh"
+#include "base/hashmap.hh"
+#include "cpu/inst_seq.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+//#include "mem/page_table.hh"
+#include "sim/debug.hh"
+#include "sim/sim_object.hh"
+
+class MemObject;
+
+/**
+ * Class that implements the actual LQ and SQ for each specific thread.
+ * Both are circular queues; load entries are freed upon committing, while
+ * store entries are freed once they writeback. The LSQUnit tracks if there
+ * are memory ordering violations, and also detects partial load to store
+ * forwarding cases (a store only has part of a load's data) that requires
+ * the load to wait until the store writes back. In the former case it
+ * holds onto the instruction until the dependence unit looks at it, and
+ * in the latter it stalls the LSQ until the store writes back. At that
+ * point the load is replayed.
+ */
+template <class Impl>
+class OzoneLWLSQ {
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::OzoneCPU OzoneCPU;
+ typedef typename Impl::BackEnd BackEnd;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+ typedef typename Impl::IssueStruct IssueStruct;
+
+ typedef TheISA::IntReg IntReg;
+
+ typedef typename std::map<InstSeqNum, DynInstPtr>::iterator LdMapIt;
+
+ public:
+ /** Constructs an LSQ unit. init() must be called prior to use. */
+ OzoneLWLSQ();
+
+ /** Initializes the LSQ unit with the specified number of entries. */
+ void init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id);
+
+ /** Returns the name of the LSQ unit. */
+ std::string name() const;
+
+ /** Sets the CPU pointer. */
+ void setCPU(OzoneCPU *cpu_ptr);
+
+ /** Sets the back-end stage pointer. */
+ void setBE(BackEnd *be_ptr)
+ { be = be_ptr; }
+
+ /** Sets the page table pointer. */
+// void setPageTable(PageTable *pt_ptr);
+
+ /** Ticks the LSQ unit, which in this case only resets the number of
+ * used cache ports.
+ * @todo: Move the number of used ports up to the LSQ level so it can
+ * be shared by all LSQ units.
+ */
+ void tick() { usedPorts = 0; }
+
+ /** Inserts an instruction. */
+ void insert(DynInstPtr &inst);
+ /** Inserts a load instruction. */
+ void insertLoad(DynInstPtr &load_inst);
+ /** Inserts a store instruction. */
+ void insertStore(DynInstPtr &store_inst);
+
+ /** Executes a load instruction. */
+ Fault executeLoad(DynInstPtr &inst);
+
+ /** Executes a store instruction. */
+ Fault executeStore(DynInstPtr &inst);
+
+ /** Commits the head load. */
+ void commitLoad();
+ /** Commits loads older than a specific sequence number. */
+ void commitLoads(InstSeqNum &youngest_inst);
+
+ /** Commits stores older than a specific sequence number. */
+ void commitStores(InstSeqNum &youngest_inst);
+
+ /** Writes back stores. */
+ void writebackStores();
+
+ /** Completes the data access that has been returned from the
+ * memory system. */
+ void completeDataAccess(PacketPtr pkt);
+
+ // @todo: Include stats in the LSQ unit.
+ //void regStats();
+
+ /** Clears all the entries in the LQ. */
+ void clearLQ();
+
+ /** Clears all the entries in the SQ. */
+ void clearSQ();
+
+ /** Resizes the LQ to a given size. */
+ void resizeLQ(unsigned size);
+
+ /** Resizes the SQ to a given size. */
+ void resizeSQ(unsigned size);
+
+ /** Squashes all instructions younger than a specific sequence number. */
+ void squash(const InstSeqNum &squashed_num);
+
+ /** Returns if there is a memory ordering violation. Value is reset upon
+ * call to getMemDepViolator().
+ */
+ bool violation() { return memDepViolator; }
+
+ /** Returns the memory ordering violator. */
+ DynInstPtr getMemDepViolator();
+
+ /** Returns if a load became blocked due to the memory system. It clears
+ * the bool's value upon this being called.
+ */
+ bool loadBlocked()
+ { return isLoadBlocked; }
+
+ void clearLoadBlocked()
+ { isLoadBlocked = false; }
+
+ bool isLoadBlockedHandled()
+ { return loadBlockedHandled; }
+
+ void setLoadBlockedHandled()
+ { loadBlockedHandled = true; }
+
+ /** Returns the number of free entries (min of free LQ and SQ entries). */
+ unsigned numFreeEntries();
+
+ /** Returns the number of loads ready to execute. */
+ int numLoadsReady();
+
+ /** Returns the number of loads in the LQ. */
+ int numLoads() { return loads; }
+
+ /** Returns the number of stores in the SQ. */
+ int numStores() { return stores; }
+
+ /** Returns if either the LQ or SQ is full. */
+ bool isFull() { return lqFull() || sqFull(); }
+
+ /** Returns if the LQ is full. */
+ bool lqFull() { return loads >= (LQEntries - 1); }
+
+ /** Returns if the SQ is full. */
+ bool sqFull() { return stores >= (SQEntries - 1); }
+
+ /** Debugging function to dump instructions in the LSQ. */
+ void dumpInsts();
+
+ /** Returns the number of instructions in the LSQ. */
+ unsigned getCount() { return loads + stores; }
+
+ /** Returns if there are any stores to writeback. */
+ bool hasStoresToWB() { return storesToWB; }
+
+ /** Returns the number of stores to writeback. */
+ int numStoresToWB() { return storesToWB; }
+
+ /** Returns if the LSQ unit will writeback on this cycle. */
+ bool willWB() { return storeQueue.back().canWB &&
+ !storeQueue.back().completed &&
+ !isStoreBlocked; }
+
+ void switchOut();
+
+ void takeOverFrom(ThreadContext *old_tc = NULL);
+
+ bool isSwitchedOut() { return switchedOut; }
+
+ bool switchedOut;
+
+ private:
+ /** Writes back the instruction, sending it to IEW. */
+ void writeback(DynInstPtr &inst, PacketPtr pkt);
+
+ /** Handles completing the send of a store to memory. */
+ void storePostSend(Packet *pkt, DynInstPtr &inst);
+
+ /** Completes the store at the specified index. */
+ void completeStore(int store_idx);
+
+ /** Handles doing the retry. */
+ void recvRetry();
+
+ private:
+ /** Pointer to the CPU. */
+ OzoneCPU *cpu;
+
+ /** Pointer to the back-end stage. */
+ BackEnd *be;
+
+ MemObject *mem;
+
+ class DcachePort : public Port
+ {
+ protected:
+ OzoneCPU *cpu;
+
+ OzoneLWLSQ *lsq;
+
+ public:
+ DcachePort(OzoneCPU *_cpu, OzoneLWLSQ *_lsq)
+ : Port(_lsq->name() + "-dport"), cpu(_cpu), lsq(_lsq)
+ { }
+
+ protected:
+ virtual Tick recvAtomic(PacketPtr pkt);
+
+ virtual void recvFunctional(PacketPtr pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { resp.clear(); snoop.clear(); }
+
+ virtual bool recvTiming(PacketPtr pkt);
+
+ virtual void recvRetry();
+ };
+
+ /** Pointer to the D-cache. */
+ DcachePort *dcachePort;
+
+ /** Pointer to the page table. */
+// PageTable *pTable;
+
+ public:
+ struct SQEntry {
+ /** Constructs an empty store queue entry. */
+ SQEntry()
+ : inst(NULL), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0), lqIt(NULL)
+ { }
+
+ /** Constructs a store queue entry for a given instruction. */
+ SQEntry(DynInstPtr &_inst)
+ : inst(_inst), req(NULL), size(0), data(0),
+ canWB(0), committed(0), completed(0), lqIt(NULL)
+ { }
+
+ /** The store instruction. */
+ DynInstPtr inst;
+ /** The memory request for the store. */
+ RequestPtr req;
+ /** The size of the store. */
+ int size;
+ /** The store data. */
+ IntReg data;
+ /** Whether or not the store can writeback. */
+ bool canWB;
+ /** Whether or not the store is committed. */
+ bool committed;
+ /** Whether or not the store is completed. */
+ bool completed;
+
+ typename std::list<DynInstPtr>::iterator lqIt;
+ };
+
+ /** Derived class to hold any sender state the LSQ needs. */
+ class LSQSenderState : public Packet::SenderState
+ {
+ public:
+ /** Default constructor. */
+ LSQSenderState()
+ : noWB(false)
+ { }
+
+ /** Instruction who initiated the access to memory. */
+ DynInstPtr inst;
+ /** Whether or not it is a load. */
+ bool isLoad;
+ /** The LQ/SQ index of the instruction. */
+ int idx;
+ /** Whether or not the instruction will need to writeback. */
+ bool noWB;
+ };
+
+ /** Writeback event, specifically for when stores forward data to loads. */
+ class WritebackEvent : public Event {
+ public:
+ /** Constructs a writeback event. */
+ WritebackEvent(DynInstPtr &_inst, PacketPtr pkt, OzoneLWLSQ *lsq_ptr);
+
+ /** Processes the writeback event. */
+ void process();
+
+ /** Returns the description of this event. */
+ const char *description();
+
+ private:
+ /** Instruction whose results are being written back. */
+ DynInstPtr inst;
+
+ /** The packet that would have been sent to memory. */
+ PacketPtr pkt;
+
+ /** The pointer to the LSQ unit that issued the store. */
+ OzoneLWLSQ<Impl> *lsqPtr;
+ };
+
+ enum Status {
+ Running,
+ Idle,
+ DcacheMissStall,
+ DcacheMissSwitch
+ };
+
+ private:
+ /** The OzoneLWLSQ thread id. */
+ unsigned lsqID;
+
+ /** The status of the LSQ unit. */
+ Status _status;
+
+ /** The store queue. */
+ std::list<SQEntry> storeQueue;
+ /** The load queue. */
+ std::list<DynInstPtr> loadQueue;
+
+ typedef typename std::list<SQEntry>::iterator SQIt;
+ typedef typename std::list<DynInstPtr>::iterator LQIt;
+
+
+ struct HashFn {
+ size_t operator() (const int a) const
+ {
+ unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF;
+
+ return hash;
+ }
+ };
+
+ m5::hash_map<int, SQIt, HashFn> SQItHash;
+ std::queue<int> SQIndices;
+ m5::hash_map<int, LQIt, HashFn> LQItHash;
+ std::queue<int> LQIndices;
+
+ typedef typename m5::hash_map<int, LQIt, HashFn>::iterator LQHashIt;
+ typedef typename m5::hash_map<int, SQIt, HashFn>::iterator SQHashIt;
+ // Consider making these 16 bits
+ /** The number of LQ entries. */
+ unsigned LQEntries;
+ /** The number of SQ entries. */
+ unsigned SQEntries;
+
+ /** The number of load instructions in the LQ. */
+ int loads;
+ /** The number of store instructions in the SQ (excludes those waiting to
+ * writeback).
+ */
+ int stores;
+
+ int storesToWB;
+
+ /// @todo Consider moving to a more advanced model with write vs read ports
+ /** The number of cache ports available each cycle. */
+ int cachePorts;
+
+ /** The number of used cache ports in this cycle. */
+ int usedPorts;
+
+ //list<InstSeqNum> mshrSeqNums;
+
+ //Stats::Scalar<> dcacheStallCycles;
+ Counter lastDcacheStall;
+
+ // Make these per thread?
+ /** Whether or not the LSQ is stalled. */
+ bool stalled;
+ /** The store that causes the stall due to partial store to load
+ * forwarding.
+ */
+ InstSeqNum stallingStoreIsn;
+ /** The index of the above store. */
+ LQIt stallingLoad;
+
+ /** The packet that needs to be retried. */
+ PacketPtr retryPkt;
+
+ /** Whehter or not a store is blocked due to the memory system. */
+ bool isStoreBlocked;
+
+ /** Whether or not a load is blocked due to the memory system. It is
+ * cleared when this value is checked via loadBlocked().
+ */
+ bool isLoadBlocked;
+
+ bool loadBlockedHandled;
+
+ InstSeqNum blockedLoadSeqNum;
+
+ /** The oldest faulting load instruction. */
+ DynInstPtr loadFaultInst;
+ /** The oldest faulting store instruction. */
+ DynInstPtr storeFaultInst;
+
+ /** The oldest load that caused a memory ordering violation. */
+ DynInstPtr memDepViolator;
+
+ // Will also need how many read/write ports the Dcache has. Or keep track
+ // of that in stage that is one level up, and only call executeLoad/Store
+ // the appropriate number of times.
+
+ public:
+ /** Executes the load at the given index. */
+ template <class T>
+ Fault read(RequestPtr req, T &data, int load_idx);
+
+ /** Executes the store at the given index. */
+ template <class T>
+ Fault write(RequestPtr req, T &data, int store_idx);
+
+ /** Returns the sequence number of the head load instruction. */
+ InstSeqNum getLoadHeadSeqNum()
+ {
+ if (!loadQueue.empty()) {
+ return loadQueue.back()->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns the sequence number of the head store instruction. */
+ InstSeqNum getStoreHeadSeqNum()
+ {
+ if (!storeQueue.empty()) {
+ return storeQueue.back().inst->seqNum;
+ } else {
+ return 0;
+ }
+
+ }
+
+ /** Returns whether or not the LSQ unit is stalled. */
+ bool isStalled() { return stalled; }
+};
+
+template <class Impl>
+template <class T>
+Fault
+OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
+{
+ //Depending on issue2execute delay a squashed load could
+ //execute if it is found to be squashed in the same
+ //cycle it is scheduled to execute
+ typename m5::hash_map<int, LQIt, HashFn>::iterator
+ lq_hash_it = LQItHash.find(load_idx);
+ assert(lq_hash_it != LQItHash.end());
+ DynInstPtr inst = (*(*lq_hash_it).second);
+
+ // Make sure this isn't an uncacheable access
+ // A bit of a hackish way to get uncached accesses to work only if they're
+ // at the head of the LSQ and are ready to commit (at the head of the ROB
+ // too).
+ // @todo: Fix uncached accesses.
+ if (req->getFlags() & UNCACHEABLE &&
+ (inst != loadQueue.back() || !inst->isAtCommit())) {
+ DPRINTF(OzoneLSQ, "[sn:%lli] Uncached load and not head of "
+ "commit/LSQ!\n",
+ inst->seqNum);
+ be->rescheduleMemInst(inst);
+ return TheISA::genMachineCheckFault();
+ }
+
+ // Check the SQ for any previous stores that might lead to forwarding
+ SQIt sq_it = storeQueue.begin();
+ int store_size = 0;
+
+ DPRINTF(OzoneLSQ, "Read called, load idx: %i addr: %#x\n",
+ load_idx, req->getPaddr());
+
+ while (sq_it != storeQueue.end() && (*sq_it).inst->seqNum > inst->seqNum)
+ ++sq_it;
+
+ while (1) {
+ // End once we've reached the top of the LSQ
+ if (sq_it == storeQueue.end()) {
+ break;
+ }
+
+ assert((*sq_it).inst);
+
+ store_size = (*sq_it).size;
+
+ if (store_size == 0) {
+ sq_it++;
+ continue;
+ }
+
+ // Check if the store data is within the lower and upper bounds of
+ // addresses that the request needs.
+ bool store_has_lower_limit =
+ req->getVaddr() >= (*sq_it).inst->effAddr;
+ bool store_has_upper_limit =
+ (req->getVaddr() + req->getSize()) <= ((*sq_it).inst->effAddr +
+ store_size);
+ bool lower_load_has_store_part =
+ req->getVaddr() < ((*sq_it).inst->effAddr +
+ store_size);
+ bool upper_load_has_store_part =
+ (req->getVaddr() + req->getSize()) > (*sq_it).inst->effAddr;
+
+ // If the store's data has all of the data needed, we can forward.
+ if (store_has_lower_limit && store_has_upper_limit) {
+ int shift_amt = req->getVaddr() & (store_size - 1);
+ // Assumes byte addressing
+ shift_amt = shift_amt << 3;
+
+ // Cast this to type T?
+ data = (*sq_it).data >> shift_amt;
+
+ assert(!inst->memData);
+ inst->memData = new uint8_t[64];
+
+ memcpy(inst->memData, &data, req->getSize());
+
+ DPRINTF(OzoneLSQ, "Forwarding from store [sn:%lli] to load to "
+ "[sn:%lli] addr %#x, data %#x\n",
+ (*sq_it).inst->seqNum, inst->seqNum, req->getVaddr(),
+ *(inst->memData));
+
+ PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(inst->memData);
+
+ WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);
+
+ // We'll say this has a 1 cycle load-store forwarding latency
+ // for now.
+ // @todo: Need to make this a parameter.
+ wb->schedule(curTick);
+
+ // Should keep track of stat for forwarded data
+ return NoFault;
+ } else if ((store_has_lower_limit && lower_load_has_store_part) ||
+ (store_has_upper_limit && upper_load_has_store_part) ||
+ (lower_load_has_store_part && upper_load_has_store_part)) {
+ // This is the partial store-load forwarding case where a store
+ // has only part of the load's data.
+
+ // If it's already been written back, then don't worry about
+ // stalling on it.
+ if ((*sq_it).completed) {
+ sq_it++;
+ break;
+ }
+
+ // Must stall load and force it to retry, so long as it's the oldest
+ // load that needs to do so.
+ if (!stalled ||
+ (stalled &&
+ inst->seqNum <
+ (*stallingLoad)->seqNum)) {
+ stalled = true;
+ stallingStoreIsn = (*sq_it).inst->seqNum;
+ stallingLoad = (*lq_hash_it).second;
+ }
+
+ // Tell IQ/mem dep unit that this instruction will need to be
+ // rescheduled eventually
+ be->rescheduleMemInst(inst);
+
+ DPRINTF(OzoneLSQ, "Load-store forwarding mis-match. "
+ "Store [sn:%lli] to load addr %#x\n",
+ (*sq_it).inst->seqNum, req->getVaddr());
+
+ return NoFault;
+ }
+ sq_it++;
+ }
+
+ // If there's no forwarding case, then go access memory
+ DPRINTF(OzoneLSQ, "Doing functional access for inst PC %#x\n",
+ inst->readPC());
+
+ assert(!inst->memData);
+ inst->memData = new uint8_t[64];
+
+ ++usedPorts;
+
+ DPRINTF(OzoneLSQ, "Doing timing access for inst PC %#x\n",
+ inst->readPC());
+
+ PacketPtr data_pkt = new Packet(req, Packet::ReadReq, Packet::Broadcast);
+ data_pkt->dataStatic(inst->memData);
+
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = true;
+ state->idx = load_idx;
+ state->inst = inst;
+ data_pkt->senderState = state;
+
+ // if we have a cache, do cache access too
+ if (!dcachePort->sendTiming(data_pkt)) {
+ // There's an older load that's already going to squash.
+ if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
+ return NoFault;
+
+ // Record that the load was blocked due to memory. This
+ // load will squash all instructions after it, be
+ // refetched, and re-executed.
+ isLoadBlocked = true;
+ loadBlockedHandled = false;
+ blockedLoadSeqNum = inst->seqNum;
+ // No fault occurred, even though the interface is blocked.
+ return NoFault;
+ }
+
+ if (req->getFlags() & LOCKED) {
+ cpu->lockFlag = true;
+ }
+
+ if (data_pkt->result != Packet::Success) {
+ DPRINTF(OzoneLSQ, "OzoneLSQ: D-cache miss!\n");
+ DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
+ inst->seqNum);
+ } else {
+ DPRINTF(OzoneLSQ, "OzoneLSQ: D-cache hit!\n");
+ DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
+ inst->seqNum);
+ }
+
+ return NoFault;
+}
+
+template <class Impl>
+template <class T>
+Fault
+OzoneLWLSQ<Impl>::write(RequestPtr req, T &data, int store_idx)
+{
+ SQHashIt sq_hash_it = SQItHash.find(store_idx);
+ assert(sq_hash_it != SQItHash.end());
+
+ SQIt sq_it = (*sq_hash_it).second;
+ assert((*sq_it).inst);
+
+ DPRINTF(OzoneLSQ, "Doing write to store idx %i, addr %#x data %#x"
+ " | [sn:%lli]\n",
+ store_idx, req->getPaddr(), data, (*sq_it).inst->seqNum);
+
+ (*sq_it).req = req;
+ (*sq_it).size = sizeof(T);
+ (*sq_it).data = data;
+/*
+ assert(!req->data);
+ req->data = new uint8_t[64];
+ memcpy(req->data, (uint8_t *)&(*sq_it).data, req->size);
+*/
+
+ // This function only writes the data to the store queue, so no fault
+ // can happen here.
+ return NoFault;
+}
+
+#endif // __CPU_OZONE_LW_LSQ_HH__
diff --git a/src/cpu/ozone/lw_lsq_impl.hh b/src/cpu/ozone/lw_lsq_impl.hh
new file mode 100644
index 000000000..a65a2a4d3
--- /dev/null
+++ b/src/cpu/ozone/lw_lsq_impl.hh
@@ -0,0 +1,973 @@
+/*
+ * 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
+ */
+
+#include "config/use_checker.hh"
+
+#include "arch/isa_traits.hh"
+#include "base/str.hh"
+#include "cpu/ozone/lw_lsq.hh"
+#include "cpu/checker/cpu.hh"
+
+template<class Impl>
+OzoneLWLSQ<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,
+ OzoneLWLSQ *lsq_ptr)
+ : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr)
+{
+ this->setFlags(Event::AutoDelete);
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::WritebackEvent::process()
+{
+ if (!lsqPtr->isSwitchedOut()) {
+ lsqPtr->writeback(inst, pkt);
+ }
+ delete pkt;
+}
+
+template<class Impl>
+const char *
+OzoneLWLSQ<Impl>::WritebackEvent::description()
+{
+ return "Store writeback event";
+}
+
+template <class Impl>
+Tick
+OzoneLWLSQ<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
+{
+ panic("O3CPU model does not work with atomic mode!");
+ return curTick;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
+{
+ panic("O3CPU doesn't expect recvFunctional callback!");
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvStatusChange(Status status)
+{
+ if (status == RangeChange)
+ return;
+
+ panic("O3CPU doesn't expect recvStatusChange callback!");
+}
+
+template <class Impl>
+bool
+OzoneLWLSQ<Impl>::DcachePort::recvTiming(PacketPtr pkt)
+{
+ lsq->completeDataAccess(pkt);
+ return true;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::DcachePort::recvRetry()
+{
+ lsq->recvRetry();
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt)
+{
+ LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);
+ DynInstPtr inst = state->inst;
+ DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);
+ DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);
+
+ //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
+
+ if (isSwitchedOut() || inst->isSquashed()) {
+ delete state;
+ delete pkt;
+ return;
+ } else {
+ if (!state->noWB) {
+ writeback(inst, pkt);
+ }
+
+ if (inst->isStore()) {
+ completeStore(state->idx);
+ }
+ }
+
+ delete state;
+ delete pkt;
+}
+
+template <class Impl>
+OzoneLWLSQ<Impl>::OzoneLWLSQ()
+ : switchedOut(false), loads(0), stores(0), storesToWB(0), stalled(false),
+ isStoreBlocked(false), isLoadBlocked(false), loadBlockedHandled(false)
+{
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries,
+ unsigned maxSQEntries, unsigned id)
+{
+ DPRINTF(OzoneLSQ, "Creating OzoneLWLSQ%i object.\n",id);
+
+ lsqID = id;
+
+ LQEntries = maxLQEntries;
+ SQEntries = maxSQEntries;
+
+ for (int i = 0; i < LQEntries * 2; i++) {
+ LQIndices.push(i);
+ SQIndices.push(i);
+ }
+
+ mem = params->mem;
+
+ usedPorts = 0;
+ cachePorts = params->cachePorts;
+
+ loadFaultInst = storeFaultInst = memDepViolator = NULL;
+
+ blockedLoadSeqNum = 0;
+}
+
+template<class Impl>
+std::string
+OzoneLWLSQ<Impl>::name() const
+{
+ return "lsqunit";
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::setCPU(OzoneCPU *cpu_ptr)
+{
+ cpu = cpu_ptr;
+ dcachePort = new DcachePort(cpu, this);
+
+ Port *mem_dport = mem->getPort("");
+ dcachePort->setPeer(mem_dport);
+ mem_dport->setPeer(dcachePort);
+
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->setDcachePort(dcachePort);
+ }
+#endif
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::clearLQ()
+{
+ loadQueue.clear();
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::clearSQ()
+{
+ storeQueue.clear();
+}
+/*
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::setPageTable(PageTable *pt_ptr)
+{
+ DPRINTF(OzoneLSQ, "Setting the page table pointer.\n");
+ pTable = pt_ptr;
+}
+*/
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::resizeLQ(unsigned size)
+{
+ assert( size >= LQEntries);
+
+ if (size > LQEntries) {
+ while (size > loadQueue.size()) {
+ DynInstPtr dummy;
+ loadQueue.push_back(dummy);
+ LQEntries++;
+ }
+ } else {
+ LQEntries = size;
+ }
+
+}
+
+template<class Impl>
+void
+OzoneLWLSQ<Impl>::resizeSQ(unsigned size)
+{
+ if (size > SQEntries) {
+ while (size > storeQueue.size()) {
+ SQEntry dummy;
+ storeQueue.push_back(dummy);
+ SQEntries++;
+ }
+ } else {
+ SQEntries = size;
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::insert(DynInstPtr &inst)
+{
+ // Make sure we really have a memory reference.
+ assert(inst->isMemRef());
+
+ // Make sure it's one of the two classes of memory references.
+ assert(inst->isLoad() || inst->isStore());
+
+ if (inst->isLoad()) {
+ insertLoad(inst);
+ } else {
+ insertStore(inst);
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::insertLoad(DynInstPtr &load_inst)
+{
+ assert(loads < LQEntries * 2);
+ assert(!LQIndices.empty());
+ int load_index = LQIndices.front();
+ LQIndices.pop();
+
+ DPRINTF(OzoneLSQ, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
+ load_inst->readPC(), load_index, load_inst->seqNum);
+
+ load_inst->lqIdx = load_index;
+
+ loadQueue.push_front(load_inst);
+ LQItHash[load_index] = loadQueue.begin();
+
+ ++loads;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::insertStore(DynInstPtr &store_inst)
+{
+ // Make sure it is not full before inserting an instruction.
+ assert(stores - storesToWB < SQEntries);
+
+ assert(!SQIndices.empty());
+ int store_index = SQIndices.front();
+ SQIndices.pop();
+
+ DPRINTF(OzoneLSQ, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
+ store_inst->readPC(), store_index, store_inst->seqNum);
+
+ store_inst->sqIdx = store_index;
+ SQEntry entry(store_inst);
+ if (loadQueue.empty()) {
+ entry.lqIt = loadQueue.end();
+ } else {
+ entry.lqIt = loadQueue.begin();
+ }
+ storeQueue.push_front(entry);
+
+ SQItHash[store_index] = storeQueue.begin();
+
+ ++stores;
+}
+
+template <class Impl>
+typename Impl::DynInstPtr
+OzoneLWLSQ<Impl>::getMemDepViolator()
+{
+ DynInstPtr temp = memDepViolator;
+
+ memDepViolator = NULL;
+
+ return temp;
+}
+
+template <class Impl>
+unsigned
+OzoneLWLSQ<Impl>::numFreeEntries()
+{
+ unsigned free_lq_entries = LQEntries - loads;
+ unsigned free_sq_entries = SQEntries - stores;
+
+ // Both the LQ and SQ entries have an extra dummy entry to differentiate
+ // empty/full conditions. Subtract 1 from the free entries.
+ if (free_lq_entries < free_sq_entries) {
+ return free_lq_entries - 1;
+ } else {
+ return free_sq_entries - 1;
+ }
+}
+
+template <class Impl>
+int
+OzoneLWLSQ<Impl>::numLoadsReady()
+{
+ int retval = 0;
+ LQIt lq_it = loadQueue.begin();
+ LQIt end_it = loadQueue.end();
+
+ while (lq_it != end_it) {
+ if ((*lq_it)->readyToIssue()) {
+ ++retval;
+ }
+ }
+
+ return retval;
+}
+
+template <class Impl>
+Fault
+OzoneLWLSQ<Impl>::executeLoad(DynInstPtr &inst)
+{
+ // Execute a specific load.
+ Fault load_fault = NoFault;
+
+ DPRINTF(OzoneLSQ, "Executing load PC %#x, [sn:%lli]\n",
+ inst->readPC(),inst->seqNum);
+
+ // Make sure it's really in the list.
+ // Normally it should always be in the list. However,
+ /* due to a syscall it may not be the list.
+#ifdef DEBUG
+ int i = loadHead;
+ while (1) {
+ if (i == loadTail && !find(inst)) {
+ assert(0 && "Load not in the queue!");
+ } else if (loadQueue[i] == inst) {
+ break;
+ }
+
+ i = i + 1;
+ if (i >= LQEntries) {
+ i = 0;
+ }
+ }
+#endif // DEBUG*/
+
+ load_fault = inst->initiateAcc();
+
+ // Might want to make sure that I'm not overwriting a previously faulting
+ // instruction that hasn't been checked yet.
+ // Actually probably want the oldest faulting load
+ if (load_fault != NoFault) {
+ DPRINTF(OzoneLSQ, "Load [sn:%lli] has a fault\n", inst->seqNum);
+ // Maybe just set it as can commit here, although that might cause
+ // some other problems with sending traps to the ROB too quickly.
+ be->instToCommit(inst);
+// iewStage->activityThisCycle();
+ }
+
+ return load_fault;
+}
+
+template <class Impl>
+Fault
+OzoneLWLSQ<Impl>::executeStore(DynInstPtr &store_inst)
+{
+ // Make sure that a store exists.
+ assert(stores != 0);
+
+ int store_idx = store_inst->sqIdx;
+ SQHashIt sq_hash_it = SQItHash.find(store_idx);
+ assert(sq_hash_it != SQItHash.end());
+ DPRINTF(OzoneLSQ, "Executing store PC %#x [sn:%lli]\n",
+ store_inst->readPC(), store_inst->seqNum);
+
+ SQIt sq_it = (*sq_hash_it).second;
+
+ Fault store_fault = store_inst->initiateAcc();
+
+ // Store size should now be available. Use it to get proper offset for
+ // addr comparisons.
+ int size = (*sq_it).size;
+
+ if (size == 0) {
+ DPRINTF(OzoneLSQ,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
+ store_inst->readPC(),store_inst->seqNum);
+
+ return store_fault;
+ }
+
+ assert(store_fault == NoFault);
+
+ if (!storeFaultInst) {
+ if (store_fault != NoFault) {
+ panic("Fault in a store instruction!");
+ storeFaultInst = store_inst;
+ } else if (store_inst->isStoreConditional()) {
+ // Store conditionals need to set themselves as able to
+ // writeback if we haven't had a fault by here.
+ (*sq_it).canWB = true;
+
+ ++storesToWB;
+ DPRINTF(OzoneLSQ, "Nonspeculative store! storesToWB:%i\n",
+ storesToWB);
+ }
+ }
+
+ LQIt lq_it = --(loadQueue.end());
+
+ if (!memDepViolator) {
+ while (lq_it != loadQueue.end()) {
+ if ((*lq_it)->seqNum < store_inst->seqNum) {
+ lq_it--;
+ continue;
+ }
+ // Actually should only check loads that have actually executed
+ // Might be safe because effAddr is set to InvalAddr when the
+ // dyn inst is created.
+
+ // Must actually check all addrs in the proper size range
+ // Which is more correct than needs to be. What if for now we just
+ // assume all loads are quad-word loads, and do the addr based
+ // on that.
+ // @todo: Fix this, magic number being used here
+ if (((*lq_it)->effAddr >> 8) ==
+ (store_inst->effAddr >> 8)) {
+ // A load incorrectly passed this store. Squash and refetch.
+ // For now return a fault to show that it was unsuccessful.
+ memDepViolator = (*lq_it);
+
+ return TheISA::genMachineCheckFault();
+ }
+
+ lq_it--;
+ }
+
+ // If we've reached this point, there was no violation.
+ memDepViolator = NULL;
+ }
+
+ return store_fault;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::commitLoad()
+{
+ assert(!loadQueue.empty());
+
+ DPRINTF(OzoneLSQ, "[sn:%lli] Committing head load instruction, PC %#x\n",
+ loadQueue.back()->seqNum, loadQueue.back()->readPC());
+
+ LQIndices.push(loadQueue.back()->lqIdx);
+ LQItHash.erase(loadQueue.back()->lqIdx);
+
+ loadQueue.pop_back();
+
+ --loads;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::commitLoads(InstSeqNum &youngest_inst)
+{
+ assert(loads == 0 || !loadQueue.empty());
+
+ while (loads != 0 &&
+ loadQueue.back()->seqNum <= youngest_inst) {
+ commitLoad();
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::commitStores(InstSeqNum &youngest_inst)
+{
+ assert(stores == 0 || !storeQueue.empty());
+
+ SQIt sq_it = --(storeQueue.end());
+ while (!storeQueue.empty() && sq_it != storeQueue.end()) {
+ assert((*sq_it).inst);
+ if (!(*sq_it).canWB) {
+ if ((*sq_it).inst->seqNum > youngest_inst) {
+ break;
+ }
+ ++storesToWB;
+
+ DPRINTF(OzoneLSQ, "Marking store as able to write back, PC "
+ "%#x [sn:%lli], storesToWB:%i\n",
+ (*sq_it).inst->readPC(),
+ (*sq_it).inst->seqNum,
+ storesToWB);
+
+ (*sq_it).canWB = true;
+ }
+
+ sq_it--;
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::writebackStores()
+{
+ SQIt sq_it = --(storeQueue.end());
+ while (storesToWB > 0 &&
+ sq_it != storeQueue.end() &&
+ (*sq_it).inst &&
+ (*sq_it).canWB &&
+ usedPorts < cachePorts) {
+
+ if (isStoreBlocked) {
+ DPRINTF(OzoneLSQ, "Unable to write back any more stores, cache"
+ " is blocked!\n");
+ break;
+ }
+
+ DynInstPtr inst = (*sq_it).inst;
+
+ if ((*sq_it).size == 0 && !(*sq_it).completed) {
+ sq_it--;
+ completeStore(inst->sqIdx);
+
+ continue;
+ }
+
+ if (inst->isDataPrefetch() || (*sq_it).committed) {
+ sq_it--;
+ continue;
+ }
+
+ ++usedPorts;
+
+ assert((*sq_it).req);
+ assert(!(*sq_it).committed);
+
+ Request *req = (*sq_it).req;
+ (*sq_it).committed = true;
+
+ assert(!inst->memData);
+ inst->memData = new uint8_t[64];
+ memcpy(inst->memData, (uint8_t *)&(*sq_it).data,
+ req->getSize());
+
+ PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
+ data_pkt->dataStatic(inst->memData);
+
+ LSQSenderState *state = new LSQSenderState;
+ state->isLoad = false;
+ state->idx = inst->sqIdx;
+ state->inst = inst;
+ data_pkt->senderState = state;
+
+ DPRINTF(OzoneLSQ, "D-Cache: Writing back store PC:%#x "
+ "to Addr:%#x, data:%#x [sn:%lli]\n",
+ (*sq_it).inst->readPC(),
+ req->getPaddr(), *(inst->memData),
+ inst->seqNum);
+
+ // @todo: Remove this SC hack once the memory system handles it.
+ if (req->getFlags() & LOCKED) {
+ if (req->getFlags() & UNCACHEABLE) {
+ req->setScResult(2);
+ } else {
+ if (cpu->lockFlag) {
+ req->setScResult(1);
+ } else {
+ req->setScResult(0);
+ // Hack: Instantly complete this store.
+ completeDataAccess(data_pkt);
+ --sq_it;
+ continue;
+ }
+ }
+ } else {
+ // Non-store conditionals do not need a writeback.
+ state->noWB = true;
+ }
+
+ if (!dcachePort->sendTiming(data_pkt)) {
+ // Need to handle becoming blocked on a store.
+ isStoreBlocked = true;
+ assert(retryPkt == NULL);
+ retryPkt = data_pkt;
+ } else {
+ storePostSend(data_pkt, inst);
+ --sq_it;
+ }
+/*
+ DPRINTF(OzoneLSQ, "D-Cache: Writing back store idx:%i PC:%#x "
+ "to Addr:%#x, data:%#x [sn:%lli]\n",
+ inst->sqIdx,inst->readPC(),
+ req->paddr, *(req->data),
+ inst->seqNum);
+
+ if (dcacheInterface) {
+ assert(!req->completionEvent);
+ StoreCompletionEvent *store_event = new
+ StoreCompletionEvent(inst, be, NULL, this);
+ req->completionEvent = store_event;
+
+ MemAccessResult result = dcacheInterface->access(req);
+
+ if (isStalled() &&
+ inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load [sn:%lli]\n",
+ stallingStoreIsn, (*stallingLoad)->seqNum);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst((*stallingLoad));
+ }
+
+ if (result != MA_HIT && dcacheInterface->doEvents()) {
+ store_event->miss = true;
+ typename BackEnd::LdWritebackEvent *wb = NULL;
+ if (req->flags & LOCKED) {
+ wb = new typename BackEnd::LdWritebackEvent(inst,
+ be);
+ store_event->wbEvent = wb;
+ }
+
+ DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n");
+
+// DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
+// inst->seqNum);
+
+ be->addDcacheMiss(inst);
+
+ lastDcacheStall = curTick;
+
+ _status = DcacheMissStall;
+
+ // Increment stat here or something
+
+ sq_it--;
+ } else {
+ DPRINTF(OzoneLSQ,"D-Cache: Write Hit on idx:%i !\n",
+ inst->sqIdx);
+
+// DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
+// inst->seqNum);
+
+ if (req->flags & LOCKED) {
+ // Stx_C does not generate a system port
+ // transaction in the 21264, but that might be
+ // hard to accomplish in this model.
+
+ typename BackEnd::LdWritebackEvent *wb =
+ new typename BackEnd::LdWritebackEvent(inst,
+ be);
+ store_event->wbEvent = wb;
+ }
+ sq_it--;
+ }
+ } else {
+ panic("Must HAVE DCACHE!!!!!\n");
+ }
+*/
+ }
+
+ // Not sure this should set it to 0.
+ usedPorts = 0;
+
+ assert(stores >= 0 && storesToWB >= 0);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::squash(const InstSeqNum &squashed_num)
+{
+ DPRINTF(OzoneLSQ, "Squashing until [sn:%lli]!"
+ "(Loads:%i Stores:%i)\n",squashed_num,loads,stores);
+
+
+ LQIt lq_it = loadQueue.begin();
+
+ while (loads != 0 && (*lq_it)->seqNum > squashed_num) {
+ assert(!loadQueue.empty());
+ // Clear the smart pointer to make sure it is decremented.
+ DPRINTF(OzoneLSQ,"Load Instruction PC %#x squashed, "
+ "[sn:%lli]\n",
+ (*lq_it)->readPC(),
+ (*lq_it)->seqNum);
+
+ if (isStalled() && lq_it == stallingLoad) {
+ stalled = false;
+ stallingStoreIsn = 0;
+ stallingLoad = NULL;
+ }
+
+ --loads;
+
+ // Inefficient!
+ LQHashIt lq_hash_it = LQItHash.find((*lq_it)->lqIdx);
+ assert(lq_hash_it != LQItHash.end());
+ LQItHash.erase(lq_hash_it);
+ LQIndices.push((*lq_it)->lqIdx);
+ loadQueue.erase(lq_it++);
+ }
+
+ if (isLoadBlocked) {
+ if (squashed_num < blockedLoadSeqNum) {
+ isLoadBlocked = false;
+ loadBlockedHandled = false;
+ blockedLoadSeqNum = 0;
+ }
+ }
+
+ SQIt sq_it = storeQueue.begin();
+
+ while (stores != 0 && (*sq_it).inst->seqNum > squashed_num) {
+ assert(!storeQueue.empty());
+
+ if ((*sq_it).canWB) {
+ break;
+ }
+
+ // Clear the smart pointer to make sure it is decremented.
+ DPRINTF(OzoneLSQ,"Store Instruction PC %#x idx:%i squashed [sn:%lli]\n",
+ (*sq_it).inst->readPC(), (*sq_it).inst->sqIdx,
+ (*sq_it).inst->seqNum);
+
+ // I don't think this can happen. It should have been cleared by the
+ // stalling load.
+ if (isStalled() &&
+ (*sq_it).inst->seqNum == stallingStoreIsn) {
+ panic("Is stalled should have been cleared by stalling load!\n");
+ stalled = false;
+ stallingStoreIsn = 0;
+ }
+
+ SQHashIt sq_hash_it = SQItHash.find((*sq_it).inst->sqIdx);
+ assert(sq_hash_it != SQItHash.end());
+ SQItHash.erase(sq_hash_it);
+ SQIndices.push((*sq_it).inst->sqIdx);
+ (*sq_it).inst = NULL;
+ (*sq_it).canWB = 0;
+ (*sq_it).req = NULL;
+ --stores;
+ storeQueue.erase(sq_it++);
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::dumpInsts()
+{
+ cprintf("Load store queue: Dumping instructions.\n");
+ cprintf("Load queue size: %i\n", loads);
+ cprintf("Load queue: ");
+
+ LQIt lq_it = --(loadQueue.end());
+
+ while (lq_it != loadQueue.end() && (*lq_it)) {
+ cprintf("[sn:%lli] %#x ", (*lq_it)->seqNum,
+ (*lq_it)->readPC());
+
+ lq_it--;
+ }
+
+ cprintf("\nStore queue size: %i\n", stores);
+ cprintf("Store queue: ");
+
+ SQIt sq_it = --(storeQueue.end());
+
+ while (sq_it != storeQueue.end() && (*sq_it).inst) {
+ cprintf("[sn:%lli]\nPC:%#x\nSize:%i\nCommitted:%i\nCompleted:%i\ncanWB:%i\n",
+ (*sq_it).inst->seqNum,
+ (*sq_it).inst->readPC(),
+ (*sq_it).size,
+ (*sq_it).committed,
+ (*sq_it).completed,
+ (*sq_it).canWB);
+
+ sq_it--;
+ }
+
+ cprintf("\n");
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::storePostSend(Packet *pkt, DynInstPtr &inst)
+{
+ if (isStalled() &&
+ inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load [sn:%lli]\n",
+ stallingStoreIsn, (*stallingLoad)->seqNum);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst((*stallingLoad));
+ }
+
+ if (!inst->isStoreConditional()) {
+ // The store is basically completed at this time. This
+ // only works so long as the checker doesn't try to
+ // verify the value in memory for stores.
+ inst->setCompleted();
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->verify(inst);
+ }
+#endif
+ }
+
+ if (pkt->result != Packet::Success) {
+ DPRINTF(OzoneLSQ,"D-Cache Write Miss!\n");
+
+ DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
+ inst->seqNum);
+
+ //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
+
+ //DPRINTF(OzoneLWLSQ, "Added MSHR. count = %i\n",mshrSeqNums.size());
+
+ // @todo: Increment stat here.
+ } else {
+ DPRINTF(OzoneLSQ,"D-Cache: Write Hit!\n");
+
+ DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
+ inst->seqNum);
+ }
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt)
+{
+ // Squashed instructions do not need to complete their access.
+ if (inst->isSquashed()) {
+ assert(!inst->isStore());
+ return;
+ }
+
+ if (!inst->isExecuted()) {
+ inst->setExecuted();
+
+ // Complete access to copy data to proper place.
+ inst->completeAcc(pkt);
+ }
+
+ // Need to insert instruction into queue to commit
+ be->instToCommit(inst);
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::completeStore(int store_idx)
+{
+ SQHashIt sq_hash_it = SQItHash.find(store_idx);
+ assert(sq_hash_it != SQItHash.end());
+ SQIt sq_it = (*sq_hash_it).second;
+
+ assert((*sq_it).inst);
+ (*sq_it).completed = true;
+ DynInstPtr inst = (*sq_it).inst;
+
+ --storesToWB;
+
+ if (isStalled() &&
+ inst->seqNum == stallingStoreIsn) {
+ DPRINTF(OzoneLSQ, "Unstalling, stalling store [sn:%lli] "
+ "load [sn:%lli]\n",
+ stallingStoreIsn, (*stallingLoad)->seqNum);
+ stalled = false;
+ stallingStoreIsn = 0;
+ be->replayMemInst((*stallingLoad));
+ }
+
+ DPRINTF(OzoneLSQ, "Completing store idx:%i [sn:%lli], storesToWB:%i\n",
+ inst->sqIdx, inst->seqNum, storesToWB);
+
+ assert(!storeQueue.empty());
+ SQItHash.erase(sq_hash_it);
+ SQIndices.push(inst->sqIdx);
+ storeQueue.erase(sq_it);
+ --stores;
+
+ inst->setCompleted();
+#if USE_CHECKER
+ if (cpu->checker) {
+ cpu->checker->verify(inst);
+ }
+#endif
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::recvRetry()
+{
+ panic("Unimplemented!");
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::switchOut()
+{
+ assert(storesToWB == 0);
+ switchedOut = true;
+
+ // Clear the queue to free up resources
+ storeQueue.clear();
+ loadQueue.clear();
+ loads = stores = storesToWB = 0;
+}
+
+template <class Impl>
+void
+OzoneLWLSQ<Impl>::takeOverFrom(ThreadContext *old_tc)
+{
+ // Clear out any old state. May be redundant if this is the first time
+ // the CPU is being used.
+ stalled = false;
+ isLoadBlocked = false;
+ loadBlockedHandled = false;
+ switchedOut = false;
+
+ // Could do simple checks here to see if indices are on twice
+ while (!LQIndices.empty())
+ LQIndices.pop();
+ while (!SQIndices.empty())
+ SQIndices.pop();
+
+ for (int i = 0; i < LQEntries * 2; i++) {
+ LQIndices.push(i);
+ SQIndices.push(i);
+ }
+
+ usedPorts = 0;
+
+ loadFaultInst = storeFaultInst = memDepViolator = NULL;
+
+ blockedLoadSeqNum = 0;
+}
diff --git a/src/cpu/ozone/null_predictor.hh b/src/cpu/ozone/null_predictor.hh
new file mode 100644
index 000000000..a98c89d69
--- /dev/null
+++ b/src/cpu/ozone/null_predictor.hh
@@ -0,0 +1,105 @@
+/*
+ * 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_OZONE_NULL_PREDICTOR_HH__
+#define __CPU_OZONE_NULL_PREDICTOR_HH__
+
+#include "arch/isa_traits.hh"
+#include "cpu/inst_seq.hh"
+
+template <class Impl>
+class NullPredictor
+{
+ public:
+ typedef typename Impl::Params Params;
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ NullPredictor(Params *p) { }
+
+ struct BPredInfo {
+ BPredInfo()
+ : PC(0), nextPC(0)
+ { }
+
+ BPredInfo(const Addr &pc, const Addr &next_pc)
+ : PC(pc), nextPC(next_pc)
+ { }
+
+ Addr PC;
+ Addr nextPC;
+ };
+
+ BPredInfo lookup(Addr &PC) { return BPredInfo(PC, PC+4); }
+
+ void undo(BPredInfo &bp_info) { return; }
+
+ /**
+ * 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(DynInstPtr &inst, Addr &PC, unsigned tid)
+ { return false; }
+
+ /**
+ * 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)
+ { }
+
+};
+
+#endif // __CPU_OZONE_NULL_PREDICTOR_HH__
diff --git a/src/cpu/ozone/ozone_base_dyn_inst.cc b/src/cpu/ozone/ozone_base_dyn_inst.cc
new file mode 100644
index 000000000..5a3a69dff
--- /dev/null
+++ b/src/cpu/ozone/ozone_base_dyn_inst.cc
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cpu/base_dyn_inst_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+
+// Explicit instantiation
+template class BaseDynInst<OzoneImpl>;
+
+template <>
+int
+BaseDynInst<OzoneImpl>::instcount = 0;
diff --git a/src/cpu/ozone/ozone_impl.hh b/src/cpu/ozone/ozone_impl.hh
new file mode 100644
index 000000000..503675738
--- /dev/null
+++ b/src/cpu/ozone/ozone_impl.hh
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Kevin Lim
+ */
+
+#ifndef __CPU_OZONE_OZONE_IMPL_HH__
+#define __CPU_OZONE_OZONE_IMPL_HH__
+
+#include "arch/alpha/isa_traits.hh"
+#include "cpu/o3/bpred_unit.hh"
+#include "cpu/ozone/front_end.hh"
+#include "cpu/ozone/inst_queue.hh"
+#include "cpu/ozone/lw_lsq.hh"
+#include "cpu/ozone/lw_back_end.hh"
+#include "cpu/ozone/null_predictor.hh"
+#include "cpu/ozone/dyn_inst.hh"
+#include "cpu/ozone/simple_params.hh"
+
+template <class Impl>
+class OzoneCPU;
+
+template <class Impl>
+class OzoneDynInst;
+
+struct OzoneImpl {
+ typedef SimpleParams Params;
+ typedef OzoneCPU<OzoneImpl> OzoneCPU;
+ typedef OzoneCPU CPUType;
+
+ // Would like to put these into their own area.
+// typedef NullPredictor BranchPred;
+ typedef BPredUnit<OzoneImpl> BranchPred;
+ typedef FrontEnd<OzoneImpl> FrontEnd;
+ // Will need IQ, LSQ eventually
+ typedef LWBackEnd<OzoneImpl> BackEnd;
+
+ typedef InstQueue<OzoneImpl> InstQueue;
+ typedef OzoneLWLSQ<OzoneImpl> LdstQueue;
+
+ typedef OzoneDynInst<OzoneImpl> DynInst;
+ typedef RefCountingPtr<DynInst> DynInstPtr;
+
+ typedef uint64_t IssueStruct;
+
+ enum {
+ MaxThreads = 1
+ };
+};
+
+#endif // __CPU_OZONE_OZONE_IMPL_HH__
diff --git a/src/cpu/ozone/rename_table.cc b/src/cpu/ozone/rename_table.cc
new file mode 100644
index 000000000..a44054b6e
--- /dev/null
+++ b/src/cpu/ozone/rename_table.cc
@@ -0,0 +1,36 @@
+/*
+ * 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
+ */
+
+#include "cpu/ozone/rename_table_impl.hh"
+#include "cpu/ozone/ozone_impl.hh"
+//#include "cpu/ozone/simple_impl.hh"
+
+template class RenameTable<OzoneImpl>;
+//template class RenameTable<SimpleImpl>;
diff --git a/src/cpu/ozone/rename_table.hh b/src/cpu/ozone/rename_table.hh
new file mode 100644
index 000000000..0b67d9635
--- /dev/null
+++ b/src/cpu/ozone/rename_table.hh
@@ -0,0 +1,55 @@
+/*
+ * 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_OZONE_RENAME_TABLE_HH__
+#define __CPU_OZONE_RENAME_TABLE_HH__
+
+#include "arch/isa_traits.hh"
+
+/** Rename table that holds the rename of each architectural register to
+ * producing DynInst. Needs to support copying from one table to another.
+ */
+
+template <class Impl>
+class RenameTable {
+ public:
+ typedef typename Impl::DynInstPtr DynInstPtr;
+
+ RenameTable();
+
+ void copyFrom(const RenameTable<Impl> &table_to_copy);
+
+ DynInstPtr &operator [] (int index)
+ { return table[index]; }
+
+ DynInstPtr table[TheISA::TotalNumRegs];
+};
+
+#endif // __CPU_OZONE_RENAME_TABLE_HH__
diff --git a/src/cpu/ozone/rename_table_impl.hh b/src/cpu/ozone/rename_table_impl.hh
new file mode 100644
index 000000000..67bab7337
--- /dev/null
+++ b/src/cpu/ozone/rename_table_impl.hh
@@ -0,0 +1,52 @@
+/*
+ * 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
+ */
+
+#include <cstdlib> // Not really sure what to include to get NULL
+#include "cpu/ozone/rename_table.hh"
+
+template <class Impl>
+RenameTable<Impl>::RenameTable()
+{
+ // Actually should set these to dummy dyn insts that have the initial value
+ // and force their values to be initialized. This keeps everything the
+ // same.
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ table[i] = NULL;
+ }
+}
+
+template <class Impl>
+void
+RenameTable<Impl>::copyFrom(const RenameTable<Impl> &table_to_copy)
+{
+ for (int i = 0; i < TheISA::TotalNumRegs; ++i) {
+ table[i] = table_to_copy.table[i];
+ }
+}
diff --git a/src/cpu/ozone/simple_base_dyn_inst.cc b/src/cpu/ozone/simple_base_dyn_inst.cc
new file mode 100644
index 000000000..fdaeaf57e
--- /dev/null
+++ b/src/cpu/ozone/simple_base_dyn_inst.cc
@@ -0,0 +1,39 @@
+/*
+ * 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
+ */
+
+#include "cpu/base_dyn_inst_impl.hh"
+#include "cpu/ozone/simple_impl.hh"
+
+// Explicit instantiation
+template class BaseDynInst<SimpleImpl>;
+
+template <>
+int
+BaseDynInst<SimpleImpl>::instcount = 0;
diff --git a/src/cpu/ozone/simple_cpu_builder.cc b/src/cpu/ozone/simple_cpu_builder.cc
new file mode 100644
index 000000000..baaf7c708
--- /dev/null
+++ b/src/cpu/ozone/simple_cpu_builder.cc
@@ -0,0 +1,452 @@
+/*
+ * 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
+ */
+
+#include <string>
+
+#include "cpu/checker/cpu.hh"
+#include "cpu/inst_seq.hh"
+#include "cpu/ozone/cpu_impl.hh"
+#include "cpu/ozone/simple_impl.hh"
+#include "cpu/ozone/simple_params.hh"
+#include "mem/cache/base_cache.hh"
+#include "sim/builder.hh"
+#include "sim/process.hh"
+#include "sim/sim_object.hh"
+
+template
+class OzoneCPU<SimpleImpl>;
+
+class SimpleOzoneCPU : public OzoneCPU<SimpleImpl>
+{
+ public:
+ SimpleOzoneCPU(SimpleParams *p)
+ : OzoneCPU<SimpleImpl>(p)
+ { }
+};
+
+////////////////////////////////////////////////////////////////////////
+//
+// OzoneCPU Simulation Object
+//
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU)
+
+ Param<int> clock;
+ Param<int> numThreads;
+
+#if FULL_SYSTEM
+SimObjectParam<System *> system;
+Param<int> cpu_id;
+SimObjectParam<AlphaITB *> itb;
+SimObjectParam<AlphaDTB *> dtb;
+#else
+SimObjectVectorParam<Process *> workload;
+//SimObjectParam<PageTable *> page_table;
+#endif // FULL_SYSTEM
+
+SimObjectParam<FunctionalMemory *> mem;
+
+SimObjectParam<BaseCPU *> checker;
+
+Param<Counter> max_insts_any_thread;
+Param<Counter> max_insts_all_threads;
+Param<Counter> max_loads_any_thread;
+Param<Counter> max_loads_all_threads;
+
+SimObjectParam<BaseCache *> icache;
+SimObjectParam<BaseCache *> dcache;
+
+Param<unsigned> cachePorts;
+Param<unsigned> width;
+Param<unsigned> frontEndWidth;
+Param<unsigned> backEndWidth;
+Param<unsigned> backEndSquashLatency;
+Param<unsigned> backEndLatency;
+Param<unsigned> maxInstBufferSize;
+Param<unsigned> numPhysicalRegs;
+
+Param<unsigned> decodeToFetchDelay;
+Param<unsigned> renameToFetchDelay;
+Param<unsigned> iewToFetchDelay;
+Param<unsigned> commitToFetchDelay;
+Param<unsigned> fetchWidth;
+
+Param<unsigned> renameToDecodeDelay;
+Param<unsigned> iewToDecodeDelay;
+Param<unsigned> commitToDecodeDelay;
+Param<unsigned> fetchToDecodeDelay;
+Param<unsigned> decodeWidth;
+
+Param<unsigned> iewToRenameDelay;
+Param<unsigned> commitToRenameDelay;
+Param<unsigned> decodeToRenameDelay;
+Param<unsigned> renameWidth;
+
+Param<unsigned> commitToIEWDelay;
+Param<unsigned> renameToIEWDelay;
+Param<unsigned> issueToExecuteDelay;
+Param<unsigned> issueWidth;
+Param<unsigned> executeWidth;
+Param<unsigned> executeIntWidth;
+Param<unsigned> executeFloatWidth;
+Param<unsigned> executeBranchWidth;
+Param<unsigned> executeMemoryWidth;
+
+Param<unsigned> iewToCommitDelay;
+Param<unsigned> renameToROBDelay;
+Param<unsigned> commitWidth;
+Param<unsigned> squashWidth;
+
+Param<std::string> predType;
+Param<unsigned> localPredictorSize;
+Param<unsigned> localCtrBits;
+Param<unsigned> localHistoryTableSize;
+Param<unsigned> localHistoryBits;
+Param<unsigned> globalPredictorSize;
+Param<unsigned> globalCtrBits;
+Param<unsigned> globalHistoryBits;
+Param<unsigned> choicePredictorSize;
+Param<unsigned> choiceCtrBits;
+
+Param<unsigned> BTBEntries;
+Param<unsigned> BTBTagSize;
+
+Param<unsigned> RASSize;
+
+Param<unsigned> LQEntries;
+Param<unsigned> SQEntries;
+Param<unsigned> LFSTSize;
+Param<unsigned> SSITSize;
+
+Param<unsigned> numPhysIntRegs;
+Param<unsigned> numPhysFloatRegs;
+Param<unsigned> numIQEntries;
+Param<unsigned> numROBEntries;
+
+Param<bool> decoupledFrontEnd;
+Param<int> dispatchWidth;
+Param<int> wbWidth;
+
+Param<unsigned> smtNumFetchingThreads;
+Param<std::string> smtFetchPolicy;
+Param<std::string> smtLSQPolicy;
+Param<unsigned> smtLSQThreshold;
+Param<std::string> smtIQPolicy;
+Param<unsigned> smtIQThreshold;
+Param<std::string> smtROBPolicy;
+Param<unsigned> smtROBThreshold;
+Param<std::string> smtCommitPolicy;
+
+Param<unsigned> instShiftAmt;
+
+Param<bool> defer_registration;
+
+Param<bool> function_trace;
+Param<Tick> function_trace_start;
+
+END_DECLARE_SIM_OBJECT_PARAMS(SimpleOzoneCPU)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU)
+
+ INIT_PARAM(clock, "clock speed"),
+ INIT_PARAM(numThreads, "number of HW thread contexts"),
+
+#if FULL_SYSTEM
+ INIT_PARAM(system, "System object"),
+ INIT_PARAM(cpu_id, "processor ID"),
+ INIT_PARAM(itb, "Instruction translation buffer"),
+ INIT_PARAM(dtb, "Data translation buffer"),
+#else
+ INIT_PARAM(workload, "Processes to run"),
+// INIT_PARAM(page_table, "Page table"),
+#endif // FULL_SYSTEM
+
+ INIT_PARAM_DFLT(mem, "Memory", NULL),
+
+ INIT_PARAM_DFLT(checker, "Checker CPU", NULL),
+
+ INIT_PARAM_DFLT(max_insts_any_thread,
+ "Terminate when any thread reaches this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_insts_all_threads,
+ "Terminate when all threads have reached"
+ "this inst count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_any_thread,
+ "Terminate when any thread reaches this load count",
+ 0),
+ INIT_PARAM_DFLT(max_loads_all_threads,
+ "Terminate when all threads have reached this load"
+ "count",
+ 0),
+
+ INIT_PARAM_DFLT(icache, "L1 instruction cache", NULL),
+ INIT_PARAM_DFLT(dcache, "L1 data cache", NULL),
+
+ INIT_PARAM_DFLT(cachePorts, "Cache Ports", 200),
+ INIT_PARAM_DFLT(width, "Width", 1),
+ INIT_PARAM_DFLT(frontEndWidth, "Front end width", 1),
+ INIT_PARAM_DFLT(backEndWidth, "Back end width", 1),
+ INIT_PARAM_DFLT(backEndSquashLatency, "Back end squash latency", 1),
+ INIT_PARAM_DFLT(backEndLatency, "Back end latency", 1),
+ INIT_PARAM_DFLT(maxInstBufferSize, "Maximum instruction buffer size", 16),
+ INIT_PARAM(numPhysicalRegs, "Number of physical registers"),
+
+ INIT_PARAM(decodeToFetchDelay, "Decode to fetch delay"),
+ INIT_PARAM(renameToFetchDelay, "Rename to fetch delay"),
+ INIT_PARAM(iewToFetchDelay, "Issue/Execute/Writeback to fetch"
+ "delay"),
+ INIT_PARAM(commitToFetchDelay, "Commit to fetch delay"),
+ INIT_PARAM(fetchWidth, "Fetch width"),
+ INIT_PARAM(renameToDecodeDelay, "Rename to decode delay"),
+ INIT_PARAM(iewToDecodeDelay, "Issue/Execute/Writeback to decode"
+ "delay"),
+ INIT_PARAM(commitToDecodeDelay, "Commit to decode delay"),
+ INIT_PARAM(fetchToDecodeDelay, "Fetch to decode delay"),
+ INIT_PARAM(decodeWidth, "Decode width"),
+
+ INIT_PARAM(iewToRenameDelay, "Issue/Execute/Writeback to rename"
+ "delay"),
+ INIT_PARAM(commitToRenameDelay, "Commit to rename delay"),
+ INIT_PARAM(decodeToRenameDelay, "Decode to rename delay"),
+ INIT_PARAM(renameWidth, "Rename width"),
+
+ INIT_PARAM(commitToIEWDelay, "Commit to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(renameToIEWDelay, "Rename to "
+ "Issue/Execute/Writeback delay"),
+ INIT_PARAM(issueToExecuteDelay, "Issue to execute delay (internal"
+ "to the IEW stage)"),
+ INIT_PARAM(issueWidth, "Issue width"),
+ INIT_PARAM(executeWidth, "Execute width"),
+ INIT_PARAM(executeIntWidth, "Integer execute width"),
+ INIT_PARAM(executeFloatWidth, "Floating point execute width"),
+ INIT_PARAM(executeBranchWidth, "Branch execute width"),
+ INIT_PARAM(executeMemoryWidth, "Memory execute width"),
+
+ INIT_PARAM(iewToCommitDelay, "Issue/Execute/Writeback to commit "
+ "delay"),
+ INIT_PARAM(renameToROBDelay, "Rename to reorder buffer delay"),
+ INIT_PARAM(commitWidth, "Commit width"),
+ INIT_PARAM(squashWidth, "Squash width"),
+
+ INIT_PARAM(predType, "Type of branch predictor ('local', 'tournament')"),
+ INIT_PARAM(localPredictorSize, "Size of local predictor"),
+ INIT_PARAM(localCtrBits, "Bits per counter"),
+ INIT_PARAM(localHistoryTableSize, "Size of local history table"),
+ INIT_PARAM(localHistoryBits, "Bits for the local history"),
+ INIT_PARAM(globalPredictorSize, "Size of global predictor"),
+ INIT_PARAM(globalCtrBits, "Bits per counter"),
+ INIT_PARAM(globalHistoryBits, "Bits of history"),
+ INIT_PARAM(choicePredictorSize, "Size of choice predictor"),
+ INIT_PARAM(choiceCtrBits, "Bits of choice counters"),
+
+ INIT_PARAM(BTBEntries, "Number of BTB entries"),
+ INIT_PARAM(BTBTagSize, "Size of the BTB tags, in bits"),
+
+ INIT_PARAM(RASSize, "RAS size"),
+
+ INIT_PARAM(LQEntries, "Number of load queue entries"),
+ INIT_PARAM(SQEntries, "Number of store queue entries"),
+ INIT_PARAM(LFSTSize, "Last fetched store table size"),
+ INIT_PARAM(SSITSize, "Store set ID table size"),
+
+ INIT_PARAM(numPhysIntRegs, "Number of physical integer registers"),
+ INIT_PARAM(numPhysFloatRegs, "Number of physical floating point "
+ "registers"),
+ INIT_PARAM(numIQEntries, "Number of instruction queue entries"),
+ INIT_PARAM(numROBEntries, "Number of reorder buffer entries"),
+
+ INIT_PARAM_DFLT(decoupledFrontEnd, "Decoupled front end", true),
+ INIT_PARAM_DFLT(dispatchWidth, "Dispatch width", 0),
+ INIT_PARAM_DFLT(wbWidth, "Writeback width", 0),
+
+ INIT_PARAM_DFLT(smtNumFetchingThreads, "SMT Number of Fetching Threads", 1),
+ INIT_PARAM_DFLT(smtFetchPolicy, "SMT Fetch Policy", "SingleThread"),
+ INIT_PARAM_DFLT(smtLSQPolicy, "SMT LSQ Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtLSQThreshold,"SMT LSQ Threshold", 100),
+ INIT_PARAM_DFLT(smtIQPolicy, "SMT IQ Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtIQThreshold, "SMT IQ Threshold", 100),
+ INIT_PARAM_DFLT(smtROBPolicy, "SMT ROB Sharing Policy", "Partitioned"),
+ INIT_PARAM_DFLT(smtROBThreshold,"SMT ROB Threshold", 100),
+ INIT_PARAM_DFLT(smtCommitPolicy,"SMT Commit Fetch Policy", "RoundRobin"),
+
+ INIT_PARAM(instShiftAmt, "Number of bits to shift instructions by"),
+ INIT_PARAM(defer_registration, "defer system registration (for sampling)"),
+
+ INIT_PARAM(function_trace, "Enable function trace"),
+ INIT_PARAM(function_trace_start, "Cycle to start function trace")
+
+END_INIT_SIM_OBJECT_PARAMS(SimpleOzoneCPU)
+
+CREATE_SIM_OBJECT(SimpleOzoneCPU)
+{
+ SimpleOzoneCPU *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.isValid() ? numThreads : workload.size();
+
+ if (workload.size() == 0) {
+ fatal("Must specify at least one workload!");
+ }
+
+#endif
+
+ SimpleParams *params = new SimpleParams;
+
+ params->clock = clock;
+
+ params->name = getInstanceName();
+ params->numberOfThreads = actual_num_threads;
+
+#if FULL_SYSTEM
+ params->system = system;
+ params->cpu_id = cpu_id;
+ params->itb = itb;
+ params->dtb = dtb;
+#else
+ params->workload = workload;
+// params->pTable = page_table;
+#endif // FULL_SYSTEM
+
+ params->mem = mem;
+ params->checker = checker;
+ 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->icacheInterface = icache ? icache->getInterface() : NULL;
+ params->dcacheInterface = dcache ? dcache->getInterface() : NULL;
+ params->cachePorts = cachePorts;
+
+ params->width = width;
+ params->frontEndWidth = frontEndWidth;
+ params->backEndWidth = backEndWidth;
+ params->backEndSquashLatency = backEndSquashLatency;
+ params->backEndLatency = backEndLatency;
+ params->maxInstBufferSize = maxInstBufferSize;
+ params->numPhysicalRegs = numPhysIntRegs + numPhysFloatRegs;
+
+ 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->issueWidth = issueWidth;
+ params->executeWidth = executeWidth;
+ params->executeIntWidth = executeIntWidth;
+ params->executeFloatWidth = executeFloatWidth;
+ params->executeBranchWidth = executeBranchWidth;
+ params->executeMemoryWidth = executeMemoryWidth;
+
+ params->iewToCommitDelay = iewToCommitDelay;
+ params->renameToROBDelay = renameToROBDelay;
+ params->commitWidth = commitWidth;
+ params->squashWidth = squashWidth;
+
+ 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->decoupledFrontEnd = decoupledFrontEnd;
+ params->dispatchWidth = dispatchWidth;
+ params->wbWidth = wbWidth;
+
+ params->smtNumFetchingThreads = smtNumFetchingThreads;
+ 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 SimpleOzoneCPU(params);
+
+ return cpu;
+}
+
+REGISTER_SIM_OBJECT("SimpleOzoneCPU", SimpleOzoneCPU)
+
diff --git a/src/cpu/ozone/simple_impl.hh b/src/cpu/ozone/simple_impl.hh
new file mode 100644
index 000000000..3199d8d8a
--- /dev/null
+++ b/src/cpu/ozone/simple_impl.hh
@@ -0,0 +1,71 @@
+/*
+ * 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_OZONE_SIMPLE_IMPL_HH__
+#define __CPU_OZONE_SIMPLE_IMPL_HH__
+
+#include "arch/isa_traits.hh"
+#include "cpu/o3/bpred_unit.hh"
+#include "cpu/ozone/cpu.hh"
+#include "cpu/ozone/front_end.hh"
+#include "cpu/ozone/inorder_back_end.hh"
+#include "cpu/ozone/null_predictor.hh"
+#include "cpu/ozone/dyn_inst.hh"
+#include "cpu/ozone/simple_params.hh"
+
+//template <class Impl>
+//class OzoneCPU;
+
+template <class Impl>
+class OzoneDynInst;
+
+struct SimpleImpl {
+ typedef SimpleParams Params;
+ typedef OzoneCPU<SimpleImpl> OzoneCPU;
+ typedef OzoneCPU FullCPU;
+
+ // Would like to put these into their own area.
+// typedef NullPredictor BranchPred;
+ typedef BPredUnit<SimpleImpl> BranchPred;
+ typedef FrontEnd<SimpleImpl> FrontEnd;
+ // Will need IQ, LSQ eventually
+ typedef InorderBackEnd<SimpleImpl> BackEnd;
+
+ typedef OzoneDynInst<SimpleImpl> DynInst;
+ typedef RefCountingPtr<DynInst> DynInstPtr;
+
+ typedef uint64_t IssueStruct;
+
+ enum {
+ MaxThreads = 1
+ };
+};
+
+#endif // __CPU_OZONE_SIMPLE_IMPL_HH__
diff --git a/src/cpu/ozone/simple_params.hh b/src/cpu/ozone/simple_params.hh
new file mode 100644
index 000000000..11cee716f
--- /dev/null
+++ b/src/cpu/ozone/simple_params.hh
@@ -0,0 +1,192 @@
+/*
+ * 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_OZONE_SIMPLE_PARAMS_HH__
+#define __CPU_OZONE_SIMPLE_PARAMS_HH__
+
+#include "cpu/ozone/cpu.hh"
+
+//Forward declarations
+class AlphaDTB;
+class AlphaITB;
+class FUPool;
+class MemObject;
+class PageTable;
+class Process;
+class System;
+
+/**
+ * This file defines the parameters that will be used for the OzoneCPU.
+ * 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 SimpleParams : public BaseCPU::Params
+{
+ public:
+
+#if FULL_SYSTEM
+ AlphaITB *itb; AlphaDTB *dtb;
+#else
+ std::vector<Process *> workload;
+#endif // FULL_SYSTEM
+
+ //Page Table
+ PageTable *pTable;
+
+ MemObject *mem;
+
+ //
+ // Caches
+ //
+// MemInterface *icacheInterface;
+// MemInterface *dcacheInterface;
+
+ unsigned cachePorts;
+ unsigned width;
+ unsigned frontEndWidth;
+ unsigned backEndWidth;
+ unsigned backEndSquashLatency;
+ unsigned backEndLatency;
+ unsigned maxInstBufferSize;
+ unsigned numPhysicalRegs;
+ unsigned maxOutstandingMemOps;
+ //
+ // 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 issueWidth;
+ unsigned executeWidth;
+ unsigned executeIntWidth;
+ unsigned executeFloatWidth;
+ unsigned executeBranchWidth;
+ unsigned executeMemoryWidth;
+ FUPool *fuPool;
+
+ //
+ // Commit
+ //
+ unsigned iewToCommitDelay;
+ unsigned renameToROBDelay;
+ unsigned commitWidth;
+ unsigned squashWidth;
+
+ //
+ // Branch predictor (BP & BTB)
+ //
+ std::string predType;
+ unsigned localPredictorSize;
+ unsigned localCtrBits;
+ unsigned localHistoryTableSize;
+ unsigned localHistoryBits;
+ unsigned globalPredictorSize;
+ unsigned globalCtrBits;
+ unsigned globalHistoryBits;
+ unsigned choicePredictorSize;
+ unsigned choiceCtrBits;
+
+ unsigned BTBEntries;
+ unsigned BTBTagSize;
+
+ unsigned RASSize;
+
+ //
+ // Load store queue
+ //
+ unsigned LQEntries;
+ unsigned SQEntries;
+
+ //
+ // Memory dependence
+ //
+ unsigned SSITSize;
+ unsigned LFSTSize;
+
+ //
+ // Miscellaneous
+ //
+ unsigned numPhysIntRegs;
+ unsigned numPhysFloatRegs;
+ unsigned numIQEntries;
+ unsigned numROBEntries;
+
+ bool decoupledFrontEnd;
+ int dispatchWidth;
+ int wbWidth;
+
+ //SMT Parameters
+ unsigned smtNumFetchingThreads;
+
+ std::string smtFetchPolicy;
+
+ std::string smtIQPolicy;
+ unsigned smtIQThreshold;
+
+ std::string smtLSQPolicy;
+ unsigned smtLSQThreshold;
+
+ std::string smtCommitPolicy;
+
+ std::string smtROBPolicy;
+ unsigned smtROBThreshold;
+
+ // Probably can get this from somewhere.
+ unsigned instShiftAmt;
+};
+
+#endif // __CPU_OZONE_SIMPLE_PARAMS_HH__
diff --git a/src/cpu/ozone/thread_state.hh b/src/cpu/ozone/thread_state.hh
new file mode 100644
index 000000000..ef4b1429d
--- /dev/null
+++ b/src/cpu/ozone/thread_state.hh
@@ -0,0 +1,134 @@
+/*
+ * 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_OZONE_THREAD_STATE_HH__
+#define __CPU_OZONE_THREAD_STATE_HH__
+
+#include "arch/faults.hh"
+#include "arch/isa_traits.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/thread_state.hh"
+#include "sim/process.hh"
+
+class Event;
+//class Process;
+
+#if FULL_SYSTEM
+class EndQuiesceEvent;
+class FunctionProfile;
+class ProfileNode;
+#else
+class Process;
+class FunctionalMemory;
+#endif
+
+// Maybe this ozone thread state should only really have committed state?
+// I need to think about why I'm using this and what it's useful for. Clearly
+// has benefits for SMT; basically serves same use as SimpleThread.
+// Makes the ExecContext proxy easier. Gives organization/central access point
+// to state of a thread that can be accessed normally (i.e. not in-flight
+// stuff within a OoO processor). Does this need an TC proxy within it?
+template <class Impl>
+struct OzoneThreadState : public ThreadState {
+ typedef typename ThreadContext::Status Status;
+ typedef typename Impl::CPUType CPUType;
+ typedef TheISA::MiscReg MiscReg;
+
+#if FULL_SYSTEM
+ OzoneThreadState(CPUType *_cpu, int _thread_num)
+ : ThreadState(-1, _thread_num),
+ intrflag(0), inSyscall(0), trapPending(0)
+ {
+ miscRegFile.clear();
+ }
+#else
+ OzoneThreadState(CPUType *_cpu, int _thread_num, Process *_process,
+ int _asid, MemObject *mem)
+ : ThreadState(-1, _thread_num, _process, _asid, mem),
+ cpu(_cpu), inSyscall(0), trapPending(0)
+ {
+ miscRegFile.clear();
+ }
+#endif
+
+ RenameTable<Impl> renameTable;
+
+ Addr PC;
+
+ Addr nextPC;
+
+ TheISA::MiscRegFile miscRegFile;
+
+ int intrflag;
+
+ typename Impl::CPUType *cpu;
+
+ bool inSyscall;
+
+ bool trapPending;
+
+ ThreadContext *tc;
+
+ ThreadContext *getTC() { return tc; }
+
+ MiscReg readMiscReg(int misc_reg)
+ {
+ return miscRegFile.readReg(misc_reg);
+ }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ {
+ return miscRegFile.readRegWithEffect(misc_reg, fault, tc);
+ }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ {
+ return miscRegFile.setReg(misc_reg, val);
+ }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ {
+ return miscRegFile.setRegWithEffect(misc_reg, val, tc);
+ }
+
+ uint64_t readPC()
+ { return PC; }
+
+ void setPC(uint64_t val)
+ { PC = val; }
+
+ uint64_t readNextPC()
+ { return nextPC; }
+
+ void setNextPC(uint64_t val)
+ { nextPC = val; }
+};
+
+#endif // __CPU_OZONE_THREAD_STATE_HH__
diff --git a/src/cpu/pc_event.cc b/src/cpu/pc_event.cc
index 050bf1a88..fca357fe3 100644
--- a/src/cpu/pc_event.cc
+++ b/src/cpu/pc_event.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <algorithm>
@@ -34,7 +37,7 @@
#include "base/trace.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/pc_event.hh"
#include "sim/debug.hh"
#include "sim/root.hh"
@@ -78,9 +81,9 @@ PCEventQueue::schedule(PCEvent *event)
}
bool
-PCEventQueue::doService(ExecContext *xc)
+PCEventQueue::doService(ThreadContext *tc)
{
- Addr pc = xc->readPC() & ~0x3;
+ Addr pc = tc->readPC() & ~0x3;
int serviced = 0;
range_t range = equal_range(pc);
for (iterator i = range.first; i != range.second; ++i) {
@@ -88,13 +91,13 @@ PCEventQueue::doService(ExecContext *xc)
// another event. This for example, prevents two invocations
// of the SkipFuncEvent. Maybe we should have separate PC
// event queues for each processor?
- if (pc != (xc->readPC() & ~0x3))
+ if (pc != (tc->readPC() & ~0x3))
continue;
DPRINTF(PCEvent, "PC based event serviced at %#x: %s\n",
(*i)->pc(), (*i)->descr());
- (*i)->process(xc);
+ (*i)->process(tc);
++serviced;
}
@@ -125,9 +128,9 @@ BreakPCEvent::BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
}
void
-BreakPCEvent::process(ExecContext *xc)
+BreakPCEvent::process(ThreadContext *tc)
{
- StringWrap name(xc->getCpuPtr()->name() + ".break_event");
+ StringWrap name(tc->getCpuPtr()->name() + ".break_event");
DPRINTFN("break event %s triggered\n", descr());
debug_break();
if (remove)
diff --git a/src/cpu/pc_event.hh b/src/cpu/pc_event.hh
index 32b7f3ef5..6b048b2c2 100644
--- a/src/cpu/pc_event.hh
+++ b/src/cpu/pc_event.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __PC_EVENT_HH__
@@ -33,7 +36,7 @@
#include "base/misc.hh"
-class ExecContext;
+class ThreadContext;
class PCEventQueue;
class PCEvent
@@ -55,7 +58,7 @@ class PCEvent
Addr pc() const { return evpc; }
bool remove();
- virtual void process(ExecContext *xc) = 0;
+ virtual void process(ThreadContext *tc) = 0;
};
class PCEventQueue
@@ -87,7 +90,7 @@ class PCEventQueue
protected:
map_t pc_map;
- bool doService(ExecContext *xc);
+ bool doService(ThreadContext *tc);
public:
PCEventQueue();
@@ -95,12 +98,12 @@ class PCEventQueue
bool remove(PCEvent *event);
bool schedule(PCEvent *event);
- bool service(ExecContext *xc)
+ bool service(ThreadContext *tc)
{
if (pc_map.empty())
return false;
- return doService(xc);
+ return doService(tc);
}
range_t equal_range(Addr pc);
@@ -134,7 +137,7 @@ class BreakPCEvent : public PCEvent
public:
BreakPCEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool del = false);
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
#endif // __PC_EVENT_HH__
diff --git a/src/cpu/profile.cc b/src/cpu/profile.cc
index fe3458b61..4f04615e9 100644
--- a/src/cpu/profile.cc
+++ b/src/cpu/profile.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <string>
@@ -34,7 +36,7 @@
#include "base/trace.hh"
#include "base/loader/symtab.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/profile.hh"
using namespace std;
@@ -118,7 +120,7 @@ FunctionProfile::clear()
}
void
-FunctionProfile::dump(ExecContext *xc, ostream &os) const
+FunctionProfile::dump(ThreadContext *tc, ostream &os) const
{
ccprintf(os, ">>>PC data\n");
map<Addr, Counter>::const_iterator i, end = pc_count.end();
diff --git a/src/cpu/profile.hh b/src/cpu/profile.hh
index d55c9eec9..7f9625241 100644
--- a/src/cpu/profile.hh
+++ b/src/cpu/profile.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CPU_PROFILE_HH__
@@ -35,7 +37,7 @@
#include "sim/host.hh"
#include "arch/stacktrace.hh"
-class ExecContext;
+class ThreadContext;
class ProfileNode
{
@@ -70,17 +72,17 @@ class FunctionProfile
FunctionProfile(const SymbolTable *symtab);
~FunctionProfile();
- ProfileNode *consume(ExecContext *xc, StaticInstPtr inst);
+ ProfileNode *consume(ThreadContext *tc, StaticInstPtr inst);
ProfileNode *consume(const std::vector<Addr> &stack);
void clear();
- void dump(ExecContext *xc, std::ostream &out) const;
+ void dump(ThreadContext *tc, std::ostream &out) const;
void sample(ProfileNode *node, Addr pc);
};
inline ProfileNode *
-FunctionProfile::consume(ExecContext *xc, StaticInstPtr inst)
+FunctionProfile::consume(ThreadContext *tc, StaticInstPtr inst)
{
- if (!trace.trace(xc, inst))
+ if (!trace.trace(tc, inst))
return NULL;
trace.dprintf();
return consume(trace.getstack());
diff --git a/src/cpu/quiesce_event.cc b/src/cpu/quiesce_event.cc
new file mode 100644
index 000000000..8dd20db02
--- /dev/null
+++ b/src/cpu/quiesce_event.cc
@@ -0,0 +1,49 @@
+/*
+ * 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
+ */
+
+#include "cpu/thread_context.hh"
+#include "cpu/quiesce_event.hh"
+
+EndQuiesceEvent::EndQuiesceEvent(ThreadContext *_tc)
+ : Event(&mainEventQueue), tc(_tc)
+{
+}
+
+void
+EndQuiesceEvent::process()
+{
+ tc->activate();
+}
+
+const char*
+EndQuiesceEvent::description()
+{
+ return "End Quiesce Event.";
+}
diff --git a/src/cpu/quiesce_event.hh b/src/cpu/quiesce_event.hh
new file mode 100644
index 000000000..3de40f97e
--- /dev/null
+++ b/src/cpu/quiesce_event.hh
@@ -0,0 +1,53 @@
+/*
+ * 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_QUIESCE_EVENT_HH__
+#define __CPU_QUIESCE_EVENT_HH__
+
+#include "sim/eventq.hh"
+
+class ThreadContext;
+
+/** Event for timing out quiesce instruction */
+struct EndQuiesceEvent : public Event
+{
+ /** A pointer to the thread context that is quiesced */
+ ThreadContext *tc;
+
+ EndQuiesceEvent(ThreadContext *_tc);
+
+ /** Event process to occur at interrupt*/
+ virtual void process();
+
+ /** Event description */
+ virtual const char *description();
+};
+
+#endif // __CPU_QUIESCE_EVENT_HH__
diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc
index 3cad6e43f..b7202cbbb 100644
--- a/src/cpu/simple/atomic.cc
+++ b/src/cpu/simple/atomic.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "arch/utility.hh"
@@ -68,11 +70,11 @@ AtomicSimpleCPU::init()
BaseCPU::init();
#if FULL_SYSTEM
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(xc, xc->readCpuId());
+ TheISA::initCPU(tc, tc->readCpuId());
}
#endif
}
@@ -106,11 +108,10 @@ AtomicSimpleCPU::CpuPort::recvStatusChange(Status status)
panic("AtomicSimpleCPU doesn't expect recvStatusChange callback!");
}
-Packet *
+void
AtomicSimpleCPU::CpuPort::recvRetry()
{
panic("AtomicSimpleCPU doesn't expect recvRetry callback!");
- return NULL;
}
@@ -121,26 +122,20 @@ AtomicSimpleCPU::AtomicSimpleCPU(Params *p)
{
_status = Idle;
- ifetch_req = new Request(true);
- ifetch_req->setAsid(0);
- // @todo fix me and get the real cpu iD!!!
- ifetch_req->setCpuNum(0);
- ifetch_req->setSize(sizeof(MachInst));
+ // @todo fix me and get the real cpu id & thread number!!!
+ ifetch_req = new Request();
+ ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
ifetch_pkt->dataStatic(&inst);
- data_read_req = new Request(true);
- // @todo fix me and get the real cpu iD!!!
- data_read_req->setCpuNum(0);
- data_read_req->setAsid(0);
+ data_read_req = new Request();
+ data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
data_read_pkt = new Packet(data_read_req, Packet::ReadReq,
Packet::Broadcast);
data_read_pkt->dataStatic(&dataReg);
- data_write_req = new Request(true);
- // @todo fix me and get the real cpu iD!!!
- data_write_req->setCpuNum(0);
- data_write_req->setAsid(0);
+ data_write_req = new Request();
+ data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
data_write_pkt = new Packet(data_write_req, Packet::WriteReq,
Packet::Broadcast);
}
@@ -153,8 +148,8 @@ AtomicSimpleCPU::~AtomicSimpleCPU()
void
AtomicSimpleCPU::serialize(ostream &os)
{
- BaseSimpleCPU::serialize(os);
SERIALIZE_ENUM(_status);
+ BaseSimpleCPU::serialize(os);
nameOut(os, csprintf("%s.tickEvent", name()));
tickEvent.serialize(os);
}
@@ -162,21 +157,18 @@ AtomicSimpleCPU::serialize(ostream &os)
void
AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
- BaseSimpleCPU::unserialize(cp, section);
UNSERIALIZE_ENUM(_status);
+ BaseSimpleCPU::unserialize(cp, section);
tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
}
void
-AtomicSimpleCPU::switchOut(Sampler *s)
+AtomicSimpleCPU::switchOut()
{
- sampler = s;
- if (status() == Running) {
- _status = SwitchedOut;
+ assert(status() == Running || status() == Idle);
+ _status = SwitchedOut;
- tickEvent.squash();
- }
- sampler->signalSwitched();
+ tickEvent.squash();
}
@@ -187,11 +179,11 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
assert(!tickEvent.scheduled());
- // if any of this CPU's ExecContexts are active, mark the CPU as
+ // if any of this CPU's ThreadContexts are active, mark the CPU as
// running and schedule its tick event.
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
- if (xc->status() == ExecContext::Active && _status != Running) {
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
tickEvent.schedule(curTick);
break;
@@ -204,7 +196,7 @@ void
AtomicSimpleCPU::activateContext(int thread_num, int delay)
{
assert(thread_num == 0);
- assert(cpuXC);
+ assert(thread);
assert(_status == Idle);
assert(!tickEvent.scheduled());
@@ -219,7 +211,7 @@ void
AtomicSimpleCPU::suspendContext(int thread_num)
{
assert(thread_num == 0);
- assert(cpuXC);
+ assert(thread);
assert(_status == Running);
@@ -237,24 +229,20 @@ template <class T>
Fault
AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags)
{
- data_read_req->setVaddr(addr);
- data_read_req->setSize(sizeof(T));
- data_read_req->setFlags(flags);
- data_read_req->setTime(curTick);
+ data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
if (traceData) {
traceData->setAddr(addr);
}
// translate to physical address
- Fault fault = cpuXC->translateDataReadReq(data_read_req);
+ Fault fault = thread->translateDataReadReq(data_read_req);
// Now do the access.
if (fault == NoFault) {
- data_read_pkt->reset();
data_read_pkt->reinitFromRequest();
- dcache_complete = dcachePort.sendAtomic(data_read_pkt);
+ dcache_latency = dcachePort.sendAtomic(data_read_pkt);
dcache_access = true;
assert(data_read_pkt->result == Packet::Success);
@@ -316,26 +304,22 @@ template <class T>
Fault
AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- data_write_req->setVaddr(addr);
- data_write_req->setTime(curTick);
- data_write_req->setSize(sizeof(T));
- data_write_req->setFlags(flags);
+ data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
if (traceData) {
traceData->setAddr(addr);
}
// translate to physical address
- Fault fault = cpuXC->translateDataWriteReq(data_write_req);
+ Fault fault = thread->translateDataWriteReq(data_write_req);
// Now do the access.
if (fault == NoFault) {
- data_write_pkt->reset();
data = htog(data);
- data_write_pkt->dataStatic(&data);
data_write_pkt->reinitFromRequest();
+ data_write_pkt->dataStatic(&data);
- dcache_complete = dcachePort.sendAtomic(data_write_pkt);
+ dcache_latency = dcachePort.sendAtomic(data_write_pkt);
dcache_access = true;
assert(data_write_pkt->result == Packet::Success);
@@ -411,12 +395,12 @@ AtomicSimpleCPU::tick()
checkForInterrupts();
- ifetch_req->resetMin();
- ifetch_pkt->reset();
- Fault fault = setupFetchPacket(ifetch_pkt);
+ Fault fault = setupFetchRequest(ifetch_req);
if (fault == NoFault) {
- Tick icache_complete = icachePort.sendAtomic(ifetch_pkt);
+ ifetch_pkt->reinitFromRequest();
+
+ Tick icache_latency = icachePort.sendAtomic(ifetch_pkt);
// ifetch_req is initialized to read the instruction directly
// into the CPU object's inst field.
@@ -426,15 +410,14 @@ AtomicSimpleCPU::tick()
postExecute();
if (simulate_stalls) {
- // This calculation assumes that the icache and dcache
- // access latencies are always a multiple of the CPU's
- // cycle time. If not, the next tick event may get
- // scheduled at a non-integer multiple of the CPU
- // cycle time.
- Tick icache_stall = icache_complete - curTick - cycles(1);
+ Tick icache_stall = icache_latency - cycles(1);
Tick dcache_stall =
- dcache_access ? dcache_complete - curTick - cycles(1) : 0;
- latency += icache_stall + dcache_stall;
+ dcache_access ? dcache_latency - cycles(1) : 0;
+ Tick stall_cycles = (icache_stall + dcache_stall) / cycles(1);
+ if (cycles(stall_cycles) < (icache_stall + dcache_stall))
+ latency += cycles(stall_cycles+1);
+ else
+ latency += cycles(stall_cycles);
}
}
diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh
index ab3a3e8ef..951a8da06 100644
--- a/src/cpu/simple/atomic.hh
+++ b/src/cpu/simple/atomic.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __CPU_SIMPLE_ATOMIC_HH__
@@ -98,7 +100,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU
virtual void recvStatusChange(Status status);
- virtual Packet *recvRetry();
+ virtual void recvRetry();
virtual void getDeviceAddressRanges(AddrRangeList &resp,
AddrRangeList &snoop)
@@ -116,14 +118,14 @@ class AtomicSimpleCPU : public BaseSimpleCPU
Packet *data_write_pkt;
bool dcache_access;
- Tick dcache_complete;
+ Tick dcache_latency;
public:
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
- void switchOut(Sampler *s);
+ void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
virtual void activateContext(int thread_num, int delay);
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 18f170449..db5dd2acf 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Korey Sewell
*/
#include "arch/utility.hh"
@@ -36,18 +39,18 @@
#include "base/stats/events.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
-#include "cpu/cpu_exec_context.hh"
-#include "cpu/exec_context.hh"
#include "cpu/exetrace.hh"
#include "cpu/profile.hh"
#include "cpu/sampler/sampler.hh"
#include "cpu/simple/base.hh"
+#include "cpu/simple_thread.hh"
#include "cpu/smt.hh"
#include "cpu/static_inst.hh"
+#include "cpu/thread_context.hh"
#include "kern/kernel_stats.hh"
#include "mem/packet_impl.hh"
-#include "sim/byteswap.hh"
#include "sim/builder.hh"
+#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
@@ -68,16 +71,18 @@ using namespace std;
using namespace TheISA;
BaseSimpleCPU::BaseSimpleCPU(Params *p)
- : BaseCPU(p), mem(p->mem), cpuXC(NULL)
+ : BaseCPU(p), mem(p->mem), thread(NULL)
{
#if FULL_SYSTEM
- cpuXC = new CPUExecContext(this, 0, p->system, p->itb, p->dtb);
+ thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb);
#else
- cpuXC = new CPUExecContext(this, /* thread_num */ 0, p->process,
+ thread = new SimpleThread(this, /* thread_num */ 0, p->process,
/* asid */ 0, mem);
#endif // !FULL_SYSTEM
- xcProxy = cpuXC->getProxy();
+ thread->setStatus(ThreadContext::Suspended);
+
+ tc = thread->getTC();
numInst = 0;
startNumInst = 0;
@@ -86,7 +91,7 @@ BaseSimpleCPU::BaseSimpleCPU(Params *p)
lastIcacheStall = 0;
lastDcacheStall = 0;
- execContexts.push_back(xcProxy);
+ threadContexts.push_back(tc);
}
BaseSimpleCPU::~BaseSimpleCPU()
@@ -176,7 +181,7 @@ BaseSimpleCPU::serialize(ostream &os)
BaseCPU::serialize(os);
SERIALIZE_SCALAR(inst);
nameOut(os, csprintf("%s.xc", name()));
- cpuXC->serialize(os);
+ thread->serialize(os);
}
void
@@ -184,7 +189,7 @@ BaseSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
BaseCPU::unserialize(cp, section);
UNSERIALIZE_SCALAR(inst);
- cpuXC->unserialize(cp, csprintf("%s.xc", section));
+ thread->unserialize(cp, csprintf("%s.xc", section));
}
void
@@ -213,16 +218,16 @@ BaseSimpleCPU::copySrcTranslate(Addr src)
memReq->reset(src & ~(blk_size - 1), blk_size);
// translate to physical address
- Fault fault = cpuXC->translateDataReadReq(req);
+ Fault fault = thread->translateDataReadReq(req);
if (fault == NoFault) {
- cpuXC->copySrcAddr = src;
- cpuXC->copySrcPhysAddr = memReq->paddr + offset;
+ thread->copySrcAddr = src;
+ thread->copySrcPhysAddr = memReq->paddr + offset;
} else {
assert(!fault->isAlignmentFault());
- cpuXC->copySrcAddr = 0;
- cpuXC->copySrcPhysAddr = 0;
+ thread->copySrcAddr = 0;
+ thread->copySrcPhysAddr = 0;
}
return fault;
#else
@@ -239,7 +244,7 @@ BaseSimpleCPU::copy(Addr dest)
// Only support block sizes of 64 atm.
assert(blk_size == 64);
uint8_t data[blk_size];
- //assert(cpuXC->copySrcAddr);
+ //assert(thread->copySrcAddr);
int offset = dest & (blk_size - 1);
// Make sure block doesn't span page
@@ -252,19 +257,19 @@ BaseSimpleCPU::copy(Addr dest)
memReq->reset(dest & ~(blk_size -1), blk_size);
// translate to physical address
- Fault fault = cpuXC->translateDataWriteReq(req);
+ Fault fault = thread->translateDataWriteReq(req);
if (fault == NoFault) {
Addr dest_addr = memReq->paddr + offset;
// Need to read straight from memory since we have more than 8 bytes.
- memReq->paddr = cpuXC->copySrcPhysAddr;
- cpuXC->mem->read(memReq, data);
+ memReq->paddr = thread->copySrcPhysAddr;
+ thread->mem->read(memReq, data);
memReq->paddr = dest_addr;
- cpuXC->mem->write(memReq, data);
+ thread->mem->write(memReq, data);
if (dcacheInterface) {
memReq->cmd = Copy;
memReq->completionEvent = NULL;
- memReq->paddr = cpuXC->copySrcPhysAddr;
+ memReq->paddr = thread->copySrcPhysAddr;
memReq->dest = dest_addr;
memReq->size = 64;
memReq->time = curTick;
@@ -286,7 +291,7 @@ BaseSimpleCPU::copy(Addr dest)
Addr
BaseSimpleCPU::dbg_vtophys(Addr addr)
{
- return vtophys(xcProxy, addr);
+ return vtophys(tc, addr);
}
#endif // FULL_SYSTEM
@@ -296,9 +301,9 @@ BaseSimpleCPU::post_interrupt(int int_num, int index)
{
BaseCPU::post_interrupt(int_num, index);
- if (cpuXC->status() == ExecContext::Suspended) {
+ if (thread->status() == ThreadContext::Suspended) {
DPRINTF(IPI,"Suspended Processor awoke\n");
- cpuXC->activate();
+ thread->activate();
}
}
#endif // FULL_SYSTEM
@@ -307,15 +312,15 @@ void
BaseSimpleCPU::checkForInterrupts()
{
#if FULL_SYSTEM
- if (checkInterrupts && check_interrupts() && !cpuXC->inPalMode()) {
+ if (checkInterrupts && check_interrupts() && !thread->inPalMode()) {
int ipl = 0;
int summary = 0;
checkInterrupts = false;
- if (cpuXC->readMiscReg(IPR_SIRR)) {
+ if (thread->readMiscReg(IPR_SIRR)) {
for (int i = INTLEVEL_SOFTWARE_MIN;
i < INTLEVEL_SOFTWARE_MAX; i++) {
- if (cpuXC->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
+ if (thread->readMiscReg(IPR_SIRR) & (ULL(1) << i)) {
// See table 4-19 of 21164 hardware reference
ipl = (i - INTLEVEL_SOFTWARE_MIN) + 1;
summary |= (ULL(1) << i);
@@ -323,7 +328,7 @@ BaseSimpleCPU::checkForInterrupts()
}
}
- uint64_t interrupts = cpuXC->cpu->intr_status();
+ uint64_t interrupts = thread->cpu->intr_status();
for (int i = INTLEVEL_EXTERNAL_MIN;
i < INTLEVEL_EXTERNAL_MAX; i++) {
if (interrupts & (ULL(1) << i)) {
@@ -333,17 +338,17 @@ BaseSimpleCPU::checkForInterrupts()
}
}
- if (cpuXC->readMiscReg(IPR_ASTRR))
+ if (thread->readMiscReg(IPR_ASTRR))
panic("asynchronous traps not implemented\n");
- if (ipl && ipl > cpuXC->readMiscReg(IPR_IPLR)) {
- cpuXC->setMiscReg(IPR_ISR, summary);
- cpuXC->setMiscReg(IPR_INTID, ipl);
+ if (ipl && ipl > thread->readMiscReg(IPR_IPLR)) {
+ thread->setMiscReg(IPR_ISR, summary);
+ thread->setMiscReg(IPR_INTID, ipl);
- Fault(new InterruptFault)->invoke(xcProxy);
+ Fault(new InterruptFault)->invoke(tc);
DPRINTF(Flow, "Interrupt! IPLR=%d ipl=%d summary=%x\n",
- cpuXC->readMiscReg(IPR_IPLR), ipl, summary);
+ thread->readMiscReg(IPR_IPLR), ipl, summary);
}
}
#endif
@@ -351,29 +356,22 @@ BaseSimpleCPU::checkForInterrupts()
Fault
-BaseSimpleCPU::setupFetchPacket(Packet *ifetch_pkt)
+BaseSimpleCPU::setupFetchRequest(Request *req)
{
- // Try to fetch an instruction
-
// set up memory request for instruction fetch
-
- DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",cpuXC->readPC(),
- cpuXC->readNextPC(),cpuXC->readNextNPC());
-
- Request *ifetch_req = ifetch_pkt->req;
- ifetch_req->setVaddr(cpuXC->readPC() & ~3);
- ifetch_req->setTime(curTick);
-#if FULL_SYSTEM
- ifetch_req->setFlags((cpuXC->readPC() & 1) ? PHYSICAL : 0);
+#if THE_ISA == ALPHA_ISA
+ DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p",thread->readPC(),
+ thread->readNextPC());
#else
- ifetch_req->setFlags(0);
+ DPRINTF(Fetch,"Fetch: PC:%08p NPC:%08p NNPC:%08p\n",thread->readPC(),
+ thread->readNextPC(),thread->readNextNPC());
#endif
- Fault fault = cpuXC->translateInstReq(ifetch_req);
+ req->setVirt(0, thread->readPC() & ~3, sizeof(MachInst),
+ (FULL_SYSTEM && (thread->readPC() & 1)) ? PHYSICAL : 0,
+ thread->readPC());
- if (fault == NoFault) {
- ifetch_pkt->reinitFromRequest();
- }
+ Fault fault = thread->translateInstReq(req);
return fault;
}
@@ -383,33 +381,33 @@ void
BaseSimpleCPU::preExecute()
{
// maintain $r0 semantics
- cpuXC->setIntReg(ZeroReg, 0);
+ thread->setIntReg(ZeroReg, 0);
#if THE_ISA == ALPHA_ISA
- cpuXC->setFloatReg(ZeroReg, 0.0);
+ thread->setFloatReg(ZeroReg, 0.0);
#endif // ALPHA_ISA
// keep an instruction count
numInst++;
numInsts++;
- cpuXC->func_exe_inst++;
+ thread->funcExeInst++;
// check for instruction-count-based events
comInstEventQueue[0]->serviceEvents(numInst);
// decode the instruction
inst = gtoh(inst);
- curStaticInst = StaticInst::decode(makeExtMI(inst, cpuXC->readPC()));
+ curStaticInst = StaticInst::decode(makeExtMI(inst, thread->readPC()));
- traceData = Trace::getInstRecord(curTick, xcProxy, this, curStaticInst,
- cpuXC->readPC());
+ traceData = Trace::getInstRecord(curTick, tc, this, curStaticInst,
+ thread->readPC());
DPRINTF(Decode,"Decode: Decoded %s instruction (opcode: 0x%x): 0x%x\n",
curStaticInst->getName(), curStaticInst->getOpcode(),
curStaticInst->machInst);
#if FULL_SYSTEM
- cpuXC->setInst(inst);
+ thread->setInst(inst);
#endif // FULL_SYSTEM
}
@@ -417,18 +415,13 @@ void
BaseSimpleCPU::postExecute()
{
#if FULL_SYSTEM
- if (system->kernelBinning->fnbin) {
- assert(kernelStats);
- system->kernelBinning->execute(xcProxy, inst);
- }
-
- if (cpuXC->profile) {
+ if (thread->profile) {
bool usermode =
- (cpuXC->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
- cpuXC->profilePC = usermode ? 1 : cpuXC->readPC();
- ProfileNode *node = cpuXC->profile->consume(xcProxy, inst);
+ (thread->readMiscReg(AlphaISA::IPR_DTB_CM) & 0x18) != 0;
+ thread->profilePC = usermode ? 1 : thread->readPC();
+ ProfileNode *node = thread->profile->consume(tc, inst);
if (node)
- cpuXC->profileNode = node;
+ thread->profileNode = node;
}
#endif
@@ -441,7 +434,7 @@ BaseSimpleCPU::postExecute()
comLoadEventQueue[0]->serviceEvents(numLoad);
}
- traceFunctions(cpuXC->readPC());
+ traceFunctions(thread->readPC());
if (traceData) {
traceData->finalize();
@@ -453,20 +446,16 @@ void
BaseSimpleCPU::advancePC(Fault fault)
{
if (fault != NoFault) {
-#if FULL_SYSTEM
- fault->invoke(xcProxy);
-#else // !FULL_SYSTEM
- fatal("fault (%s) detected @ PC %08p", fault->name(), cpuXC->readPC());
-#endif // FULL_SYSTEM
+ fault->invoke(tc);
}
else {
// go to the next instruction
- cpuXC->setPC(cpuXC->readNextPC());
+ thread->setPC(thread->readNextPC());
#if THE_ISA == ALPHA_ISA
- cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst));
+ thread->setNextPC(thread->readNextPC() + sizeof(MachInst));
#else
- cpuXC->setNextPC(cpuXC->readNextNPC());
- cpuXC->setNextNPC(cpuXC->readNextNPC() + sizeof(MachInst));
+ thread->setNextPC(thread->readNextNPC());
+ thread->setNextNPC(thread->readNextNPC() + sizeof(MachInst));
#endif
}
@@ -474,9 +463,9 @@ BaseSimpleCPU::advancePC(Fault fault)
#if FULL_SYSTEM
Addr oldpc;
do {
- oldpc = cpuXC->readPC();
- system->pcEventQueue.service(xcProxy);
- } while (oldpc != cpuXC->readPC());
+ oldpc = thread->readPC();
+ system->pcEventQueue.service(tc);
+ } while (oldpc != thread->readPC());
#endif
}
diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh
index 4c0e6f3c7..39bc86050 100644
--- a/src/cpu/simple/base.hh
+++ b/src/cpu/simple/base.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Dave Greene
+ * Nathan Binkert
*/
#ifndef __CPU_SIMPLE_BASE_HH__
@@ -32,7 +36,7 @@
#include "base/statistics.hh"
#include "config/full_system.hh"
#include "cpu/base.hh"
-#include "cpu/cpu_exec_context.hh"
+#include "cpu/simple_thread.hh"
#include "cpu/pc_event.hh"
#include "cpu/sampler/sampler.hh"
#include "cpu/static_inst.hh"
@@ -57,7 +61,7 @@ class Process;
#endif // FULL_SYSTEM
-class ExecContext;
+class ThreadContext;
class Checkpoint;
namespace Trace {
@@ -104,10 +108,13 @@ class BaseSimpleCPU : public BaseCPU
virtual ~BaseSimpleCPU();
public:
- // execution context
- CPUExecContext *cpuXC;
+ /** SimpleThread object, provides all the architectural state. */
+ SimpleThread *thread;
- ExecContext *xcProxy;
+ /** ThreadContext object, provides an interface for external
+ * objects to modify this thread's state.
+ */
+ ThreadContext *tc;
#if FULL_SYSTEM
Addr dbg_vtophys(Addr addr);
@@ -129,7 +136,7 @@ class BaseSimpleCPU : public BaseCPU
StaticInstPtr curStaticInst;
void checkForInterrupts();
- Fault setupFetchPacket(Packet *ifetch_pkt);
+ Fault setupFetchRequest(Request *req);
void preExecute();
void postExecute();
void advancePC(Fault fault);
@@ -213,104 +220,104 @@ class BaseSimpleCPU : public BaseCPU
uint64_t readIntReg(const StaticInst *si, int idx)
{
- return cpuXC->readIntReg(si->srcRegIdx(idx));
+ return thread->readIntReg(si->srcRegIdx(idx));
}
FloatReg readFloatReg(const StaticInst *si, int idx, int width)
{
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return cpuXC->readFloatReg(reg_idx, width);
+ return thread->readFloatReg(reg_idx, width);
}
FloatReg readFloatReg(const StaticInst *si, int idx)
{
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return cpuXC->readFloatReg(reg_idx);
+ return thread->readFloatReg(reg_idx);
}
FloatRegBits readFloatRegBits(const StaticInst *si, int idx, int width)
{
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return cpuXC->readFloatRegBits(reg_idx, width);
+ return thread->readFloatRegBits(reg_idx, width);
}
FloatRegBits readFloatRegBits(const StaticInst *si, int idx)
{
int reg_idx = si->srcRegIdx(idx) - TheISA::FP_Base_DepTag;
- return cpuXC->readFloatRegBits(reg_idx);
+ return thread->readFloatRegBits(reg_idx);
}
void setIntReg(const StaticInst *si, int idx, uint64_t val)
{
- cpuXC->setIntReg(si->destRegIdx(idx), val);
+ thread->setIntReg(si->destRegIdx(idx), val);
}
void setFloatReg(const StaticInst *si, int idx, FloatReg val, int width)
{
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- cpuXC->setFloatReg(reg_idx, val, width);
+ thread->setFloatReg(reg_idx, val, width);
}
void setFloatReg(const StaticInst *si, int idx, FloatReg val)
{
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- cpuXC->setFloatReg(reg_idx, val);
+ thread->setFloatReg(reg_idx, val);
}
void setFloatRegBits(const StaticInst *si, int idx,
FloatRegBits val, int width)
{
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- cpuXC->setFloatRegBits(reg_idx, val, width);
+ thread->setFloatRegBits(reg_idx, val, width);
}
void setFloatRegBits(const StaticInst *si, int idx, FloatRegBits val)
{
int reg_idx = si->destRegIdx(idx) - TheISA::FP_Base_DepTag;
- cpuXC->setFloatRegBits(reg_idx, val);
+ thread->setFloatRegBits(reg_idx, val);
}
- uint64_t readPC() { return cpuXC->readPC(); }
- uint64_t readNextPC() { return cpuXC->readNextPC(); }
- uint64_t readNextNPC() { return cpuXC->readNextNPC(); }
+ uint64_t readPC() { return thread->readPC(); }
+ uint64_t readNextPC() { return thread->readNextPC(); }
+ uint64_t readNextNPC() { return thread->readNextNPC(); }
- void setPC(uint64_t val) { cpuXC->setPC(val); }
- void setNextPC(uint64_t val) { cpuXC->setNextPC(val); }
- void setNextNPC(uint64_t val) { cpuXC->setNextNPC(val); }
+ void setPC(uint64_t val) { thread->setPC(val); }
+ void setNextPC(uint64_t val) { thread->setNextPC(val); }
+ void setNextNPC(uint64_t val) { thread->setNextNPC(val); }
MiscReg readMiscReg(int misc_reg)
{
- return cpuXC->readMiscReg(misc_reg);
+ return thread->readMiscReg(misc_reg);
}
MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
{
- return cpuXC->readMiscRegWithEffect(misc_reg, fault);
+ return thread->readMiscRegWithEffect(misc_reg, fault);
}
Fault setMiscReg(int misc_reg, const MiscReg &val)
{
- return cpuXC->setMiscReg(misc_reg, val);
+ return thread->setMiscReg(misc_reg, val);
}
Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
{
- return cpuXC->setMiscRegWithEffect(misc_reg, val);
+ return thread->setMiscRegWithEffect(misc_reg, val);
}
#if FULL_SYSTEM
- Fault hwrei() { return cpuXC->hwrei(); }
- int readIntrFlag() { return cpuXC->readIntrFlag(); }
- void setIntrFlag(int val) { cpuXC->setIntrFlag(val); }
- bool inPalMode() { return cpuXC->inPalMode(); }
- void ev5_trap(Fault fault) { fault->invoke(xcProxy); }
- bool simPalCheck(int palFunc) { return cpuXC->simPalCheck(palFunc); }
+ Fault hwrei() { return thread->hwrei(); }
+ int readIntrFlag() { return thread->readIntrFlag(); }
+ void setIntrFlag(int val) { thread->setIntrFlag(val); }
+ bool inPalMode() { return thread->inPalMode(); }
+ void ev5_trap(Fault fault) { fault->invoke(tc); }
+ bool simPalCheck(int palFunc) { return thread->simPalCheck(palFunc); }
#else
- void syscall(int64_t callnum) { cpuXC->syscall(callnum); }
+ void syscall(int64_t callnum) { thread->syscall(callnum); }
#endif
- bool misspeculating() { return cpuXC->misspeculating(); }
- ExecContext *xcBase() { return xcProxy; }
+ bool misspeculating() { return thread->misspeculating(); }
+ ThreadContext *tcBase() { return tc; }
};
#endif // __CPU_SIMPLE_BASE_HH__
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index 7cdcdafa1..d5bdcfa9b 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "arch/utility.hh"
@@ -50,11 +52,11 @@ TimingSimpleCPU::init()
BaseCPU::init();
#if FULL_SYSTEM
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
// initialize CPU, including PC
- TheISA::initCPU(xc, xc->readCpuId());
+ TheISA::initCPU(tc, tc->readCpuId());
}
#endif
}
@@ -86,6 +88,8 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
{
_status = Idle;
ifetch_pkt = dcache_pkt = NULL;
+ quiesceEvent = NULL;
+ state = SimObject::Timing;
}
@@ -96,25 +100,54 @@ TimingSimpleCPU::~TimingSimpleCPU()
void
TimingSimpleCPU::serialize(ostream &os)
{
- BaseSimpleCPU::serialize(os);
SERIALIZE_ENUM(_status);
+ BaseSimpleCPU::serialize(os);
}
void
TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
{
- BaseSimpleCPU::unserialize(cp, section);
UNSERIALIZE_ENUM(_status);
+ BaseSimpleCPU::unserialize(cp, section);
+}
+
+bool
+TimingSimpleCPU::quiesce(Event *quiesce_event)
+{
+ // TimingSimpleCPU is ready to quiesce if it's not waiting for
+ // an access to complete.
+ if (status() == Idle || status() == Running || status() == SwitchedOut) {
+ DPRINTF(Config, "Ready to quiesce\n");
+ return false;
+ } else {
+ DPRINTF(Config, "Waiting to quiesce\n");
+ changeState(SimObject::Quiescing);
+ quiesceEvent = quiesce_event;
+ return true;
+ }
}
void
-TimingSimpleCPU::switchOut(Sampler *s)
+TimingSimpleCPU::resume()
{
- sampler = s;
- if (status() == Running) {
- _status = SwitchedOut;
+ if (_status != SwitchedOut && _status != Idle) {
+ Event *e =
+ new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true);
+ e->schedule(curTick);
}
- sampler->signalSwitched();
+}
+
+void
+TimingSimpleCPU::setMemoryMode(State new_mode)
+{
+ assert(new_mode == SimObject::Timing);
+}
+
+void
+TimingSimpleCPU::switchOut()
+{
+ assert(status() == Running || status() == Idle);
+ _status = SwitchedOut;
}
@@ -123,11 +156,11 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
{
BaseCPU::takeOverFrom(oldCPU);
- // if any of this CPU's ExecContexts are active, mark the CPU as
+ // if any of this CPU's ThreadContexts are active, mark the CPU as
// running and schedule its tick event.
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
- if (xc->status() == ExecContext::Active && _status != Running) {
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
break;
}
@@ -139,7 +172,7 @@ void
TimingSimpleCPU::activateContext(int thread_num, int delay)
{
assert(thread_num == 0);
- assert(cpuXC);
+ assert(thread);
assert(_status == Idle);
@@ -156,7 +189,7 @@ void
TimingSimpleCPU::suspendContext(int thread_num)
{
assert(thread_num == 0);
- assert(cpuXC);
+ assert(thread);
assert(_status == Running);
@@ -172,19 +205,17 @@ template <class T>
Fault
TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
{
- Request *data_read_req = new Request(true);
-
- data_read_req->setVaddr(addr);
- data_read_req->setSize(sizeof(T));
- data_read_req->setFlags(flags);
- data_read_req->setTime(curTick);
+ // need to fill in CPU & thread IDs here
+ Request *data_read_req = new Request();
+ data_read_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+ data_read_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
if (traceData) {
traceData->setAddr(data_read_req->getVaddr());
}
// translate to physical address
- Fault fault = cpuXC->translateDataReadReq(data_read_req);
+ Fault fault = thread->translateDataReadReq(data_read_req);
// Now do the access.
if (fault == NoFault) {
@@ -255,14 +286,13 @@ template <class T>
Fault
TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
{
- Request *data_write_req = new Request(true);
- data_write_req->setVaddr(addr);
- data_write_req->setTime(curTick);
- data_write_req->setSize(sizeof(T));
- data_write_req->setFlags(flags);
+ // need to fill in CPU & thread IDs here
+ Request *data_write_req = new Request();
+ data_write_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+ data_write_req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
// translate to physical address
- Fault fault = cpuXC->translateDataWriteReq(data_write_req);
+ Fault fault = thread->translateDataWriteReq(data_write_req);
// Now do the access.
if (fault == NoFault) {
Packet *data_write_pkt =
@@ -340,13 +370,14 @@ TimingSimpleCPU::fetch()
{
checkForInterrupts();
- Request *ifetch_req = new Request(true);
- ifetch_req->setSize(sizeof(MachInst));
+ // need to fill in CPU & thread IDs here
+ Request *ifetch_req = new Request();
+ ifetch_req->setThreadContext(0,0); //Need CPU/Thread IDS HERE
+ Fault fault = setupFetchRequest(ifetch_req);
ifetch_pkt = new Packet(ifetch_req, Packet::ReadReq, Packet::Broadcast);
ifetch_pkt->dataStatic(&inst);
- Fault fault = setupFetchPacket(ifetch_pkt);
if (fault == NoFault) {
if (!icachePort.sendTiming(ifetch_pkt)) {
// Need to wait for retry
@@ -385,11 +416,17 @@ TimingSimpleCPU::completeIfetch(Packet *pkt)
// instruction
assert(pkt->result == Packet::Success);
assert(_status == IcacheWaitResponse);
+
_status = Running;
delete pkt->req;
delete pkt;
+ if (getState() == SimObject::Quiescing) {
+ completeQuiesce();
+ return;
+ }
+
preExecute();
if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) {
// load or store: just send to dcache
@@ -419,17 +456,18 @@ TimingSimpleCPU::IcachePort::recvTiming(Packet *pkt)
return true;
}
-Packet *
+void
TimingSimpleCPU::IcachePort::recvRetry()
{
// we shouldn't get a retry unless we have a packet that we're
// waiting to transmit
assert(cpu->ifetch_pkt != NULL);
assert(cpu->_status == IcacheRetry);
- cpu->_status = IcacheWaitResponse;
Packet *tmp = cpu->ifetch_pkt;
- cpu->ifetch_pkt = NULL;
- return tmp;
+ if (sendTiming(tmp)) {
+ cpu->_status = IcacheWaitResponse;
+ cpu->ifetch_pkt = NULL;
+ }
}
void
@@ -441,6 +479,15 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
assert(_status == DcacheWaitResponse);
_status = Running;
+ if (getState() == SimObject::Quiescing) {
+ completeQuiesce();
+
+ delete pkt->req;
+ delete pkt;
+
+ return;
+ }
+
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
delete pkt->req;
@@ -451,6 +498,13 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt)
}
+void
+TimingSimpleCPU::completeQuiesce()
+{
+ DPRINTF(Config, "Done quiescing\n");
+ changeState(SimObject::QuiescedTiming);
+ quiesceEvent->process();
+}
bool
TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
@@ -459,17 +513,18 @@ TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt)
return true;
}
-Packet *
+void
TimingSimpleCPU::DcachePort::recvRetry()
{
// we shouldn't get a retry unless we have a packet that we're
// waiting to transmit
assert(cpu->dcache_pkt != NULL);
assert(cpu->_status == DcacheRetry);
- cpu->_status = DcacheWaitResponse;
Packet *tmp = cpu->dcache_pkt;
- cpu->dcache_pkt = NULL;
- return tmp;
+ if (sendTiming(tmp)) {
+ cpu->_status = DcacheWaitResponse;
+ cpu->dcache_pkt = NULL;
+ }
}
diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh
index b46631d5a..d91144e4a 100644
--- a/src/cpu/simple/timing.hh
+++ b/src/cpu/simple/timing.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __CPU_SIMPLE_TIMING_HH__
@@ -62,6 +64,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
Status status() const { return _status; }
+ Event *quiesceEvent;
+
private:
class CpuPort : public Port
@@ -100,7 +104,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
virtual bool recvTiming(Packet *pkt);
- virtual Packet *recvRetry();
+ virtual void recvRetry();
};
class DcachePort : public CpuPort
@@ -115,7 +119,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
virtual bool recvTiming(Packet *pkt);
- virtual Packet *recvRetry();
+ virtual void recvRetry();
};
IcachePort icachePort;
@@ -129,7 +133,11 @@ class TimingSimpleCPU : public BaseSimpleCPU
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
- void switchOut(Sampler *s);
+ virtual bool quiesce(Event *quiesce_event);
+ virtual void resume();
+ virtual void setMemoryMode(State new_mode);
+
+ void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
virtual void activateContext(int thread_num, int delay);
@@ -145,6 +153,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
void completeIfetch(Packet *);
void completeDataAccess(Packet *);
void advanceInst(Fault fault);
+ private:
+ void completeQuiesce();
};
#endif // __CPU_SIMPLE_TIMING_HH__
diff --git a/src/cpu/cpu_exec_context.cc b/src/cpu/simple_thread.cc
index b8aa9a67e..db28b23e8 100644
--- a/src/cpu/cpu_exec_context.cc
+++ b/src/cpu/simple_thread.cc
@@ -24,14 +24,19 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
+ * Kevin Lim
*/
#include <string>
#include "arch/isa_traits.hh"
#include "cpu/base.hh"
-#include "cpu/cpu_exec_context.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
#if FULL_SYSTEM
#include "base/callback.hh"
@@ -39,6 +44,7 @@
#include "base/output.hh"
#include "base/trace.hh"
#include "cpu/profile.hh"
+#include "cpu/quiesce_event.hh"
#include "kern/kernel_stats.hh"
#include "sim/serialize.hh"
#include "sim/sim_exit.hh"
@@ -53,23 +59,24 @@ using namespace std;
// constructor
#if FULL_SYSTEM
-CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
- AlphaITB *_itb, AlphaDTB *_dtb)
- : _status(ExecContext::Unallocated), cpu(_cpu), thread_num(_thread_num),
- cpu_id(-1), lastActivate(0), lastSuspend(0), system(_sys), itb(_itb),
- dtb(_dtb), profile(NULL), quiesceEvent(this), func_exe_inst(0),
- storeCondFailures(0)
+SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num, System *_sys,
+ AlphaITB *_itb, AlphaDTB *_dtb,
+ bool use_kernel_stats)
+ : ThreadState(-1, _thread_num), cpu(_cpu), system(_sys), itb(_itb),
+ dtb(_dtb)
{
- proxy = new ProxyExecContext<CPUExecContext>(this);
+ tc = new ProxyThreadContext<SimpleThread>(this);
+
+ quiesceEvent = new EndQuiesceEvent(tc);
regs.clear();
if (cpu->params->profile) {
profile = new FunctionProfile(system->kernelSymtab);
Callback *cb =
- new MakeCallback<CPUExecContext,
- &CPUExecContext::dumpFuncProfile>(this);
+ new MakeCallback<SimpleThread,
+ &SimpleThread::dumpFuncProfile>(this);
registerExitCallback(cb);
}
@@ -79,98 +86,59 @@ CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_sys,
profileNode = &dummyNode;
profilePC = 3;
+ if (use_kernel_stats) {
+ kernelStats = new Kernel::Statistics(system);
+ } else {
+ kernelStats = NULL;
+ }
Port *mem_port;
physPort = new FunctionalPort(csprintf("%s-%d-funcport",
- cpu->name(), thread_num));
+ cpu->name(), tid));
mem_port = system->physmem->getPort("functional");
mem_port->setPeer(physPort);
physPort->setPeer(mem_port);
virtPort = new VirtualPort(csprintf("%s-%d-vport",
- cpu->name(), thread_num));
+ cpu->name(), tid));
mem_port = system->physmem->getPort("functional");
mem_port->setPeer(virtPort);
virtPort->setPeer(mem_port);
}
#else
-CPUExecContext::CPUExecContext(BaseCPU *_cpu, int _thread_num,
+SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num,
Process *_process, int _asid, MemObject* memobj)
- : _status(ExecContext::Unallocated),
- cpu(_cpu), thread_num(_thread_num), cpu_id(-1), lastActivate(0),
- lastSuspend(0), process(_process), asid(_asid),
- func_exe_inst(0), storeCondFailures(0)
+ : ThreadState(-1, _thread_num, _process, _asid, memobj),
+ cpu(_cpu)
{
/* Use this port to for syscall emulation writes to memory. */
Port *mem_port;
port = new TranslatingPort(csprintf("%s-%d-funcport",
- cpu->name(), thread_num),
+ cpu->name(), tid),
process->pTable, false);
mem_port = memobj->getPort("functional");
mem_port->setPeer(port);
port->setPeer(mem_port);
regs.clear();
- proxy = new ProxyExecContext<CPUExecContext>(this);
+ tc = new ProxyThreadContext<SimpleThread>(this);
}
-CPUExecContext::CPUExecContext(RegFile *regFile)
- : cpu(NULL), thread_num(-1), process(NULL), asid(-1),
- func_exe_inst(0), storeCondFailures(0)
+SimpleThread::SimpleThread(RegFile *regFile)
+ : ThreadState(-1, -1, NULL, -1, NULL), cpu(NULL)
{
regs = *regFile;
- proxy = new ProxyExecContext<CPUExecContext>(this);
+ tc = new ProxyThreadContext<SimpleThread>(this);
}
#endif
-CPUExecContext::~CPUExecContext()
-{
- delete proxy;
-}
-
-#if FULL_SYSTEM
-void
-CPUExecContext::dumpFuncProfile()
-{
- std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
- profile->dump(proxy, *os);
-}
-
-CPUExecContext::EndQuiesceEvent::EndQuiesceEvent(CPUExecContext *_cpuXC)
- : Event(&mainEventQueue), cpuXC(_cpuXC)
-{
-}
-
-void
-CPUExecContext::EndQuiesceEvent::process()
-{
- cpuXC->activate();
-}
-
-const char*
-CPUExecContext::EndQuiesceEvent::description()
-{
- return "End Quiesce Event.";
-}
-
-void
-CPUExecContext::profileClear()
-{
- if (profile)
- profile->clear();
-}
-
-void
-CPUExecContext::profileSample()
+SimpleThread::~SimpleThread()
{
- if (profile)
- profile->sample(profileNode, profilePC);
+ delete tc;
}
-#endif
-
void
-CPUExecContext::takeOverFrom(ExecContext *oldContext)
+SimpleThread::takeOverFrom(ThreadContext *oldContext)
{
// some things should already be set up
#if FULL_SYSTEM
@@ -182,69 +150,97 @@ CPUExecContext::takeOverFrom(ExecContext *oldContext)
// copy over functional state
_status = oldContext->status();
copyArchRegs(oldContext);
- cpu_id = oldContext->readCpuId();
+ cpuId = oldContext->readCpuId();
#if !FULL_SYSTEM
- func_exe_inst = oldContext->readFuncExeInst();
+ funcExeInst = oldContext->readFuncExeInst();
+#else
+ EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
+ if (quiesce) {
+ // Point the quiesce event's TC at this TC so that it wakes up
+ // the proper CPU.
+ quiesce->tc = tc;
+ }
+ if (quiesceEvent) {
+ quiesceEvent->tc = tc;
+ }
#endif
storeCondFailures = 0;
- oldContext->setStatus(ExecContext::Unallocated);
+ oldContext->setStatus(ThreadContext::Unallocated);
}
void
-CPUExecContext::serialize(ostream &os)
+SimpleThread::serialize(ostream &os)
{
SERIALIZE_ENUM(_status);
regs.serialize(os);
// thread_num and cpu_id are deterministic from the config
- SERIALIZE_SCALAR(func_exe_inst);
+ SERIALIZE_SCALAR(funcExeInst);
SERIALIZE_SCALAR(inst);
#if FULL_SYSTEM
Tick quiesceEndTick = 0;
- if (quiesceEvent.scheduled())
- quiesceEndTick = quiesceEvent.when();
+ if (quiesceEvent->scheduled())
+ quiesceEndTick = quiesceEvent->when();
SERIALIZE_SCALAR(quiesceEndTick);
-
+ if (kernelStats)
+ kernelStats->serialize(os);
#endif
}
void
-CPUExecContext::unserialize(Checkpoint *cp, const std::string &section)
+SimpleThread::unserialize(Checkpoint *cp, const std::string &section)
{
UNSERIALIZE_ENUM(_status);
regs.unserialize(cp, section);
// thread_num and cpu_id are deterministic from the config
- UNSERIALIZE_SCALAR(func_exe_inst);
+ UNSERIALIZE_SCALAR(funcExeInst);
UNSERIALIZE_SCALAR(inst);
#if FULL_SYSTEM
Tick quiesceEndTick;
UNSERIALIZE_SCALAR(quiesceEndTick);
if (quiesceEndTick)
- quiesceEvent.schedule(quiesceEndTick);
+ quiesceEvent->schedule(quiesceEndTick);
+ if (kernelStats)
+ kernelStats->unserialize(cp, section);
#endif
}
+#if FULL_SYSTEM
+void
+SimpleThread::dumpFuncProfile()
+{
+ std::ostream *os = simout.create(csprintf("profile.%s.dat", cpu->name()));
+ profile->dump(tc, *os);
+}
+#endif
void
-CPUExecContext::activate(int delay)
+SimpleThread::activate(int delay)
{
- if (status() == ExecContext::Active)
+ if (status() == ThreadContext::Active)
return;
lastActivate = curTick;
- _status = ExecContext::Active;
- cpu->activateContext(thread_num, delay);
+ if (status() == ThreadContext::Unallocated) {
+ cpu->activateWhenReady(tid);
+ return;
+ }
+
+ _status = ThreadContext::Active;
+
+ // status() == Suspended
+ cpu->activateContext(tid, delay);
}
void
-CPUExecContext::suspend()
+SimpleThread::suspend()
{
- if (status() == ExecContext::Suspended)
+ if (status() == ThreadContext::Suspended)
return;
lastActivate = curTick;
@@ -253,58 +249,62 @@ CPUExecContext::suspend()
#if FULL_SYSTEM
// Don't change the status from active if there are pending interrupts
if (cpu->check_interrupts()) {
- assert(status() == ExecContext::Active);
+ assert(status() == ThreadContext::Active);
return;
}
#endif
*/
- _status = ExecContext::Suspended;
- cpu->suspendContext(thread_num);
+ _status = ThreadContext::Suspended;
+ cpu->suspendContext(tid);
}
void
-CPUExecContext::deallocate()
+SimpleThread::deallocate()
{
- if (status() == ExecContext::Unallocated)
+ if (status() == ThreadContext::Unallocated)
return;
- _status = ExecContext::Unallocated;
- cpu->deallocateContext(thread_num);
+ _status = ThreadContext::Unallocated;
+ cpu->deallocateContext(tid);
}
void
-CPUExecContext::halt()
+SimpleThread::halt()
{
- if (status() == ExecContext::Halted)
+ if (status() == ThreadContext::Halted)
return;
- _status = ExecContext::Halted;
- cpu->haltContext(thread_num);
+ _status = ThreadContext::Halted;
+ cpu->haltContext(tid);
}
void
-CPUExecContext::regStats(const string &name)
+SimpleThread::regStats(const string &name)
{
+#if FULL_SYSTEM
+ if (kernelStats)
+ kernelStats->regStats(name + ".kern");
+#endif
}
void
-CPUExecContext::copyArchRegs(ExecContext *xc)
+SimpleThread::copyArchRegs(ThreadContext *src_tc)
{
- TheISA::copyRegs(xc, proxy);
+ TheISA::copyRegs(src_tc, tc);
}
#if FULL_SYSTEM
VirtualPort*
-CPUExecContext::getVirtPort(ExecContext *xc)
+SimpleThread::getVirtPort(ThreadContext *src_tc)
{
- if (!xc)
+ if (!src_tc)
return virtPort;
VirtualPort *vp;
Port *mem_port;
- vp = new VirtualPort("xc-vport", xc);
+ vp = new VirtualPort("tc-vport", src_tc);
mem_port = system->physmem->getPort("functional");
mem_port->setPeer(vp);
vp->setPeer(mem_port);
@@ -312,11 +312,12 @@ CPUExecContext::getVirtPort(ExecContext *xc)
}
void
-CPUExecContext::delVirtPort(VirtualPort *vp)
+SimpleThread::delVirtPort(VirtualPort *vp)
{
-// assert(!vp->nullExecContext());
- delete vp->getPeer();
- delete vp;
+ if (vp != virtPort) {
+ delete vp->getPeer();
+ delete vp;
+ }
}
diff --git a/src/cpu/cpu_exec_context.hh b/src/cpu/simple_thread.hh
index 2c06a7b3b..de65e9891 100644
--- a/src/cpu/cpu_exec_context.hh
+++ b/src/cpu/simple_thread.hh
@@ -24,14 +24,18 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __CPU_CPU_EXEC_CONTEXT_HH__
-#define __CPU_CPU_EXEC_CONTEXT_HH__
+#ifndef __CPU_SIMPLE_THREAD_HH__
+#define __CPU_SIMPLE_THREAD_HH__
#include "arch/isa_traits.hh"
#include "config/full_system.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/thread_state.hh"
#include "mem/physical.hh"
#include "mem/request.hh"
#include "sim/byteswap.hh"
@@ -51,6 +55,9 @@ class ProfileNode;
class FunctionalPort;
class PhysicalPort;
+namespace Kernel {
+ class Statistics;
+};
#else // !FULL_SYSTEM
@@ -58,16 +65,25 @@ class PhysicalPort;
#include "mem/page_table.hh"
class TranslatingPort;
-
#endif // FULL_SYSTEM
-//
-// The CPUExecContext object represents a functional context for
-// instruction execution. It incorporates everything required for
-// architecture-level functional simulation of a single thread.
-//
+/**
+ * The SimpleThread object provides a combination of the ThreadState
+ * object and the ThreadContext interface. It implements the
+ * ThreadContext interface so that a ProxyThreadContext class can be
+ * made using SimpleThread as the template parameter (see
+ * thread_context.hh). It adds to the ThreadState object by adding all
+ * the objects needed for simple functional execution, including a
+ * simple architectural register file, and pointers to the ITB and DTB
+ * in full system mode. For CPU models that do not need more advanced
+ * ways to hold state (i.e. a separate physical register file, or
+ * separate fetch and commit PC's), this SimpleThread class provides
+ * all the necessary state for full architecture-level functional
+ * simulation. See the AtomicSimpleCPU or TimingSimpleCPU for
+ * examples.
+ */
-class CPUExecContext
+class SimpleThread : public ThreadState
{
protected:
typedef TheISA::RegFile RegFile;
@@ -77,202 +93,83 @@ class CPUExecContext
typedef TheISA::FloatReg FloatReg;
typedef TheISA::FloatRegBits FloatRegBits;
public:
- typedef ExecContext::Status Status;
-
- private:
- Status _status;
-
- public:
- Status status() const { return _status; }
-
- void setStatus(Status newStatus) { _status = newStatus; }
-
- /// Set the status to Active. Optional delay indicates number of
- /// cycles to wait before beginning execution.
- void activate(int delay = 1);
-
- /// Set the status to Suspended.
- void suspend();
-
- /// Set the status to Unallocated.
- void deallocate();
-
- /// Set the status to Halted.
- void halt();
+ typedef ThreadContext::Status Status;
protected:
RegFile regs; // correct-path register context
public:
- // pointer to CPU associated with this context
+ // pointer to CPU associated with this SimpleThread
BaseCPU *cpu;
- ProxyExecContext<CPUExecContext> *proxy;
-
- // Current instruction
- MachInst inst;
-
- // Index of hardware thread context on the CPU that this represents.
- int thread_num;
-
- // ID of this context w.r.t. the System or Process object to which
- // it belongs. For full-system mode, this is the system CPU ID.
- int cpu_id;
-
- Tick lastActivate;
- Tick lastSuspend;
+ ProxyThreadContext<SimpleThread> *tc;
System *system;
-
#if FULL_SYSTEM
AlphaITB *itb;
AlphaDTB *dtb;
-
- /** A functional port outgoing only for functional accesses to physical
- * addresses.*/
- FunctionalPort *physPort;
-
- /** A functional port, outgoing only, for functional accesse to virtual
- * addresses. That doen't require execution context information */
- VirtualPort *virtPort;
-
- FunctionProfile *profile;
- ProfileNode *profileNode;
- Addr profilePC;
- void dumpFuncProfile();
-
- /** Event for timing out quiesce instruction */
- struct EndQuiesceEvent : public Event
- {
- /** A pointer to the execution context that is quiesced */
- CPUExecContext *cpuXC;
-
- EndQuiesceEvent(CPUExecContext *_cpuXC);
-
- /** Event process to occur at interrupt*/
- virtual void process();
-
- /** Event description */
- virtual const char *description();
- };
- EndQuiesceEvent quiesceEvent;
-
- Event *getQuiesceEvent() { return &quiesceEvent; }
-
- Tick readLastActivate() { return lastActivate; }
-
- Tick readLastSuspend() { return lastSuspend; }
-
- void profileClear();
-
- void profileSample();
-
-#else
- /// Port that syscalls can use to access memory (provides translation step).
- TranslatingPort *port;
-
- Process *process;
-
- // Address space ID. Note that this is used for TIMING cache
- // simulation only; all functional memory accesses should use
- // one of the FunctionalMemory pointers above.
- short asid;
-
#endif
- /**
- * Temporary storage to pass the source address from copy_load to
- * copy_store.
- * @todo Remove this temporary when we have a better way to do it.
- */
- Addr copySrcAddr;
- /**
- * Temp storage for the physical source address of a copy.
- * @todo Remove this temporary when we have a better way to do it.
- */
- Addr copySrcPhysAddr;
-
-
- /*
- * number of executed instructions, for matching with syscall trace
- * points in EIO files.
- */
- Counter func_exe_inst;
-
- //
- // Count failed store conditionals so we can warn of apparent
- // application deadlock situations.
- unsigned storeCondFailures;
-
- // constructor: initialize context from given process structure
+ // constructor: initialize SimpleThread from given process structure
#if FULL_SYSTEM
- CPUExecContext(BaseCPU *_cpu, int _thread_num, System *_system,
- AlphaITB *_itb, AlphaDTB *_dtb);
+ SimpleThread(BaseCPU *_cpu, int _thread_num, System *_system,
+ AlphaITB *_itb, AlphaDTB *_dtb,
+ bool use_kernel_stats = true);
#else
- CPUExecContext(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
- MemObject *memobj);
- // Constructor to use XC to pass reg file around. Not used for anything
- // else.
- CPUExecContext(RegFile *regFile);
+ SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
+ MemObject *memobj);
+ // Constructor to use SimpleThread to pass reg file around. Not
+ // used for anything else.
+ SimpleThread(RegFile *regFile);
#endif
- virtual ~CPUExecContext();
+ virtual ~SimpleThread();
- virtual void takeOverFrom(ExecContext *oldContext);
+ virtual void takeOverFrom(ThreadContext *oldContext);
void regStats(const std::string &name);
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
- BaseCPU *getCpuPtr() { return cpu; }
-
- ExecContext *getProxy() { return proxy; }
+ /***************************************************************
+ * SimpleThread functions to provide CPU with access to various
+ * state, and to provide address translation methods.
+ **************************************************************/
- int getThreadNum() { return thread_num; }
+ /** Returns the pointer to this SimpleThread's ThreadContext. Used
+ * when a ThreadContext must be passed to objects outside of the
+ * CPU.
+ */
+ ThreadContext *getTC() { return tc; }
#if FULL_SYSTEM
- System *getSystemPtr() { return system; }
-
- AlphaITB *getITBPtr() { return itb; }
-
- AlphaDTB *getDTBPtr() { return dtb; }
-
int getInstAsid() { return regs.instAsid(); }
int getDataAsid() { return regs.dataAsid(); }
Fault translateInstReq(RequestPtr &req)
{
- return itb->translate(req, proxy);
+ return itb->translate(req, tc);
}
Fault translateDataReadReq(RequestPtr &req)
{
- return dtb->translate(req, proxy, false);
+ return dtb->translate(req, tc, false);
}
Fault translateDataWriteReq(RequestPtr &req)
{
- return dtb->translate(req, proxy, true);
+ return dtb->translate(req, tc, true);
}
- FunctionalPort *getPhysPort() { return physPort; }
-
- /** Return a virtual port. If no exec context is specified then a static
- * port is returned. Otherwise a port is created and returned. It must be
- * deleted by deleteVirtPort(). */
- VirtualPort *getVirtPort(ExecContext *xc);
+ void dumpFuncProfile();
- void delVirtPort(VirtualPort *vp);
+ int readIntrFlag() { return regs.intrflag; }
+ void setIntrFlag(int val) { regs.intrflag = val; }
+ Fault hwrei();
+ bool simPalCheck(int palFunc);
#else
- TranslatingPort *getMemPort() { return port; }
-
- Process *getProcessPtr() { return process; }
-
- int getInstAsid() { return asid; }
- int getDataAsid() { return asid; }
-
Fault translateInstReq(RequestPtr &req)
{
return process->pTable->translate(req);
@@ -287,9 +184,50 @@ class CPUExecContext
{
return process->pTable->translate(req);
}
+#endif
+
+ /*******************************************
+ * ThreadContext interface functions.
+ ******************************************/
+
+ BaseCPU *getCpuPtr() { return cpu; }
+
+ int getThreadNum() { return tid; }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return system; }
+
+ AlphaITB *getITBPtr() { return itb; }
+
+ AlphaDTB *getDTBPtr() { return dtb; }
+
+ 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);
#endif
+ Status status() const { return _status; }
+
+ void setStatus(Status newStatus) { _status = newStatus; }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1);
+
+ /// Set the status to Suspended.
+ void suspend();
+
+ /// Set the status to Unallocated.
+ void deallocate();
+
+ /// Set the status to Halted.
+ void halt();
+
/*
template <class T>
Fault read(RequestPtr &req, T &data)
@@ -361,14 +299,6 @@ class CPUExecContext
*/
virtual bool misspeculating();
-
- MachInst getInst() { return inst; }
-
- void setInst(MachInst new_inst)
- {
- inst = new_inst;
- }
-
Fault instRead(RequestPtr &req)
{
panic("instRead not implemented");
@@ -376,11 +306,9 @@ class CPUExecContext
return NoFault;
}
- void setCpuId(int id) { cpu_id = id; }
-
- int readCpuId() { return cpu_id; }
+ void copyArchRegs(ThreadContext *tc);
- void copyArchRegs(ExecContext *xc);
+ void clearArchRegs() { regs.clear(); }
//
// New accessors for new decoder.
@@ -465,7 +393,6 @@ class CPUExecContext
regs.setNextNPC(val);
}
-
MiscReg readMiscReg(int misc_reg)
{
return regs.readMiscReg(misc_reg);
@@ -473,7 +400,7 @@ class CPUExecContext
MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
{
- return regs.readMiscRegWithEffect(misc_reg, fault, proxy);
+ return regs.readMiscRegWithEffect(misc_reg, fault, tc);
}
Fault setMiscReg(int misc_reg, const MiscReg &val)
@@ -483,7 +410,7 @@ class CPUExecContext
Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
{
- return regs.setMiscRegWithEffect(misc_reg, val, proxy);
+ return regs.setMiscRegWithEffect(misc_reg, val, tc);
}
unsigned readStCondFailures() { return storeCondFailures; }
@@ -491,14 +418,8 @@ class CPUExecContext
void setStCondFailures(unsigned sc_failures)
{ storeCondFailures = sc_failures; }
- void clearArchRegs() { regs.clear(); }
-
#if FULL_SYSTEM
- int readIntrFlag() { return regs.intrflag; }
- void setIntrFlag(int val) { regs.intrflag = val; }
- Fault hwrei();
bool inPalMode() { return AlphaISA::PcPAL(regs.readPC()); }
- bool simPalCheck(int palFunc);
#endif
#if !FULL_SYSTEM
@@ -520,12 +441,8 @@ class CPUExecContext
void syscall(int64_t callnum)
{
- process->syscall(callnum, proxy);
+ process->syscall(callnum, tc);
}
-
- Counter readFuncExeInst() { return func_exe_inst; }
-
- void setFuncExeInst(Counter new_val) { func_exe_inst = new_val; }
#endif
void changeRegFileContext(RegFile::ContextParam param,
@@ -538,7 +455,7 @@ class CPUExecContext
// for non-speculative execution context, spec_mode is always false
inline bool
-CPUExecContext::misspeculating()
+SimpleThread::misspeculating()
{
return false;
}
diff --git a/src/cpu/smt.hh b/src/cpu/smt.hh
index 9c52abf95..cac1a8fd5 100644
--- a/src/cpu/smt.hh
+++ b/src/cpu/smt.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
diff --git a/src/cpu/static_inst.cc b/src/cpu/static_inst.cc
index c307dc6fc..c311d2282 100644
--- a/src/cpu/static_inst.cc
+++ b/src/cpu/static_inst.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <iostream>
@@ -57,7 +60,7 @@ StaticInst::dumpDecodeCacheStats()
}
bool
-StaticInst::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const
+StaticInst::hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const
{
if (isDirectCtrl()) {
tgt = branchTarget(pc);
@@ -65,7 +68,7 @@ StaticInst::hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const
}
if (isIndirectCtrl()) {
- tgt = branchTarget(xc);
+ tgt = branchTarget(tc);
return true;
}
diff --git a/src/cpu/static_inst.hh b/src/cpu/static_inst.hh
index 33c9144fb..a98078634 100644
--- a/src/cpu/static_inst.hh
+++ b/src/cpu/static_inst.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __CPU_STATIC_INST_HH__
@@ -32,6 +34,7 @@
#include <bitset>
#include <string>
+#include "base/bitfield.hh"
#include "base/hashmap.hh"
#include "base/misc.hh"
#include "base/refcnt.hh"
@@ -41,13 +44,19 @@
// forward declarations
struct AlphaSimpleImpl;
-class ExecContext;
+struct OzoneImpl;
+struct SimpleImpl;
+class ThreadContext;
class DynInst;
class Packet;
template <class Impl>
class AlphaDynInst;
+template <class Impl>
+class OzoneDynInst;
+
+class CheckerCPU;
class FastCPU;
class AtomicSimpleCPU;
class TimingSimpleCPU;
@@ -100,6 +109,7 @@ class StaticInstBase : public RefCounted
IsMemRef, ///< References memory (load, store, or prefetch).
IsLoad, ///< Reads from memory (load or prefetch).
IsStore, ///< Writes to memory.
+ IsStoreConditional, ///< Store conditional instruction.
IsInstPrefetch, ///< Instruction-cache prefetch.
IsDataPrefetch, ///< Data-cache prefetch.
IsCopy, ///< Fast Cache block copy
@@ -124,6 +134,10 @@ class StaticInstBase : public RefCounted
IsWriteBarrier, ///< Is a write barrier
IsNonSpeculative, ///< Should not be executed speculatively
+ IsQuiesce, ///< Is a quiesce instruction
+
+ IsIprAccess, ///< Accesses IPRs
+ IsUnverifiable, ///< Can't be verified by a checker
NumFlags
};
@@ -187,6 +201,7 @@ class StaticInstBase : public RefCounted
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];}
@@ -211,6 +226,9 @@ class StaticInstBase : public RefCounted
bool isMemBarrier() const { return flags[IsMemBarrier]; }
bool isWriteBarrier() const { return flags[IsWriteBarrier]; }
bool isNonSpeculative() const { return flags[IsNonSpeculative]; }
+ bool isQuiesce() const { return flags[IsQuiesce]; }
+ bool isIprAccess() const { return flags[IsIprAccess]; }
+ bool isUnverifiable() const { return flags[IsUnverifiable]; }
//@}
/// Operation class. Used to select appropriate function unit in issue.
@@ -340,12 +358,12 @@ class StaticInst : public StaticInstBase
/**
* Return the target address for an indirect branch (jump). The
- * register value is read from the supplied execution context, so
- * the result is valid only if the execution context is about to
+ * register value is read from the supplied thread context, so
+ * the result is valid only if the thread context is about to
* execute the branch in question. Invalid if not an indirect
* branch (i.e. isIndirectCtrl() should be true).
*/
- virtual Addr branchTarget(ExecContext *xc) const
+ virtual Addr branchTarget(ThreadContext *tc) const
{
panic("StaticInst::branchTarget() called on instruction "
"that is not an indirect branch.");
@@ -355,7 +373,7 @@ class StaticInst : public StaticInstBase
* Return true if the instruction is a control transfer, and if so,
* return the target address as well.
*/
- bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const;
+ bool hasBranchTarget(Addr pc, ThreadContext *tc, Addr &tgt) const;
/**
* Return string representation of disassembled instruction.
@@ -394,16 +412,10 @@ class StaticInst : public StaticInstBase
//This is defined as inline below.
static StaticInstPtr decode(ExtMachInst mach_inst);
- //MIPS Decoder Debug Functions
- int getOpcode() { return (machInst & 0xFC000000) >> 26 ; }//31..26
- int getRs() { return (machInst & 0x03E00000) >> 21; } //25...21
- int getRt() { return (machInst & 0x001F0000) >> 16; } //20...16
- int getRd() { return (machInst & 0x0000F800) >> 11; } //15...11
- int getImm() { return (machInst & 0x0000FFFF); } //15...0
- int getFunction(){ return (machInst & 0x0000003F); }//5...0
- int getBranch(){ return (machInst & 0x0000FFFF); }//15...0
- int getJump(){ return (machInst & 0x03FFFFFF); }//5...0
- int getHint(){ return (machInst & 0x000007C0) >> 6; } //10...6
+ /// Return opcode of machine instruction
+ uint32_t getOpcode() { return bits(machInst, 31, 26);}
+
+ /// Return name of machine instruction
std::string getName() { return mnemonic; }
};
diff --git a/src/cpu/thread_context.hh b/src/cpu/thread_context.hh
new file mode 100644
index 000000000..70d705144
--- /dev/null
+++ b/src/cpu/thread_context.hh
@@ -0,0 +1,448 @@
+/*
+ * 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_THREAD_CONTEXT_HH__
+#define __CPU_THREAD_CONTEXT_HH__
+
+#include "config/full_system.hh"
+#include "mem/request.hh"
+#include "sim/faults.hh"
+#include "sim/host.hh"
+#include "sim/serialize.hh"
+#include "sim/byteswap.hh"
+
+// @todo: Figure out a more architecture independent way to obtain the ITB and
+// DTB pointers.
+class AlphaDTB;
+class AlphaITB;
+class BaseCPU;
+class EndQuiesceEvent;
+class Event;
+class TranslatingPort;
+class FunctionalPort;
+class VirtualPort;
+class Process;
+class System;
+namespace Kernel {
+ class Statistics;
+};
+
+/**
+ * ThreadContext is the external interface to all thread state for
+ * anything outside of the CPU. It provides all accessor methods to
+ * state that might be needed by external objects, ranging from
+ * register values to things such as kernel stats. It is an abstract
+ * base class; the CPU can create its own ThreadContext by either
+ * deriving from it, or using the templated ProxyThreadContext.
+ *
+ * The ThreadContext is slightly different than the ExecContext. The
+ * ThreadContext provides access to an individual thread's state; an
+ * ExecContext provides ISA access to the CPU (meaning it is
+ * implicitly multithreaded on SMT systems). Additionally the
+ * ThreadState is an abstract class that exactly defines the
+ * interface; the ExecContext is a more implicit interface that must
+ * be implemented so that the ISA can access whatever state it needs.
+ */
+class ThreadContext
+{
+ protected:
+ typedef TheISA::RegFile RegFile;
+ typedef TheISA::MachInst MachInst;
+ typedef TheISA::IntReg IntReg;
+ typedef TheISA::FloatReg FloatReg;
+ typedef TheISA::FloatRegBits FloatRegBits;
+ typedef TheISA::MiscRegFile MiscRegFile;
+ typedef TheISA::MiscReg MiscReg;
+ public:
+ enum Status
+ {
+ /// Initialized but not running yet. All CPUs start in
+ /// this state, but most transition to Active on cycle 1.
+ /// In MP or SMT systems, non-primary contexts will stay
+ /// in this state until a thread is assigned to them.
+ Unallocated,
+
+ /// Running. Instructions should be executed only when
+ /// the context is in this state.
+ Active,
+
+ /// Temporarily inactive. Entered while waiting for
+ /// synchronization, etc.
+ Suspended,
+
+ /// Permanently shut down. Entered when target executes
+ /// m5exit pseudo-instruction. When all contexts enter
+ /// this state, the simulation will terminate.
+ Halted
+ };
+
+ virtual ~ThreadContext() { };
+
+ virtual BaseCPU *getCpuPtr() = 0;
+
+ virtual void setCpuId(int id) = 0;
+
+ virtual int readCpuId() = 0;
+
+#if FULL_SYSTEM
+ virtual System *getSystemPtr() = 0;
+
+ virtual AlphaITB *getITBPtr() = 0;
+
+ virtual AlphaDTB * getDTBPtr() = 0;
+
+ virtual Kernel::Statistics *getKernelStats() = 0;
+
+ virtual FunctionalPort *getPhysPort() = 0;
+
+ virtual VirtualPort *getVirtPort(ThreadContext *tc = NULL) = 0;
+
+ virtual void delVirtPort(VirtualPort *vp) = 0;
+#else
+ virtual TranslatingPort *getMemPort() = 0;
+
+ virtual Process *getProcessPtr() = 0;
+#endif
+
+ virtual Status status() const = 0;
+
+ virtual void setStatus(Status new_status) = 0;
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ virtual void activate(int delay = 1) = 0;
+
+ /// Set the status to Suspended.
+ virtual void suspend() = 0;
+
+ /// Set the status to Unallocated.
+ virtual void deallocate() = 0;
+
+ /// Set the status to Halted.
+ virtual void halt() = 0;
+
+#if FULL_SYSTEM
+ virtual void dumpFuncProfile() = 0;
+#endif
+
+ virtual void takeOverFrom(ThreadContext *old_context) = 0;
+
+ virtual void regStats(const std::string &name) = 0;
+
+ virtual void serialize(std::ostream &os) = 0;
+ virtual void unserialize(Checkpoint *cp, const std::string &section) = 0;
+
+#if FULL_SYSTEM
+ virtual EndQuiesceEvent *getQuiesceEvent() = 0;
+
+ // Not necessarily the best location for these...
+ // Having an extra function just to read these is obnoxious
+ virtual Tick readLastActivate() = 0;
+ virtual Tick readLastSuspend() = 0;
+
+ virtual void profileClear() = 0;
+ virtual void profileSample() = 0;
+#endif
+
+ virtual int getThreadNum() = 0;
+
+ // Also somewhat obnoxious. Really only used for the TLB fault.
+ // However, may be quite useful in SPARC.
+ virtual TheISA::MachInst getInst() = 0;
+
+ virtual void copyArchRegs(ThreadContext *tc) = 0;
+
+ virtual void clearArchRegs() = 0;
+
+ //
+ // New accessors for new decoder.
+ //
+ virtual uint64_t readIntReg(int reg_idx) = 0;
+
+ virtual FloatReg readFloatReg(int reg_idx, int width) = 0;
+
+ virtual FloatReg readFloatReg(int reg_idx) = 0;
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx, int width) = 0;
+
+ virtual FloatRegBits readFloatRegBits(int reg_idx) = 0;
+
+ virtual void setIntReg(int reg_idx, uint64_t val) = 0;
+
+ virtual void setFloatReg(int reg_idx, FloatReg val, int width) = 0;
+
+ virtual void setFloatReg(int reg_idx, FloatReg val) = 0;
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val) = 0;
+
+ virtual void setFloatRegBits(int reg_idx, FloatRegBits val, int width) = 0;
+
+ virtual uint64_t readPC() = 0;
+
+ virtual void setPC(uint64_t val) = 0;
+
+ virtual uint64_t readNextPC() = 0;
+
+ virtual void setNextPC(uint64_t val) = 0;
+
+ virtual uint64_t readNextNPC() = 0;
+
+ virtual void setNextNPC(uint64_t val) = 0;
+
+ virtual MiscReg readMiscReg(int misc_reg) = 0;
+
+ virtual MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault) = 0;
+
+ virtual Fault setMiscReg(int misc_reg, const MiscReg &val) = 0;
+
+ virtual Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val) = 0;
+
+ // Also not necessarily the best location for these two. Hopefully will go
+ // away once we decide upon where st cond failures goes.
+ virtual unsigned readStCondFailures() = 0;
+
+ virtual void setStCondFailures(unsigned sc_failures) = 0;
+
+#if FULL_SYSTEM
+ virtual bool inPalMode() = 0;
+#endif
+
+ // Only really makes sense for old CPU model. Still could be useful though.
+ virtual bool misspeculating() = 0;
+
+#if !FULL_SYSTEM
+ virtual IntReg getSyscallArg(int i) = 0;
+
+ // used to shift args for indirect syscall
+ virtual void setSyscallArg(int i, IntReg val) = 0;
+
+ virtual void setSyscallReturn(SyscallReturn return_value) = 0;
+
+ // Same with st cond failures.
+ virtual Counter readFuncExeInst() = 0;
+
+ // 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 calls the exit syscall.
+ virtual int exit() { return 1; };
+#endif
+
+ virtual void changeRegFileContext(RegFile::ContextParam param,
+ RegFile::ContextVal val) = 0;
+};
+
+/**
+ * ProxyThreadContext class that provides a way to implement a
+ * ThreadContext without having to derive from it. ThreadContext is an
+ * abstract class, so anything that derives from it and uses its
+ * interface will pay the overhead of virtual function calls. This
+ * class is created to enable a user-defined Thread object to be used
+ * wherever ThreadContexts are used, without paying the overhead of
+ * virtual function calls when it is used by itself. See
+ * simple_thread.hh for an example of this.
+ */
+template <class TC>
+class ProxyThreadContext : public ThreadContext
+{
+ public:
+ ProxyThreadContext(TC *actual_tc)
+ { actualTC = actual_tc; }
+
+ private:
+ TC *actualTC;
+
+ public:
+
+ BaseCPU *getCpuPtr() { return actualTC->getCpuPtr(); }
+
+ void setCpuId(int id) { actualTC->setCpuId(id); }
+
+ int readCpuId() { return actualTC->readCpuId(); }
+
+#if FULL_SYSTEM
+ System *getSystemPtr() { return actualTC->getSystemPtr(); }
+
+ AlphaITB *getITBPtr() { return actualTC->getITBPtr(); }
+
+ AlphaDTB *getDTBPtr() { return actualTC->getDTBPtr(); }
+
+ 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); }
+#else
+ TranslatingPort *getMemPort() { return actualTC->getMemPort(); }
+
+ Process *getProcessPtr() { return actualTC->getProcessPtr(); }
+#endif
+
+ Status status() const { return actualTC->status(); }
+
+ void setStatus(Status new_status) { actualTC->setStatus(new_status); }
+
+ /// Set the status to Active. Optional delay indicates number of
+ /// cycles to wait before beginning execution.
+ void activate(int delay = 1) { actualTC->activate(delay); }
+
+ /// Set the status to Suspended.
+ void suspend() { actualTC->suspend(); }
+
+ /// Set the status to Unallocated.
+ void deallocate() { actualTC->deallocate(); }
+
+ /// Set the status to Halted.
+ void halt() { actualTC->halt(); }
+
+#if FULL_SYSTEM
+ void dumpFuncProfile() { actualTC->dumpFuncProfile(); }
+#endif
+
+ void takeOverFrom(ThreadContext *oldContext)
+ { actualTC->takeOverFrom(oldContext); }
+
+ void regStats(const std::string &name) { actualTC->regStats(name); }
+
+ void serialize(std::ostream &os) { actualTC->serialize(os); }
+ void unserialize(Checkpoint *cp, const std::string &section)
+ { actualTC->unserialize(cp, section); }
+
+#if FULL_SYSTEM
+ EndQuiesceEvent *getQuiesceEvent() { return actualTC->getQuiesceEvent(); }
+
+ Tick readLastActivate() { return actualTC->readLastActivate(); }
+ Tick readLastSuspend() { return actualTC->readLastSuspend(); }
+
+ 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(); }
+
+ // @todo: Do I need this?
+ void copyArchRegs(ThreadContext *tc) { actualTC->copyArchRegs(tc); }
+
+ void clearArchRegs() { actualTC->clearArchRegs(); }
+
+ //
+ // New accessors for new decoder.
+ //
+ uint64_t readIntReg(int reg_idx)
+ { return actualTC->readIntReg(reg_idx); }
+
+ FloatReg readFloatReg(int reg_idx, int width)
+ { return actualTC->readFloatReg(reg_idx, width); }
+
+ FloatReg readFloatReg(int reg_idx)
+ { return actualTC->readFloatReg(reg_idx); }
+
+ FloatRegBits readFloatRegBits(int reg_idx, int width)
+ { return actualTC->readFloatRegBits(reg_idx, width); }
+
+ FloatRegBits readFloatRegBits(int reg_idx)
+ { return actualTC->readFloatRegBits(reg_idx); }
+
+ void setIntReg(int reg_idx, uint64_t val)
+ { actualTC->setIntReg(reg_idx, val); }
+
+ void setFloatReg(int reg_idx, FloatReg val, int width)
+ { actualTC->setFloatReg(reg_idx, val, width); }
+
+ void setFloatReg(int reg_idx, FloatReg val)
+ { actualTC->setFloatReg(reg_idx, val); }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val, int width)
+ { actualTC->setFloatRegBits(reg_idx, val, width); }
+
+ void setFloatRegBits(int reg_idx, FloatRegBits val)
+ { actualTC->setFloatRegBits(reg_idx, val); }
+
+ uint64_t readPC() { return actualTC->readPC(); }
+
+ void setPC(uint64_t val) { actualTC->setPC(val); }
+
+ uint64_t readNextPC() { return actualTC->readNextPC(); }
+
+ void setNextPC(uint64_t val) { actualTC->setNextPC(val); }
+
+ uint64_t readNextNPC() { return actualTC->readNextNPC(); }
+
+ void setNextNPC(uint64_t val) { actualTC->setNextNPC(val); }
+
+ MiscReg readMiscReg(int misc_reg)
+ { return actualTC->readMiscReg(misc_reg); }
+
+ MiscReg readMiscRegWithEffect(int misc_reg, Fault &fault)
+ { return actualTC->readMiscRegWithEffect(misc_reg, fault); }
+
+ Fault setMiscReg(int misc_reg, const MiscReg &val)
+ { return actualTC->setMiscReg(misc_reg, val); }
+
+ Fault setMiscRegWithEffect(int misc_reg, const MiscReg &val)
+ { return actualTC->setMiscRegWithEffect(misc_reg, val); }
+
+ unsigned readStCondFailures()
+ { return actualTC->readStCondFailures(); }
+
+ void setStCondFailures(unsigned sc_failures)
+ { actualTC->setStCondFailures(sc_failures); }
+#if FULL_SYSTEM
+ bool inPalMode() { return actualTC->inPalMode(); }
+#endif
+
+ // @todo: Fix this!
+ 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); }
+
+ Counter readFuncExeInst() { return actualTC->readFuncExeInst(); }
+#endif
+
+ void changeRegFileContext(RegFile::ContextParam param,
+ RegFile::ContextVal val)
+ {
+ actualTC->changeRegFileContext(param, val);
+ }
+};
+
+#endif
diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc
new file mode 100644
index 000000000..872678a41
--- /dev/null
+++ b/src/cpu/thread_state.cc
@@ -0,0 +1,68 @@
+/*
+ * 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
+ */
+
+#include "base/output.hh"
+#include "cpu/profile.hh"
+#include "cpu/thread_state.hh"
+
+#if FULL_SYSTEM
+ThreadState::ThreadState(int _cpuId, int _tid)
+ : cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ profile(NULL), profileNode(NULL), profilePC(0), quiesceEvent(NULL),
+ funcExeInst(0), storeCondFailures(0)
+#else
+ThreadState::ThreadState(int _cpuId, int _tid, Process *_process,
+ short _asid, MemObject *mem)
+ : cpuId(_cpuId), tid(_tid), lastActivate(0), lastSuspend(0),
+ process(_process), asid(_asid),
+ funcExeInst(0), storeCondFailures(0)
+#endif
+{
+ numInst = 0;
+ numLoad = 0;
+}
+
+#if FULL_SYSTEM
+
+void
+ThreadState::profileClear()
+{
+ if (profile)
+ profile->clear();
+}
+
+void
+ThreadState::profileSample()
+{
+ if (profile)
+ profile->sample(profileNode, profilePC);
+}
+
+#endif
diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh
new file mode 100644
index 000000000..cb1449ac5
--- /dev/null
+++ b/src/cpu/thread_state.hh
@@ -0,0 +1,220 @@
+/*
+ * 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_THREAD_STATE_HH__
+#define __CPU_THREAD_STATE_HH__
+
+#include "arch/isa_traits.hh"
+#include "cpu/thread_context.hh"
+
+#if !FULL_SYSTEM
+#include "mem/mem_object.hh"
+#include "mem/translating_port.hh"
+#include "sim/process.hh"
+#endif
+
+#if FULL_SYSTEM
+class EndQuiesceEvent;
+class FunctionProfile;
+class ProfileNode;
+namespace Kernel {
+ class Statistics;
+};
+#endif
+
+/**
+ * Struct for holding general thread state that is needed across CPU
+ * models. This includes things such as pointers to the process,
+ * memory, quiesce events, and certain stats. This can be expanded
+ * to hold more thread-specific stats within it.
+ */
+struct ThreadState {
+ typedef ThreadContext::Status Status;
+
+#if FULL_SYSTEM
+ ThreadState(int _cpuId, int _tid);
+#else
+ ThreadState(int _cpuId, int _tid, Process *_process,
+ short _asid, MemObject *mem);
+#endif
+
+ void setCpuId(int id) { cpuId = id; }
+
+ int readCpuId() { return cpuId; }
+
+ void setTid(int id) { tid = id; }
+
+ int readTid() { return tid; }
+
+ Tick readLastActivate() { return lastActivate; }
+
+ Tick readLastSuspend() { return lastSuspend; }
+
+#if FULL_SYSTEM
+ void dumpFuncProfile();
+
+ EndQuiesceEvent *getQuiesceEvent() { return quiesceEvent; }
+
+ void profileClear();
+
+ void profileSample();
+
+ Kernel::Statistics *getKernelStats() { return kernelStats; }
+
+ FunctionalPort *getPhysPort() { return physPort; }
+
+ void setPhysPort(FunctionalPort *port) { physPort = port; }
+
+ VirtualPort *getVirtPort(ThreadContext *tc = NULL) { return virtPort; }
+
+ void setVirtPort(VirtualPort *port) { virtPort = port; }
+#else
+ Process *getProcessPtr() { return process; }
+
+ TranslatingPort *getMemPort() { return port; }
+
+ void setMemPort(TranslatingPort *_port) { port = _port; }
+
+ int getInstAsid() { return asid; }
+ int getDataAsid() { return asid; }
+#endif
+
+ /** Sets the current instruction being committed. */
+ void setInst(TheISA::MachInst _inst) { inst = _inst; }
+
+ /** Returns the current instruction being committed. */
+ TheISA::MachInst getInst() { return inst; }
+
+ /** Reads the number of instructions functionally executed and
+ * committed.
+ */
+ Counter readFuncExeInst() { return funcExeInst; }
+
+ /** Sets the total number of instructions functionally executed
+ * and committed.
+ */
+ void setFuncExeInst(Counter new_val) { funcExeInst = new_val; }
+
+ /** Returns the status of this thread. */
+ Status status() const { return _status; }
+
+ /** Sets the status of this thread. */
+ void setStatus(Status new_status) { _status = new_status; }
+
+ /** Number of instructions committed. */
+ Counter numInst;
+ /** Stat for number instructions committed. */
+ Stats::Scalar<> numInsts;
+ /** Stat for number of memory references. */
+ Stats::Scalar<> numMemRefs;
+
+ /** Number of simulated loads, used for tracking events based on
+ * the number of loads committed.
+ */
+ Counter numLoad;
+
+ /** The number of simulated loads committed prior to this run. */
+ Counter startNumLoad;
+
+ protected:
+ ThreadContext::Status _status;
+
+ // 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;
+
+ // Index of hardware thread context on the CPU that this represents.
+ int tid;
+
+ public:
+ /** Last time activate was called on this thread. */
+ Tick lastActivate;
+
+ /** Last time suspend was called on this thread. */
+ Tick lastSuspend;
+
+#if FULL_SYSTEM
+ public:
+ FunctionProfile *profile;
+ ProfileNode *profileNode;
+ Addr profilePC;
+ EndQuiesceEvent *quiesceEvent;
+
+ Kernel::Statistics *kernelStats;
+ protected:
+ /** A functional port outgoing only for functional accesses to physical
+ * addresses.*/
+ FunctionalPort *physPort;
+
+ /** A functional port, outgoing only, for functional accesse to virtual
+ * addresses. That doen't require execution context information */
+ VirtualPort *virtPort;
+#else
+ TranslatingPort *port;
+
+ Process *process;
+
+ // Address space ID. Note that this is used for TIMING cache
+ // simulation only; all functional memory accesses should use
+ // one of the FunctionalMemory pointers above.
+ short asid;
+#endif
+
+ /** Current instruction the thread is committing. Only set and
+ * used for DTB faults currently.
+ */
+ TheISA::MachInst inst;
+
+ public:
+ /**
+ * Temporary storage to pass the source address from copy_load to
+ * copy_store.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcAddr;
+ /**
+ * Temp storage for the physical source address of a copy.
+ * @todo Remove this temporary when we have a better way to do it.
+ */
+ Addr copySrcPhysAddr;
+
+ /*
+ * number of executed instructions, for matching with syscall trace
+ * points in EIO files.
+ */
+ Counter funcExeInst;
+
+ //
+ // Count failed store conditionals so we can warn of apparent
+ // application deadlock situations.
+ unsigned storeCondFailures;
+};
+
+#endif // __CPU_THREAD_STATE_HH__
diff --git a/src/cpu/trace/opt_cpu.cc b/src/cpu/trace/opt_cpu.cc
index 6cd23b0dd..996e89f01 100644
--- a/src/cpu/trace/opt_cpu.cc
+++ b/src/cpu/trace/opt_cpu.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
@@ -174,7 +176,7 @@ OptCPU::tick()
fprintf(stderr,"sys.cpu.misses %d #opt cache misses\n",misses);
fprintf(stderr,"sys.cpu.hits %d #opt cache hits\n", hits);
fprintf(stderr,"sys.cpu.accesses %d #opt cache acceses\n", references);
- new SimExitEvent("Finshed Memory Trace");
+ exitSimLoop("end of memory trace reached");
}
void
diff --git a/src/cpu/trace/opt_cpu.hh b/src/cpu/trace/opt_cpu.hh
index f81691733..dfb122319 100644
--- a/src/cpu/trace/opt_cpu.hh
+++ b/src/cpu/trace/opt_cpu.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/ibm_reader.cc b/src/cpu/trace/reader/ibm_reader.cc
index 420101b63..87e13f307 100644
--- a/src/cpu/trace/reader/ibm_reader.cc
+++ b/src/cpu/trace/reader/ibm_reader.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/ibm_reader.hh b/src/cpu/trace/reader/ibm_reader.hh
index ce29206a2..a72f62e03 100644
--- a/src/cpu/trace/reader/ibm_reader.hh
+++ b/src/cpu/trace/reader/ibm_reader.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/itx_reader.cc b/src/cpu/trace/reader/itx_reader.cc
index 39ba27393..e4738eed8 100644
--- a/src/cpu/trace/reader/itx_reader.cc
+++ b/src/cpu/trace/reader/itx_reader.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/itx_reader.hh b/src/cpu/trace/reader/itx_reader.hh
index a16a08085..63a4c9ac9 100644
--- a/src/cpu/trace/reader/itx_reader.hh
+++ b/src/cpu/trace/reader/itx_reader.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/m5_reader.cc b/src/cpu/trace/reader/m5_reader.cc
index ce44672f2..8efcb022b 100644
--- a/src/cpu/trace/reader/m5_reader.cc
+++ b/src/cpu/trace/reader/m5_reader.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/m5_reader.hh b/src/cpu/trace/reader/m5_reader.hh
index 974a83ffa..5007bfd5b 100644
--- a/src/cpu/trace/reader/m5_reader.hh
+++ b/src/cpu/trace/reader/m5_reader.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/mem_trace_reader.cc b/src/cpu/trace/reader/mem_trace_reader.cc
index 769f0be27..5623f168a 100644
--- a/src/cpu/trace/reader/mem_trace_reader.cc
+++ b/src/cpu/trace/reader/mem_trace_reader.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/reader/mem_trace_reader.hh b/src/cpu/trace/reader/mem_trace_reader.hh
index b433cdbdd..628a3ecdc 100644
--- a/src/cpu/trace/reader/mem_trace_reader.hh
+++ b/src/cpu/trace/reader/mem_trace_reader.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/cpu/trace/trace_cpu.cc b/src/cpu/trace/trace_cpu.cc
index 20d0a567f..3c9da4849 100644
--- a/src/cpu/trace/trace_cpu.cc
+++ b/src/cpu/trace/trace_cpu.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
@@ -106,7 +108,7 @@ TraceCPU::tick()
if (!nextReq) {
// No more requests to send. Finish trailing events and exit.
if (mainEventQueue.empty()) {
- new SimExitEvent("Finshed Memory Trace");
+ exitSimLoop("end of memory trace reached");
} else {
tickEvent.schedule(mainEventQueue.nextEventTime() + cycles(1));
}
diff --git a/src/cpu/trace/trace_cpu.hh b/src/cpu/trace/trace_cpu.hh
index 69ca35321..9c96d71d5 100644
--- a/src/cpu/trace/trace_cpu.hh
+++ b/src/cpu/trace/trace_cpu.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Erik Hallnor
*/
/**
diff --git a/src/dev/alpha_access.h b/src/dev/alpha_access.h
index 5a1df6f39..4adeaf84b 100644
--- a/src/dev/alpha_access.h
+++ b/src/dev/alpha_access.h
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ALPHA_ACCESS_H__
diff --git a/src/dev/alpha_console.cc b/src/dev/alpha_console.cc
index 0b4bb048c..181bbf934 100644
--- a/src/dev/alpha_console.cc
+++ b/src/dev/alpha_console.cc
@@ -24,6 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
+ * Steve Reinhardt
+ * Erik Hallnor
*/
/** @file
@@ -38,7 +43,7 @@
#include "base/str.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "dev/alpha_console.hh"
#include "dev/platform.hh"
#include "dev/simconsole.hh"
@@ -98,7 +103,6 @@ AlphaConsole::read(Packet *pkt)
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
- pkt->time += pioDelay;
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
@@ -191,8 +195,6 @@ AlphaConsole::read(Packet *pkt)
Tick
AlphaConsole::write(Packet *pkt)
{
- pkt->time += pioDelay;
-
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
diff --git a/src/dev/alpha_console.hh b/src/dev/alpha_console.hh
index 34d21e15c..b6360d40f 100644
--- a/src/dev/alpha_console.hh
+++ b/src/dev/alpha_console.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
diff --git a/src/dev/baddev.cc b/src/dev/baddev.cc
index 66fbd8a86..e4297be19 100644
--- a/src/dev/baddev.cc
+++ b/src/dev/baddev.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/baddev.hh b/src/dev/baddev.hh
index 35ae0382a..d7d778af4 100644
--- a/src/dev/baddev.hh
+++ b/src/dev/baddev.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/disk_image.cc b/src/dev/disk_image.cc
index 185a8b083..f70d2ccdb 100644
--- a/src/dev/disk_image.cc
+++ b/src/dev/disk_image.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
diff --git a/src/dev/disk_image.hh b/src/dev/disk_image.hh
index 648aa20c6..45d5af649 100644
--- a/src/dev/disk_image.hh
+++ b/src/dev/disk_image.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
index 906e324d3..348bb818a 100644
--- a/src/dev/etherbus.cc
+++ b/src/dev/etherbus.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh
index 4a364abd8..2ff1d0a5e 100644
--- a/src/dev/etherbus.hh
+++ b/src/dev/etherbus.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
index cb5f0b70e..0c986cc21 100644
--- a/src/dev/etherdump.cc
+++ b/src/dev/etherdump.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh
index 8bba073fe..f3080f341 100644
--- a/src/dev/etherdump.hh
+++ b/src/dev/etherdump.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherint.cc b/src/dev/etherint.cc
index 8fb047373..3f81591e9 100644
--- a/src/dev/etherint.cc
+++ b/src/dev/etherint.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "dev/etherint.hh"
diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh
index 1f641fadb..dfc224ecc 100644
--- a/src/dev/etherint.hh
+++ b/src/dev/etherint.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
index 5b6531c2e..cd3812270 100644
--- a/src/dev/etherlink.cc
+++ b/src/dev/etherlink.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ron Dreslinski
*/
/* @file
diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh
index 570444e1b..bb2854810 100644
--- a/src/dev/etherlink.hh
+++ b/src/dev/etherlink.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc
index 85e18e981..5c552b4bd 100644
--- a/src/dev/etherpkt.cc
+++ b/src/dev/etherpkt.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh
index 01741b3d5..80c7baff7 100644
--- a/src/dev/etherpkt.hh
+++ b/src/dev/etherpkt.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc
index b5abb1d62..2d72383c5 100644
--- a/src/dev/ethertap.cc
+++ b/src/dev/ethertap.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh
index 40ce6af0b..f64ed7187 100644
--- a/src/dev/ethertap.hh
+++ b/src/dev/ethertap.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/ide_ctrl.cc b/src/dev/ide_ctrl.cc
index eb03d5db8..63435e87c 100644
--- a/src/dev/ide_ctrl.cc
+++ b/src/dev/ide_ctrl.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Ali Saidi
+ * Miguel Serrano
*/
#include <cstddef>
@@ -430,7 +434,6 @@ IdeController::read(Packet *pkt)
IdeRegType reg_type;
int disk;
- pkt->time += pioDelay;
pkt->allocate();
if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
panic("Bad IDE read size: %d\n", pkt->getSize());
@@ -518,8 +521,6 @@ IdeController::write(Packet *pkt)
int disk;
uint8_t oldVal, newVal;
- pkt->time += pioDelay;
-
parseAddr(pkt->getAddr(), offset, channel, reg_type);
if (!io_enabled) {
diff --git a/src/dev/ide_ctrl.hh b/src/dev/ide_ctrl.hh
index dda2cbb66..1d30c8b31 100644
--- a/src/dev/ide_ctrl.hh
+++ b/src/dev/ide_ctrl.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Miguel Serrano
*/
/** @file
diff --git a/src/dev/ide_disk.cc b/src/dev/ide_disk.cc
index 909f35c60..dc78021f8 100644
--- a/src/dev/ide_disk.cc
+++ b/src/dev/ide_disk.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Ali Saidi
*/
/** @file
diff --git a/src/dev/ide_disk.hh b/src/dev/ide_disk.hh
index 5379e5e73..fb0614d4d 100644
--- a/src/dev/ide_disk.hh
+++ b/src/dev/ide_disk.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
*/
/** @file
diff --git a/src/dev/io_device.cc b/src/dev/io_device.cc
index 87fdbb765..e769ef037 100644
--- a/src/dev/io_device.cc
+++ b/src/dev/io_device.cc
@@ -24,8 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
+#include "base/trace.hh"
#include "dev/io_device.hh"
#include "sim/builder.hh"
@@ -55,15 +59,17 @@ PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
}
-Packet *
+void
PioPort::recvRetry()
{
- Packet* pkt = transmitList.front();
- transmitList.pop_front();
- return pkt;
+ bool result = true;
+ while (result && transmitList.size()) {
+ result = Port::sendTiming(transmitList.front());
+ if (result)
+ transmitList.pop_front();
+ }
}
-
void
PioPort::SendEvent::process()
{
@@ -74,13 +80,24 @@ PioPort::SendEvent::process()
}
+
bool
PioPort::recvTiming(Packet *pkt)
{
- device->recvAtomic(pkt);
- // turn packet around to go back to requester
- pkt->makeTimingResponse();
- sendTiming(pkt, pkt->time - pkt->req->getTime());
+ if (pkt->result == Packet::Nacked) {
+ pkt->reinitNacked();
+ if (transmitList.size()) {
+ transmitList.push_front(pkt);
+ } else {
+ if (!Port::sendTiming(pkt))
+ transmitList.push_front(pkt);
+ }
+ } else {
+ Tick latency = device->recvAtomic(pkt);
+ // turn packet around to go back to requester
+ pkt->makeTimingResponse();
+ sendTiming(pkt, latency);
+ }
return true;
}
@@ -114,18 +131,35 @@ DmaPort::DmaPort(DmaDevice *dev, Platform *p)
bool
DmaPort::recvTiming(Packet *pkt)
{
- if (pkt->senderState) {
+
+
+ if (pkt->result == Packet::Nacked) {
+ DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n",
+ pkt, pkt->senderState, pkt->getAddr());
+ pkt->reinitNacked();
+ sendDma(pkt, true);
+ } else if (pkt->senderState) {
DmaReqState *state;
+ DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x\n",
+ pkt, pkt->senderState, pkt->getAddr());
state = dynamic_cast<DmaReqState*>(pkt->senderState);
- state->completionEvent->schedule(pkt->time - pkt->req->getTime());
+ pendingCount--;
+
+ assert(pendingCount >= 0);
+ assert(state);
+
+ state->numBytes += pkt->req->getSize();
+ if (state->totBytes == state->numBytes) {
+ state->completionEvent->process();
+ delete state;
+ }
delete pkt->req;
delete pkt;
} else {
- delete pkt->req;
- delete pkt;
+ panic("Got packet without sender state... huh?\n");
}
- return Packet::Success;
+ return true;
}
DmaDevice::DmaDevice(Params *p)
@@ -133,20 +167,21 @@ DmaDevice::DmaDevice(Params *p)
{ }
void
-DmaPort::SendEvent::process()
-{
- if (port->Port::sendTiming(packet))
- return;
-
- port->transmitList.push_back(packet);
-}
-
-Packet *
DmaPort::recvRetry()
{
Packet* pkt = transmitList.front();
- transmitList.pop_front();
- return pkt;
+ bool result = true;
+ while (result && transmitList.size()) {
+ DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n",
+ pkt, pkt->senderState);
+ result = sendTiming(pkt);
+ if (result) {
+ DPRINTF(DMA, "-- Done\n");
+ transmitList.pop_front();
+ } else {
+ DPRINTF(DMA, "-- Failed, queued\n");
+ }
+ }
}
@@ -156,27 +191,19 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
{
assert(event);
- int prevSize = 0;
+ DmaReqState *reqState = new DmaReqState(event, this, size);
for (ChunkGenerator gen(addr, size, peerBlockSize());
!gen.done(); gen.next()) {
- Request *req = new Request(false);
- req->setPaddr(gen.addr());
- req->setSize(gen.size());
- req->setTime(curTick);
+ Request *req = new Request(gen.addr(), gen.size(), 0);
Packet *pkt = new Packet(req, cmd, Packet::Broadcast);
// Increment the data pointer on a write
if (data)
- pkt->dataStatic(data + prevSize) ;
+ pkt->dataStatic(data + gen.complete());
- prevSize += gen.size();
+ pkt->senderState = reqState;
- // Set the last bit of the dma as the final packet for this dma
- // and set it's completion event.
- if (prevSize == size) {
- pkt->senderState = new DmaReqState(event, true);
- }
assert(pendingCount >= 0);
pendingCount++;
sendDma(pkt);
@@ -185,28 +212,40 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
void
-DmaPort::sendDma(Packet *pkt)
+DmaPort::sendDma(Packet *pkt, bool front)
{
// some kind of selction between access methods
// more work is going to have to be done to make
// switching actually work
/* MemState state = device->platform->system->memState;
- if (state == Timing) {
- if (!sendTiming(pkt))
- transmitList.push_back(&packet);
- } else if (state == Atomic) {*/
+ if (state == Timing) { */
+ DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
+ pkt, pkt->getAddr());
+ if (transmitList.size() || !sendTiming(pkt)) {
+ if (front)
+ transmitList.push_front(pkt);
+ else
+ transmitList.push_back(pkt);
+ DPRINTF(DMA, "-- Failed: queued\n");
+ } else {
+ DPRINTF(DMA, "-- Done\n");
+ }
+ /* } else if (state == Atomic) {
sendAtomic(pkt);
if (pkt->senderState) {
DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
- state->completionEvent->schedule(curTick + (pkt->time - pkt->req->getTime()) +1);
+ assert(state);
+ state->completionEvent->schedule(curTick + (pkt->time -
+ pkt->req->getTime()) +1);
+ delete state;
}
pendingCount--;
assert(pendingCount >= 0);
delete pkt->req;
delete pkt;
-/* } else if (state == Functional) {
+ } else if (state == Functional) {
sendFunctional(pkt);
// Is this correct???
completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime);
diff --git a/src/dev/io_device.hh b/src/dev/io_device.hh
index 74730ad92..a2b61c7f4 100644
--- a/src/dev/io_device.hh
+++ b/src/dev/io_device.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __DEV_IO_DEVICE_HH__
@@ -105,8 +108,9 @@ class PioPort : public Port
void sendTiming(Packet *pkt, Tick time)
{ new PioPort::SendEvent(this, pkt, time); }
- /** This function pops the last element off the transmit list and sends it.*/
- virtual Packet *recvRetry();
+ /** This function is notification that the device should attempt to send a
+ * packet again. */
+ virtual void recvRetry();
public:
PioPort(PioDevice *dev, Platform *p);
@@ -115,18 +119,29 @@ class PioPort : public Port
};
-struct DmaReqState : public Packet::SenderState
-{
- Event *completionEvent;
- bool final;
- DmaReqState(Event *ce, bool f)
- : completionEvent(ce), final(f)
- {}
-};
-
class DmaPort : public Port
{
protected:
+ struct DmaReqState : public Packet::SenderState
+ {
+ /** Event to call on the device when this transaction (all packets)
+ * complete. */
+ Event *completionEvent;
+
+ /** Where we came from for some sanity checking. */
+ Port *outPort;
+
+ /** Total number of bytes that this transaction involves. */
+ Addr totBytes;
+
+ /** 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)
+ {}
+ };
+
DmaDevice *device;
std::list<Packet*> transmitList;
@@ -146,29 +161,12 @@ class DmaPort : public Port
virtual void recvStatusChange(Status status)
{ ; }
- virtual Packet *recvRetry() ;
+ virtual void recvRetry() ;
virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
{ resp.clear(); snoop.clear(); }
- class SendEvent : public Event
- {
- DmaPort *port;
- Packet *packet;
-
- SendEvent(PioPort *p, Packet *pkt, Tick t)
- : Event(&mainEventQueue), packet(pkt)
- { schedule(curTick + t); }
-
- virtual void process();
-
- virtual const char *description()
- { return "Future scheduled sendTiming event"; }
-
- friend class DmaPort;
- };
-
- void sendDma(Packet *pkt);
+ void sendDma(Packet *pkt, bool front = false);
public:
DmaPort(DmaDevice *dev, Platform *p);
@@ -178,8 +176,6 @@ class DmaPort : public Port
bool dmaPending() { return pendingCount > 0; }
- friend class DmaPort::SendEvent;
-
};
/**
@@ -250,7 +246,7 @@ class PioDevice : public MemObject
virtual void init();
- virtual Port *getPort(const std::string &if_name)
+ virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "pio") {
if (pioPort != NULL)
@@ -312,7 +308,7 @@ class DmaDevice : public PioDevice
bool dmaPending() { return dmaPort->dmaPending(); }
- virtual Port *getPort(const std::string &if_name)
+ virtual Port *getPort(const std::string &if_name, int idx = -1)
{
if (if_name == "pio") {
if (pioPort != NULL)
diff --git a/src/dev/isa_fake.cc b/src/dev/isa_fake.cc
index c303ffc30..9622f015c 100644
--- a/src/dev/isa_fake.cc
+++ b/src/dev/isa_fake.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
/** @file
@@ -54,8 +57,6 @@ IsaFake::read(Packet *pkt)
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
- pkt->time += pioDelay;
-
DPRINTF(Tsunami, "read va=%#x size=%d\n", pkt->getAddr(), pkt->getSize());
switch (pkt->getSize()) {
@@ -80,7 +81,6 @@ IsaFake::read(Packet *pkt)
Tick
IsaFake::write(Packet *pkt)
{
- pkt->time += pioDelay;
DPRINTF(Tsunami, "write - va=%#x size=%d \n", pkt->getAddr(), pkt->getSize());
pkt->result = Packet::Success;
return pioDelay;
diff --git a/src/dev/isa_fake.hh b/src/dev/isa_fake.hh
index 65d44f6a5..a7a469e17 100644
--- a/src/dev/isa_fake.hh
+++ b/src/dev/isa_fake.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
/** @file
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
index 963675847..360fe8c9b 100644
--- a/src/dev/ns_gige.cc
+++ b/src/dev/ns_gige.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
@@ -35,7 +38,7 @@
#include "arch/alpha/ev5.hh"
#include "base/inet.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "dev/etherlink.hh"
#include "dev/ns_gige.hh"
#include "dev/pciconfigall.hh"
@@ -492,7 +495,6 @@ NSGigE::read(Packet *pkt)
{
assert(ioEnable);
- pkt->time += pioDelay;
pkt->allocate();
//The mask is to give you only the offset into the device register file
@@ -728,8 +730,6 @@ NSGigE::write(Packet *pkt)
DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
daddr, pkt->getAddr(), pkt->getSize());
- pkt->time += pioDelay;
-
if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
} else if (daddr > RESERVED && daddr <= 0x3FC) {
diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh
index 51520fd00..2f47026f3 100644
--- a/src/dev/ns_gige.hh
+++ b/src/dev/ns_gige.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
diff --git a/src/dev/ns_gige_reg.h b/src/dev/ns_gige_reg.h
index 5f6fa2cc5..80ac5800d 100644
--- a/src/dev/ns_gige_reg.h
+++ b/src/dev/ns_gige_reg.h
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/pciconfigall.cc b/src/dev/pciconfigall.cc
index 14a28e86d..785774ff4 100644
--- a/src/dev/pciconfigall.cc
+++ b/src/dev/pciconfigall.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Ali Saidi
*/
/* @file
@@ -99,7 +102,6 @@ PciConfigAll::read(Packet *pkt)
int func = (daddr >> 8) & 0x7;
int reg = daddr & 0xFF;
- pkt->time += pioDelay;
pkt->allocate();
DPRINTF(PciConfigAll, "read va=%#x da=%#x size=%d\n", pkt->getAddr(), daddr,
@@ -134,8 +136,6 @@ PciConfigAll::read(Packet *pkt)
Tick
PciConfigAll::write(Packet *pkt)
{
- pkt->time += pioDelay;
-
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == sizeof(uint8_t) || pkt->getSize() == sizeof(uint16_t) ||
diff --git a/src/dev/pciconfigall.hh b/src/dev/pciconfigall.hh
index df4eae448..e60fd949b 100644
--- a/src/dev/pciconfigall.hh
+++ b/src/dev/pciconfigall.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Ali Saidi
*/
/*
diff --git a/src/dev/pcidev.cc b/src/dev/pcidev.cc
index 76392ccfe..f8db2efbc 100644
--- a/src/dev/pcidev.cc
+++ b/src/dev/pcidev.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/pcidev.hh b/src/dev/pcidev.hh
index fc4773908..92786427b 100644
--- a/src/dev/pcidev.hh
+++ b/src/dev/pcidev.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
/* @file
diff --git a/src/dev/pcireg.h b/src/dev/pcireg.h
index 9d2737c20..0aa4ba8ef 100644
--- a/src/dev/pcireg.h
+++ b/src/dev/pcireg.h
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Miguel Serrano
*/
/* @file
diff --git a/src/dev/pitreg.h b/src/dev/pitreg.h
index 5fe1cf03f..d42925a41 100644
--- a/src/dev/pitreg.h
+++ b/src/dev/pitreg.h
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc
index 922a66912..37f7ff680 100644
--- a/src/dev/pktfifo.cc
+++ b/src/dev/pktfifo.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "base/misc.hh"
diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh
index 336da22d8..45157ba41 100644
--- a/src/dev/pktfifo.hh
+++ b/src/dev/pktfifo.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __DEV_PKTFIFO_HH__
diff --git a/src/dev/platform.cc b/src/dev/platform.cc
index 9d10e0828..ed021e3b6 100644
--- a/src/dev/platform.cc
+++ b/src/dev/platform.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#include "dev/platform.hh"
diff --git a/src/dev/platform.hh b/src/dev/platform.hh
index f149ca2fb..0e6f4ba4a 100644
--- a/src/dev/platform.hh
+++ b/src/dev/platform.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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: Andrew Schultz
+ * Nathan Binkert
*/
/**
diff --git a/src/dev/rtcreg.h b/src/dev/rtcreg.h
index 5025a0e95..37255777b 100644
--- a/src/dev/rtcreg.h
+++ b/src/dev/rtcreg.h
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Miguel Serrano
+ * Nathan Binkert
*/
#define RTC_SEC 0x00
diff --git a/src/dev/simconsole.cc b/src/dev/simconsole.cc
index c3e4f554a..77aafd9fa 100644
--- a/src/dev/simconsole.cc
+++ b/src/dev/simconsole.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
/* @file
@@ -202,32 +205,31 @@ SimConsole::write(const uint8_t *buf, size_t len)
#define RECEIVE_NONE (ULL(2) << 62)
#define RECEIVE_ERROR (ULL(3) << 62)
-bool
-SimConsole::in(uint8_t &c)
+uint8_t
+SimConsole::in()
{
- bool empty, ret;
+ bool empty;
+ uint8_t c;
empty = rxbuf.empty();
- ret = !empty;
- if (!empty) {
- rxbuf.read((char *)&c, 1);
- empty = rxbuf.empty();
- }
+ assert(!empty);
+ rxbuf.read((char *)&c, 1);
+ empty = rxbuf.empty();
- DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d, return: %d\n",
- isprint(c) ? c : ' ', c, !empty, ret);
- return ret;
+ DPRINTF(ConsoleVerbose, "in: \'%c\' %#02x more: %d\n",
+ isprint(c) ? c : ' ', c, !empty);
+
+ return c;
}
uint64_t
SimConsole::console_in()
{
- uint8_t c;
uint64_t value;
- if (in(c)) {
- value = RECEIVE_SUCCESS | c;
+ if (dataAvailable()) {
+ value = RECEIVE_SUCCESS | in();
if (!rxbuf.empty())
value |= MORE_PENDING;
} else {
diff --git a/src/dev/simconsole.hh b/src/dev/simconsole.hh
index cf0641f9e..ec99c6028 100644
--- a/src/dev/simconsole.hh
+++ b/src/dev/simconsole.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
/* @file
@@ -102,7 +105,7 @@ class SimConsole : public SimObject
// OS interface
// Get a character from the console.
- bool in(uint8_t &value);
+ uint8_t in();
// get a character from the console in the console specific format
// corresponds to GETC:
diff --git a/src/dev/simple_disk.cc b/src/dev/simple_disk.cc
index 9eee4668c..e29bfa726 100644
--- a/src/dev/simple_disk.cc
+++ b/src/dev/simple_disk.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/simple_disk.hh b/src/dev/simple_disk.hh
index 19967f208..9f588cb95 100644
--- a/src/dev/simple_disk.hh
+++ b/src/dev/simple_disk.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
index 31fbc49aa..a0223733b 100644
--- a/src/dev/sinic.cc
+++ b/src/dev/sinic.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <deque>
@@ -31,7 +33,7 @@
#include <string>
#include "base/inet.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/intr_control.hh"
#include "dev/etherlink.hh"
#include "dev/sinic.hh"
@@ -322,7 +324,6 @@ Device::read(Packet *pkt)
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
- pkt->time += pioDelay;
pkt->allocate();
if (!regValid(raddr))
@@ -410,8 +411,6 @@ Device::write(Packet *pkt)
Addr index = daddr >> Regs::VirtualShift;
Addr raddr = daddr & Regs::VirtualMask;
- pkt->time += pioDelay;
-
if (!regValid(raddr))
panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
cpu, daddr, pkt->getAddr(), pkt->getSize());
diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh
index 1bb4c77e0..f6c229039 100644
--- a/src/dev/sinic.hh
+++ b/src/dev/sinic.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __DEV_SINIC_HH__
diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh
index d41eb5b16..de4188145 100644
--- a/src/dev/sinicreg.hh
+++ b/src/dev/sinicreg.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __DEV_SINICREG_HH__
diff --git a/src/dev/tsunami.cc b/src/dev/tsunami.cc
index ed011531d..c9e15581d 100644
--- a/src/dev/tsunami.cc
+++ b/src/dev/tsunami.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/tsunami.hh b/src/dev/tsunami.hh
index 668c82674..13fc4417c 100644
--- a/src/dev/tsunami.hh
+++ b/src/dev/tsunami.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
diff --git a/src/dev/tsunami_cchip.cc b/src/dev/tsunami_cchip.cc
index 146321b9f..3feb7439f 100644
--- a/src/dev/tsunami_cchip.cc
+++ b/src/dev/tsunami_cchip.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ron Dreslinski
*/
/** @file
@@ -40,7 +43,7 @@
#include "dev/tsunamireg.h"
#include "dev/tsunami.hh"
#include "mem/port.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/intr_control.hh"
#include "sim/builder.hh"
#include "sim/system.hh"
@@ -76,7 +79,6 @@ TsunamiCChip::read(Packet *pkt)
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
- pkt->time += pioDelay;
Addr regnum = (pkt->getAddr() - pioAddr) >> 6;
Addr daddr = (pkt->getAddr() - pioAddr);
@@ -182,9 +184,6 @@ TsunamiCChip::read(Packet *pkt)
Tick
TsunamiCChip::write(Packet *pkt)
{
- pkt->time += pioDelay;
-
-
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
Addr regnum = (pkt->getAddr() - pioAddr) >> 6 ;
@@ -369,7 +368,7 @@ TsunamiCChip::write(Packet *pkt)
void
TsunamiCChip::clearIPI(uint64_t ipintr)
{
- int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipintr) {
@@ -395,7 +394,7 @@ TsunamiCChip::clearIPI(uint64_t ipintr)
void
TsunamiCChip::clearITI(uint64_t itintr)
{
- int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (itintr) {
@@ -415,7 +414,7 @@ TsunamiCChip::clearITI(uint64_t itintr)
void
TsunamiCChip::reqIPI(uint64_t ipreq)
{
- int numcpus = tsunami->intrctrl->cpu->system->execContexts.size();
+ int numcpus = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(numcpus <= Tsunami::Max_CPUs);
if (ipreq) {
@@ -442,7 +441,7 @@ TsunamiCChip::reqIPI(uint64_t ipreq)
void
TsunamiCChip::postRTC()
{
- int size = tsunami->intrctrl->cpu->system->execContexts.size();
+ int size = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
for (int i = 0; i < size; i++) {
@@ -460,7 +459,7 @@ void
TsunamiCChip::postDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
- uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
drir |= bitvector;
@@ -478,7 +477,7 @@ void
TsunamiCChip::clearDRIR(uint32_t interrupt)
{
uint64_t bitvector = ULL(1) << interrupt;
- uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+ uint64_t size = tsunami->intrctrl->cpu->system->threadContexts.size();
assert(size <= Tsunami::Max_CPUs);
if (drir & bitvector)
diff --git a/src/dev/tsunami_cchip.hh b/src/dev/tsunami_cchip.hh
index 3dde0131e..ef43f621f 100644
--- a/src/dev/tsunami_cchip.hh
+++ b/src/dev/tsunami_cchip.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/tsunami_io.cc b/src/dev/tsunami_io.cc
index 7c649a84a..e3da10eb5 100644
--- a/src/dev/tsunami_io.cc
+++ b/src/dev/tsunami_io.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
@@ -118,25 +122,27 @@ TsunamiIO::RTC::writeData(const uint8_t data)
}
}
-void
-TsunamiIO::RTC::readData(uint8_t *data)
+uint8_t
+TsunamiIO::RTC::readData()
{
if (addr < RTC_STAT_REGA)
- *data = clock_data[addr];
+ return clock_data[addr];
else {
switch (addr) {
case RTC_STAT_REGA:
// toggle UIP bit for linux
stat_regA ^= RTCA_UIP;
- *data = stat_regA;
+ return stat_regA;
break;
case RTC_STAT_REGB:
- *data = stat_regB;
+ return stat_regB;
break;
case RTC_STAT_REGC:
case RTC_STAT_REGD:
- *data = 0x00;
+ return 0x00;
break;
+ default:
+ panic("Shouldn't be here");
}
}
}
@@ -263,31 +269,35 @@ TsunamiIO::PITimer::Counter::latchCount()
}
}
-void
-TsunamiIO::PITimer::Counter::read(uint8_t *data)
+uint8_t
+TsunamiIO::PITimer::Counter::read()
{
if (latch_on) {
switch (read_byte) {
case LSB:
read_byte = MSB;
- *data = (uint8_t)latched_count;
+ return (uint8_t)latched_count;
break;
case MSB:
read_byte = LSB;
latch_on = false;
- *data = latched_count >> 8;
+ return latched_count >> 8;
break;
+ default:
+ panic("Shouldn't be here");
}
} else {
switch (read_byte) {
case LSB:
read_byte = MSB;
- *data = (uint8_t)count;
+ return (uint8_t)count;
break;
case MSB:
read_byte = LSB;
- *data = count >> 8;
+ return count >> 8;
break;
+ default:
+ panic("Shouldn't be here");
}
}
}
@@ -441,7 +451,6 @@ TsunamiIO::read(Packet *pkt)
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
- pkt->time += pioDelay;
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Tsunami, "io read va=%#x size=%d IOPorrt=%#x\n", pkt->getAddr(),
@@ -469,16 +478,16 @@ TsunamiIO::read(Packet *pkt)
pkt->set(0x00);
break;
case TSDEV_TMR0_DATA:
- pitimer.counter0.read(pkt->getPtr<uint8_t>());
+ pkt->set(pitimer.counter0.read());
break;
case TSDEV_TMR1_DATA:
- pitimer.counter1.read(pkt->getPtr<uint8_t>());
+ pkt->set(pitimer.counter1.read());
break;
case TSDEV_TMR2_DATA:
- pitimer.counter2.read(pkt->getPtr<uint8_t>());
+ pkt->set(pitimer.counter2.read());
break;
case TSDEV_RTC_DATA:
- rtc.readData(pkt->getPtr<uint8_t>());
+ pkt->set(rtc.readData());
break;
case TSDEV_CTRL_PORTB:
if (pitimer.counter2.outputHigh())
@@ -505,8 +514,6 @@ TsunamiIO::read(Packet *pkt)
Tick
TsunamiIO::write(Packet *pkt)
{
- pkt->time += pioDelay;
-
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = pkt->getAddr() - pioAddr;
diff --git a/src/dev/tsunami_io.hh b/src/dev/tsunami_io.hh
index 4e4fb2036..ee25bbdfd 100644
--- a/src/dev/tsunami_io.hh
+++ b/src/dev/tsunami_io.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
@@ -118,7 +122,7 @@ class TsunamiIO : public BasicPioDevice
void writeData(const uint8_t data);
/** RTC read data */
- void readData(uint8_t *data);
+ uint8_t readData();
/**
* Serialize this object to the given output stream.
@@ -207,7 +211,7 @@ class TsunamiIO : public BasicPioDevice
void setBCD(int bcd_val);
/** Read a count byte */
- void read(uint8_t *data);
+ uint8_t read();
/** Write a count byte */
void write(const uint8_t data);
diff --git a/src/dev/tsunami_pchip.cc b/src/dev/tsunami_pchip.cc
index c430ca0a0..a376b908d 100644
--- a/src/dev/tsunami_pchip.cc
+++ b/src/dev/tsunami_pchip.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/** @file
@@ -70,8 +73,6 @@ TsunamiPChip::read(Packet *pkt)
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
-
- pkt->time += pioDelay;
pkt->allocate();
Addr daddr = (pkt->getAddr() - pioAddr) >> 6;;
assert(pkt->getSize() == sizeof(uint64_t));
@@ -151,8 +152,6 @@ TsunamiPChip::read(Packet *pkt)
Tick
TsunamiPChip::write(Packet *pkt)
{
- pkt->time += pioDelay;
-
assert(pkt->result == Packet::Unknown);
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
Addr daddr = (pkt->getAddr() - pioAddr) >> 6;
diff --git a/src/dev/tsunami_pchip.hh b/src/dev/tsunami_pchip.hh
index bb84339c9..9f80f7d68 100644
--- a/src/dev/tsunami_pchip.hh
+++ b/src/dev/tsunami_pchip.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/tsunamireg.h b/src/dev/tsunamireg.h
index a10259900..d603972be 100644
--- a/src/dev/tsunamireg.h
+++ b/src/dev/tsunamireg.h
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/uart.cc b/src/dev/uart.cc
index 4a9f2b505..f769b720b 100644
--- a/src/dev/uart.cc
+++ b/src/dev/uart.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/uart.hh b/src/dev/uart.hh
index 2dd15d9b8..f0ae0854c 100644
--- a/src/dev/uart.hh
+++ b/src/dev/uart.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/dev/uart8250.cc b/src/dev/uart8250.cc
index 8e6843841..b92527b5a 100644
--- a/src/dev/uart8250.cc
+++ b/src/dev/uart8250.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
@@ -114,7 +116,6 @@ Uart8250::read(Packet *pkt)
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 1);
- pkt->time += pioDelay;
Addr daddr = pkt->getAddr() - pioAddr;
pkt->allocate();
@@ -124,7 +125,7 @@ Uart8250::read(Packet *pkt)
case 0x0:
if (!(LCR & 0x80)) { // read byte
if (cons->dataAvailable())
- cons->in(*pkt->getPtr<uint8_t>());
+ pkt->set(cons->in());
else {
pkt->set((uint8_t)0);
// A limited amount of these are ok.
@@ -198,7 +199,6 @@ Uart8250::write(Packet *pkt)
assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
assert(pkt->getSize() == 1);
- pkt->time += pioDelay;
Addr daddr = pkt->getAddr() - pioAddr;
DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
diff --git a/src/dev/uart8250.hh b/src/dev/uart8250.hh
index 4b7c2f1e4..44e90132f 100644
--- a/src/dev/uart8250.hh
+++ b/src/dev/uart8250.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
diff --git a/src/kern/kernel_stats.cc b/src/kern/kernel_stats.cc
index b85d88145..f7868b50f 100644
--- a/src/kern/kernel_stats.cc
+++ b/src/kern/kernel_stats.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#include <map>
@@ -32,7 +35,7 @@
#include "arch/alpha/osfpal.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/kernel_stats.hh"
#include "kern/tru64/tru64_syscalls.hh"
#include "sim/system.hh"
@@ -42,13 +45,12 @@ using namespace Stats;
namespace Kernel {
-const char *modestr[] = { "kernel", "user", "idle", "interrupt" };
+const char *modestr[] = { "kernel", "user", "idle" };
Statistics::Statistics(System *system)
: idleProcess((Addr)-1), themode(kernel), lastModeTick(0),
iplLast(0), iplLastTick(0)
{
- bin_int = system->params()->bin_int;
}
void
@@ -181,16 +183,16 @@ Statistics::regStats(const string &_name)
}
void
-Statistics::setIdleProcess(Addr idlepcbb, ExecContext *xc)
+Statistics::setIdleProcess(Addr idlepcbb, ThreadContext *tc)
{
- assert(themode == kernel || themode == interrupt);
+ assert(themode == kernel);
idleProcess = idlepcbb;
themode = idle;
- changeMode(themode, xc);
+ changeMode(themode, tc);
}
void
-Statistics::changeMode(cpu_mode newmode, ExecContext *xc)
+Statistics::changeMode(cpu_mode newmode, ThreadContext *tc)
{
_mode[newmode]++;
@@ -203,8 +205,6 @@ Statistics::changeMode(cpu_mode newmode, ExecContext *xc)
_modeGood[newmode]++;
_modeTicks[themode] += curTick - lastModeTick;
- xc->getSystemPtr()->kernelBinning->changeMode(newmode);
-
lastModeTick = curTick;
themode = newmode;
}
@@ -226,31 +226,27 @@ Statistics::swpipl(int ipl)
}
void
-Statistics::mode(cpu_mode newmode, ExecContext *xc)
+Statistics::mode(cpu_mode newmode, ThreadContext *tc)
{
- Addr pcbb = xc->readMiscReg(AlphaISA::IPR_PALtemp23);
+ Addr pcbb = tc->readMiscReg(AlphaISA::IPR_PALtemp23);
- if ((newmode == kernel || newmode == interrupt) &&
- pcbb == idleProcess)
+ if (newmode == kernel && pcbb == idleProcess)
newmode = idle;
- if (bin_int == false && newmode == interrupt)
- newmode = kernel;
-
- changeMode(newmode, xc);
+ changeMode(newmode, tc);
}
void
-Statistics::context(Addr oldpcbb, Addr newpcbb, ExecContext *xc)
+Statistics::context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc)
{
assert(themode != user);
_swap_context++;
- changeMode(newpcbb == idleProcess ? idle : kernel, xc);
+ changeMode(newpcbb == idleProcess ? idle : kernel, tc);
}
void
-Statistics::callpal(int code, ExecContext *xc)
+Statistics::callpal(int code, ThreadContext *tc)
{
if (!PAL::name(code))
return;
@@ -259,17 +255,12 @@ Statistics::callpal(int code, ExecContext *xc)
switch (code) {
case PAL::callsys: {
- int number = xc->readIntReg(0);
+ int number = tc->readIntReg(0);
if (SystemCalls<Tru64>::validSyscallNumber(number)) {
int cvtnum = SystemCalls<Tru64>::convert(number);
_syscall[cvtnum]++;
}
} break;
-
- case PAL::swpctx:
- if (xc->getSystemPtr()->kernelBinning)
- xc->getSystemPtr()->kernelBinning->palSwapContext(xc);
- break;
}
}
diff --git a/src/kern/kernel_stats.hh b/src/kern/kernel_stats.hh
index 16ec721d0..c691ad8cf 100644
--- a/src/kern/kernel_stats.hh
+++ b/src/kern/kernel_stats.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __KERNEL_STATS_HH__
@@ -37,104 +40,26 @@
#include "cpu/static_inst.hh"
class BaseCPU;
-class ExecContext;
+class ThreadContext;
class FnEvent;
// What does kernel stats expect is included?
class System;
namespace Kernel {
-enum cpu_mode { kernel, user, idle, interrupt, cpu_mode_num };
+enum cpu_mode { kernel, user, idle, cpu_mode_num };
extern const char *modestr[];
-class Binning
-{
- private:
- std::string myname;
- System *system;
-
- private:
- // lisa's binning stuff
- struct fnCall
- {
- Stats::MainBin *myBin;
- std::string name;
- };
-
- struct SWContext
- {
- Counter calls;
- std::stack<fnCall *> callStack;
- };
-
- std::map<const std::string, Stats::MainBin *> fnBins;
- std::map<const Addr, SWContext *> swCtxMap;
-
- std::multimap<const std::string, std::string> callerMap;
- void populateMap(std::string caller, std::string callee);
-
- std::vector<FnEvent *> fnEvents;
-
- Stats::Scalar<> fnCalls;
-
- Stats::MainBin *getBin(const std::string &name);
- bool findCaller(std::string, std::string) const;
-
- SWContext *findContext(Addr pcb);
- bool addContext(Addr pcb, SWContext *ctx)
- {
- return (swCtxMap.insert(std::make_pair(pcb, ctx))).second;
- }
-
- void remContext(Addr pcb)
- {
- swCtxMap.erase(pcb);
- }
-
- void dumpState() const;
-
- SWContext *swctx;
- std::vector<std::string> binned_fns;
-
- private:
- Stats::MainBin *modeBin[cpu_mode_num];
-
- public:
- const bool bin;
- const bool fnbin;
-
- cpu_mode themode;
- void palSwapContext(ExecContext *xc);
- void execute(ExecContext *xc, StaticInstPtr inst);
- void call(ExecContext *xc, Stats::MainBin *myBin);
- void changeMode(cpu_mode mode);
-
- public:
- Binning(System *sys);
- virtual ~Binning();
-
- const std::string name() const { return myname; }
- void regStats(const std::string &name);
-
- public:
- virtual void serialize(std::ostream &os);
- virtual void unserialize(Checkpoint *cp, const std::string &section);
-};
-
class Statistics : public Serializable
{
private:
- friend class Binning;
-
- private:
std::string myname;
Addr idleProcess;
cpu_mode themode;
Tick lastModeTick;
- bool bin_int;
- void changeMode(cpu_mode newmode, ExecContext *xc);
+ void changeMode(cpu_mode newmode, ThreadContext *tc);
private:
Stats::Scalar<> _arm;
@@ -176,11 +101,11 @@ class Statistics : public Serializable
void ivle() { _ivle++; }
void hwrei() { _hwrei++; }
void swpipl(int ipl);
- void mode(cpu_mode newmode, ExecContext *xc);
- void context(Addr oldpcbb, Addr newpcbb, ExecContext *xc);
- void callpal(int code, ExecContext *xc);
+ void mode(cpu_mode newmode, ThreadContext *tc);
+ void context(Addr oldpcbb, Addr newpcbb, ThreadContext *tc);
+ void callpal(int code, ThreadContext *tc);
- void setIdleProcess(Addr idle, ExecContext *xc);
+ void setIdleProcess(Addr idle, ThreadContext *tc);
public:
virtual void serialize(std::ostream &os);
diff --git a/src/kern/linux/events.cc b/src/kern/linux/events.cc
index b688e9dd0..289ece5ce 100644
--- a/src/kern/linux/events.cc
+++ b/src/kern/linux/events.cc
@@ -24,11 +24,14 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include "arch/arguments.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/linux/events.hh"
#include "kern/linux/printk.hh"
#include "kern/system_events.hh"
@@ -38,17 +41,17 @@
namespace Linux {
void
-DebugPrintkEvent::process(ExecContext *xc)
+DebugPrintkEvent::process(ThreadContext *tc)
{
if (DTRACE(DebugPrintf)) {
if (!raw) {
- StringWrap name(xc->getSystemPtr()->name() + ".dprintk");
+ StringWrap name(tc->getSystemPtr()->name() + ".dprintk");
DPRINTFN("");
}
- AlphaISA::AlphaArguments args(xc);
+ AlphaISA::AlphaArguments args(tc);
Printk(args);
- SkipFuncEvent::process(xc);
+ SkipFuncEvent::process(tc);
}
}
diff --git a/src/kern/linux/events.hh b/src/kern/linux/events.hh
index 95c268976..b0510c18f 100644
--- a/src/kern/linux/events.hh
+++ b/src/kern/linux/events.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __KERN_LINUX_EVENTS_HH__
@@ -42,7 +45,7 @@ class DebugPrintkEvent : public SkipFuncEvent
DebugPrintkEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool r = false)
: SkipFuncEvent(q, desc, addr), raw(r) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *xc);
};
}
diff --git a/src/kern/linux/linux.hh b/src/kern/linux/linux.hh
index 63e0dd5ca..e3f554a22 100644
--- a/src/kern/linux/linux.hh
+++ b/src/kern/linux/linux.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __LINUX_HH__
@@ -67,7 +69,7 @@ class Linux {
typedef uint32_t gid_t;
//@}
-#if BSD_HOST
+#if NO_STAT64
typedef struct stat hst_stat;
typedef struct stat hst_stat64;
#else
@@ -174,7 +176,7 @@ class Linux {
/// Helper function to convert a host stat buffer to a target stat
/// buffer. Also copies the target buffer out to the simulated
/// memory space. Used by stat(), fstat(), and lstat().
-#if !BSD_HOST
+#if !NO_STAT64
static void
copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host)
{
diff --git a/src/kern/linux/linux_syscalls.cc b/src/kern/linux/linux_syscalls.cc
index c85b6d28f..7c2821dec 100644
--- a/src/kern/linux/linux_syscalls.cc
+++ b/src/kern/linux/linux_syscalls.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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/linux/linux_syscalls.hh"
diff --git a/src/kern/linux/linux_syscalls.hh b/src/kern/linux/linux_syscalls.hh
index 7f2a08ea9..65616e862 100644
--- a/src/kern/linux/linux_syscalls.hh
+++ b/src/kern/linux/linux_syscalls.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __KERN_LINUX_LINUX_SYSCALLS_HH__
diff --git a/src/kern/linux/printk.cc b/src/kern/linux/printk.cc
index 918b8dabe..004d1be2f 100644
--- a/src/kern/linux/printk.cc
+++ b/src/kern/linux/printk.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <sys/types.h>
diff --git a/src/kern/linux/printk.hh b/src/kern/linux/printk.hh
index b88c40f5e..5ddf0a018 100644
--- a/src/kern/linux/printk.hh
+++ b/src/kern/linux/printk.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __PRINTK_HH__
diff --git a/src/kern/linux/sched.hh b/src/kern/linux/sched.hh
index a11fa590d..f849cee30 100644
--- a/src/kern/linux/sched.hh
+++ b/src/kern/linux/sched.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#ifndef __KERN_LINUX_SCHED_HH__
diff --git a/src/kern/solaris/solaris.hh b/src/kern/solaris/solaris.hh
index e2b61d613..b819fb6d2 100644
--- a/src/kern/solaris/solaris.hh
+++ b/src/kern/solaris/solaris.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SOLARIS_HH__
@@ -72,7 +74,7 @@ class Solaris {
typedef uint32_t nlink_t;
//@}
-#if BSD_HOST
+#if NO_STAT64
typedef struct stat hst_stat;
typedef struct stat hst_stat64;
#else
@@ -175,7 +177,7 @@ class Solaris {
/// Helper function to convert a host stat buffer to a target stat
/// buffer. Also copies the target buffer out to the simulated
/// memory space. Used by stat(), fstat(), and lstat().
-#if !BSD_HOST
+#if !NO_STAT64
static void
copyOutStatBuf(TranslatingPort *mem, Addr addr, hst_stat *host)
{
diff --git a/src/kern/system_events.cc b/src/kern/system_events.cc
index fd5c12e44..177ce96d1 100644
--- a/src/kern/system_events.cc
+++ b/src/kern/system_events.cc
@@ -24,10 +24,13 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
#include "cpu/base.hh"
-#include "cpu/cpu_exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/kernel_stats.hh"
#include "kern/system_events.hh"
#include "sim/system.hh"
@@ -35,57 +38,28 @@
using namespace TheISA;
void
-SkipFuncEvent::process(ExecContext *xc)
+SkipFuncEvent::process(ThreadContext *tc)
{
- Addr newpc = xc->readIntReg(ReturnAddressReg);
+ Addr newpc = tc->readIntReg(ReturnAddressReg);
DPRINTF(PCEvent, "skipping %s: pc=%x, newpc=%x\n", description,
- xc->readPC(), newpc);
+ tc->readPC(), newpc);
- xc->setPC(newpc);
- xc->setNextPC(xc->readPC() + sizeof(TheISA::MachInst));
+ tc->setPC(newpc);
+ tc->setNextPC(tc->readPC() + sizeof(TheISA::MachInst));
/*
- BranchPred *bp = xc->getCpuPtr()->getBranchPred();
+ BranchPred *bp = tc->getCpuPtr()->getBranchPred();
if (bp != NULL) {
- bp->popRAS(xc->getThreadNum());
+ bp->popRAS(tc->getThreadNum());
}
*/
}
-
-FnEvent::FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
- Stats::MainBin *bin)
- : PCEvent(q, desc, addr), _name(desc), mybin(bin)
-{
-}
-
-void
-FnEvent::process(ExecContext *xc)
-{
- if (xc->misspeculating())
- return;
-
- xc->getSystemPtr()->kernelBinning->call(xc, mybin);
-}
-
void
-IdleStartEvent::process(ExecContext *xc)
+IdleStartEvent::process(ThreadContext *tc)
{
- xc->getCpuPtr()->kernelStats->setIdleProcess(
- xc->readMiscReg(AlphaISA::IPR_PALtemp23), xc);
+ if (tc->getKernelStats())
+ tc->getKernelStats()->setIdleProcess(
+ tc->readMiscReg(AlphaISA::IPR_PALtemp23), tc);
remove();
}
-
-void
-InterruptStartEvent::process(ExecContext *xc)
-{
- xc->getCpuPtr()->kernelStats->mode(Kernel::interrupt, xc);
-}
-
-void
-InterruptEndEvent::process(ExecContext *xc)
-{
- // We go back to kernel, if we are user, inside the rti
- // pal code we will get switched to user because of the ICM write
- xc->getCpuPtr()->kernelStats->mode(Kernel::kernel, xc);
-}
diff --git a/src/kern/system_events.hh b/src/kern/system_events.hh
index 246140a09..93b5eb528 100644
--- a/src/kern/system_events.hh
+++ b/src/kern/system_events.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __SYSTEM_EVENTS_HH__
@@ -39,20 +43,7 @@ class SkipFuncEvent : public PCEvent
SkipFuncEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
- virtual void process(ExecContext *xc);
-};
-
-class FnEvent : public PCEvent
-{
- public:
- FnEvent(PCEventQueue *q, const std::string &desc, Addr addr,
- Stats::MainBin *bin);
- virtual void process(ExecContext *xc);
- std::string myname() const { return _name; }
-
- private:
- std::string _name;
- Stats::MainBin *mybin;
+ virtual void process(ThreadContext *tc);
};
class IdleStartEvent : public PCEvent
@@ -61,26 +52,7 @@ class IdleStartEvent : public PCEvent
IdleStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr)
{}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
-class InterruptStartEvent : public PCEvent
-{
- public:
- InterruptStartEvent(PCEventQueue *q, const std::string &desc, Addr addr)
- : PCEvent(q, desc, addr)
- {}
- virtual void process(ExecContext *xc);
-};
-
-class InterruptEndEvent : public PCEvent
-{
- public:
- InterruptEndEvent(PCEventQueue *q, const std::string &desc, Addr addr)
- : PCEvent(q, desc, addr)
- {}
- virtual void process(ExecContext *xc);
-};
-
-
#endif // __SYSTEM_EVENTS_HH__
diff --git a/src/kern/tru64/dump_mbuf.cc b/src/kern/tru64/dump_mbuf.cc
index c3c37531a..8f88f8904 100644
--- a/src/kern/tru64/dump_mbuf.cc
+++ b/src/kern/tru64/dump_mbuf.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
@@ -32,7 +34,7 @@
#include "base/cprintf.hh"
#include "base/trace.hh"
#include "base/loader/symtab.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "kern/tru64/mbuf.hh"
#include "sim/host.hh"
#include "sim/system.hh"
@@ -47,11 +49,11 @@ namespace tru64 {
void
DumpMbuf(AlphaArguments args)
{
- ExecContext *xc = args.getExecContext();
+ ThreadContext *tc = args.getThreadContext();
Addr addr = (Addr)args;
struct mbuf m;
- CopyOut(xc, &m, addr, sizeof(m));
+ CopyOut(tc, &m, addr, sizeof(m));
int count = m.m_pkthdr.len;
@@ -62,8 +64,8 @@ DumpMbuf(AlphaArguments args)
ccprintf(DebugOut(), "m=%#lx, m->m_data=%#lx, m->m_len=%d\n",
addr, m.m_data, m.m_len);
char *buffer = new char[m.m_len];
- CopyOut(xc, buffer, m.m_data, m.m_len);
- Trace::dataDump(curTick, xc->getSystemPtr()->name(), (uint8_t *)buffer,
+ CopyOut(tc, buffer, m.m_data, m.m_len);
+ Trace::dataDump(curTick, tc->getSystemPtr()->name(), (uint8_t *)buffer,
m.m_len);
delete [] buffer;
@@ -71,7 +73,7 @@ DumpMbuf(AlphaArguments args)
if (!m.m_next)
break;
- CopyOut(xc, &m, m.m_next, sizeof(m));
+ CopyOut(tc, &m, m.m_next, sizeof(m));
}
}
diff --git a/src/kern/tru64/dump_mbuf.hh b/src/kern/tru64/dump_mbuf.hh
index 9e1698ff1..25c6fd31d 100644
--- a/src/kern/tru64/dump_mbuf.hh
+++ b/src/kern/tru64/dump_mbuf.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __DUMP_MBUF_HH__
diff --git a/src/kern/tru64/mbuf.hh b/src/kern/tru64/mbuf.hh
index 93424858f..cb5a84a7e 100644
--- a/src/kern/tru64/mbuf.hh
+++ b/src/kern/tru64/mbuf.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __MBUF_HH__
diff --git a/src/kern/tru64/printf.cc b/src/kern/tru64/printf.cc
index 319d36673..29dd443d2 100644
--- a/src/kern/tru64/printf.cc
+++ b/src/kern/tru64/printf.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
diff --git a/src/kern/tru64/printf.hh b/src/kern/tru64/printf.hh
index 61236e83a..f6a4544ad 100644
--- a/src/kern/tru64/printf.hh
+++ b/src/kern/tru64/printf.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __PRINTF_HH__
diff --git a/src/kern/tru64/tru64.hh b/src/kern/tru64/tru64.hh
index 91db5bb84..d2b7c862f 100644
--- a/src/kern/tru64/tru64.hh
+++ b/src/kern/tru64/tru64.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __TRU64_HH__
@@ -576,23 +579,23 @@ class Tru64 {
/// Target getdirentries() handler.
static SyscallReturn
getdirentriesFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace TheISA;
#ifdef __CYGWIN__
panic("getdirent not implemented on cygwin!");
#else
- int fd = process->sim_fd(xc->getSyscallArg(0));
- Addr tgt_buf = xc->getSyscallArg(1);
- int tgt_nbytes = xc->getSyscallArg(2);
- Addr tgt_basep = xc->getSyscallArg(3);
+ 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);
char * const host_buf = new char[tgt_nbytes];
// just pass basep through uninterpreted.
TypedBufferArg<int64_t> basep(tgt_basep);
- basep.copyIn(xc->getMemPort());
+ basep.copyIn(tc->getMemPort());
long host_basep = (off_t)htog((int64_t)*basep);
int host_result = getdirentries(fd, host_buf, tgt_nbytes, &host_basep);
@@ -619,7 +622,7 @@ class Tru64 {
tgt_dp->d_reclen = tgt_bufsize;
tgt_dp->d_namlen = namelen;
strcpy(tgt_dp->d_name, host_dp->d_name);
- tgt_dp.copyOut(xc->getMemPort());
+ tgt_dp.copyOut(tc->getMemPort());
tgt_buf_ptr += tgt_bufsize;
host_buf_ptr += host_dp->d_reclen;
@@ -628,7 +631,7 @@ class Tru64 {
delete [] host_buf;
*basep = htog((int64_t)host_basep);
- basep.copyOut(xc->getMemPort());
+ basep.copyOut(tc->getMemPort());
return tgt_buf_ptr - tgt_buf;
#endif
@@ -637,27 +640,27 @@ class Tru64 {
/// Target sigreturn() handler.
static SyscallReturn
sigreturnFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace TheISA;
using TheISA::RegFile;
- TypedBufferArg<Tru64::sigcontext> sc(xc->getSyscallArg(0));
+ TypedBufferArg<Tru64::sigcontext> sc(tc->getSyscallArg(0));
- sc.copyIn(xc->getMemPort());
+ sc.copyIn(tc->getMemPort());
// Restore state from sigcontext structure.
// Note that we'll advance PC <- NPC before the end of the cycle,
// so we need to restore the desired PC into NPC.
// The current regs->pc will get clobbered.
- xc->setNextPC(htog(sc->sc_pc));
+ tc->setNextPC(htog(sc->sc_pc));
for (int i = 0; i < 31; ++i) {
- xc->setIntReg(i, htog(sc->sc_regs[i]));
- xc->setFloatRegBits(i, htog(sc->sc_fpregs[i]));
+ tc->setIntReg(i, htog(sc->sc_regs[i]));
+ tc->setFloatRegBits(i, htog(sc->sc_fpregs[i]));
}
- xc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr));
+ tc->setMiscReg(TheISA::Fpcr_DepTag, htog(sc->sc_fpcr));
return 0;
}
@@ -670,13 +673,13 @@ class Tru64 {
/// Create a stack region for a thread.
static SyscallReturn
stack_createFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace TheISA;
- TypedBufferArg<Tru64::vm_stack> argp(xc->getSyscallArg(0));
+ TypedBufferArg<Tru64::vm_stack> argp(tc->getSyscallArg(0));
- argp.copyIn(xc->getMemPort());
+ argp.copyIn(tc->getMemPort());
// if the user chose an address, just let them have it. Otherwise
// pick one for them.
@@ -685,7 +688,7 @@ class Tru64 {
int stack_size = (htog(argp->rsize) + htog(argp->ysize) +
htog(argp->gsize));
process->next_thread_stack_base -= stack_size;
- argp.copyOut(xc->getMemPort());
+ argp.copyOut(tc->getMemPort());
}
return 0;
@@ -700,15 +703,15 @@ class Tru64 {
/// region has several structs, some global, some per-RAD, some per-VP.
static SyscallReturn
nxm_task_initFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
using namespace TheISA;
- TypedBufferArg<Tru64::nxm_task_attr> attrp(xc->getSyscallArg(0));
- TypedBufferArg<Addr> configptr_ptr(xc->getSyscallArg(1));
+ TypedBufferArg<Tru64::nxm_task_attr> attrp(tc->getSyscallArg(0));
+ TypedBufferArg<Addr> configptr_ptr(tc->getSyscallArg(1));
- attrp.copyIn(xc->getMemPort());
+ attrp.copyIn(tc->getMemPort());
if (gtoh(attrp->nxm_version) != NXM_LIB_VERSION) {
cerr << "nxm_task_init: thread library version mismatch! "
@@ -749,7 +752,7 @@ class Tru64 {
config->nxm_slot_state = htog(slot_state_addr);
config->nxm_rad[0] = htog(rad_state_addr);
- config.copyOut(xc->getMemPort());
+ config.copyOut(tc->getMemPort());
// initialize the slot_state array and copy it out
TypedBufferArg<Tru64::nxm_slot_state_t> slot_state(slot_state_addr,
@@ -762,7 +765,7 @@ class Tru64 {
(i == 0) ? Tru64::NXM_SLOT_BOUND : Tru64::NXM_SLOT_AVAIL;
}
- slot_state.copyOut(xc->getMemPort());
+ slot_state.copyOut(tc->getMemPort());
// same for the per-RAD "shared" struct. Note that we need to
// allocate extra bytes for the per-VP array which is embedded at
@@ -786,7 +789,7 @@ class Tru64 {
ssp->nxm_sysevent = htog(0);
if (i == 0) {
- uint64_t uniq = xc->readMiscReg(TheISA::Uniq_DepTag);
+ uint64_t uniq = tc->readMiscReg(TheISA::Uniq_DepTag);
ssp->nxm_u.pth_id = htog(uniq + gtoh(attrp->nxm_uniq_offset));
ssp->nxm_u.nxm_active = htog(uniq | 1);
}
@@ -796,13 +799,13 @@ class Tru64 {
}
}
- rad_state.copyOut(xc->getMemPort());
+ rad_state.copyOut(tc->getMemPort());
//
// copy pointer to shared config area out to user
//
*configptr_ptr = htog(config_addr);
- configptr_ptr.copyOut(xc->getMemPort());
+ configptr_ptr.copyOut(tc->getMemPort());
// Register this as a valid address range with the process
process->nxm_start = base_addr;
@@ -811,40 +814,40 @@ class Tru64 {
return 0;
}
- /// Initialize execution context.
+ /// Initialize thread context.
static void
- init_exec_context(ExecContext *ec,
+ init_thread_context(ThreadContext *tc,
Tru64::nxm_thread_attr *attrp, uint64_t uniq_val)
{
using namespace TheISA;
- ec->clearArchRegs();
+ tc->clearArchRegs();
- ec->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0));
- ec->setIntReg(27/*t12*/, gtoh(attrp->registers.pc));
- ec->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp));
- ec->setMiscReg(TheISA::Uniq_DepTag, uniq_val);
+ tc->setIntReg(TheISA::ArgumentReg0, gtoh(attrp->registers.a0));
+ tc->setIntReg(27/*t12*/, gtoh(attrp->registers.pc));
+ tc->setIntReg(TheISA::StackPointerReg, gtoh(attrp->registers.sp));
+ tc->setMiscReg(TheISA::Uniq_DepTag, uniq_val);
- ec->setPC(gtoh(attrp->registers.pc));
- ec->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst));
+ tc->setPC(gtoh(attrp->registers.pc));
+ tc->setNextPC(gtoh(attrp->registers.pc) + sizeof(TheISA::MachInst));
- ec->activate();
+ tc->activate();
}
/// Create thread.
static SyscallReturn
nxm_thread_createFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
using namespace TheISA;
- TypedBufferArg<Tru64::nxm_thread_attr> attrp(xc->getSyscallArg(0));
- TypedBufferArg<uint64_t> kidp(xc->getSyscallArg(1));
- int thread_index = xc->getSyscallArg(2);
+ TypedBufferArg<Tru64::nxm_thread_attr> attrp(tc->getSyscallArg(0));
+ TypedBufferArg<uint64_t> kidp(tc->getSyscallArg(1));
+ int thread_index = tc->getSyscallArg(2);
// get attribute args
- attrp.copyIn(xc->getMemPort());
+ attrp.copyIn(tc->getMemPort());
if (gtoh(attrp->version) != NXM_LIB_VERSION) {
cerr << "nxm_thread_create: thread library version mismatch! "
@@ -869,7 +872,7 @@ class Tru64 {
TypedBufferArg<Tru64::nxm_shared> rad_state(0x14000,
rad_state_size);
- rad_state.copyIn(xc->getMemPort());
+ rad_state.copyIn(tc->getMemPort());
uint64_t uniq_val = gtoh(attrp->pthid) - gtoh(rad_state->nxm_uniq_offset);
@@ -880,7 +883,7 @@ class Tru64 {
// This is supposed to be a port number. Make something up.
*kidp = htog(99);
- kidp.copyOut(xc->getMemPort());
+ kidp.copyOut(tc->getMemPort());
return 0;
} else if (gtoh(attrp->type) == Tru64::NXM_TYPE_VP) {
@@ -894,7 +897,7 @@ class Tru64 {
ssp->nxm_u.pth_id = attrp->pthid;
ssp->nxm_u.nxm_active = htog(uniq_val | 1);
- rad_state.copyOut(xc->getMemPort());
+ rad_state.copyOut(tc->getMemPort());
Addr slot_state_addr = 0x12000 + sizeof(Tru64::nxm_config_info);
int slot_state_size =
@@ -904,7 +907,7 @@ class Tru64 {
slot_state(slot_state_addr,
slot_state_size);
- slot_state.copyIn(xc->getMemPort());
+ slot_state.copyIn(tc->getMemPort());
if (slot_state[thread_index] != Tru64::NXM_SLOT_AVAIL) {
cerr << "nxm_thread_createFunc: requested VP slot "
@@ -916,21 +919,21 @@ class Tru64 {
// doesn't work anyway
slot_state[thread_index] = Tru64::NXM_SLOT_BOUND;
- slot_state.copyOut(xc->getMemPort());
+ slot_state.copyOut(tc->getMemPort());
- // Find a free simulator execution context.
+ // Find a free simulator thread context.
for (int i = 0; i < process->numCpus(); ++i) {
- ExecContext *xc = process->execContexts[i];
+ ThreadContext *tc = process->threadContexts[i];
- if (xc->status() == ExecContext::Unallocated) {
+ if (tc->status() == ThreadContext::Suspended) {
// inactive context... grab it
- init_exec_context(xc, attrp, uniq_val);
+ 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(xc->getMemPort());
+ kidp.copyOut(tc->getMemPort());
return 0;
}
@@ -951,7 +954,7 @@ class Tru64 {
/// Thread idle call (like yield()).
static SyscallReturn
nxm_idleFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 0;
}
@@ -959,17 +962,17 @@ class Tru64 {
/// Block thread.
static SyscallReturn
nxm_thread_blockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
- uint64_t tid = xc->getSyscallArg(0);
- uint64_t secs = xc->getSyscallArg(1);
- uint64_t flags = xc->getSyscallArg(2);
- uint64_t action = xc->getSyscallArg(3);
- uint64_t usecs = xc->getSyscallArg(4);
+ 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);
- cout << xc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " "
+ cout << tc->getCpuPtr()->name() << ": nxm_thread_block " << tid << " "
<< secs << " " << flags << " " << action << " " << usecs << endl;
return 0;
@@ -978,17 +981,17 @@ class Tru64 {
/// block.
static SyscallReturn
nxm_blockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
- Addr uaddr = xc->getSyscallArg(0);
- uint64_t val = xc->getSyscallArg(1);
- uint64_t secs = xc->getSyscallArg(2);
- uint64_t usecs = xc->getSyscallArg(3);
- uint64_t flags = xc->getSyscallArg(4);
+ 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);
- BaseCPU *cpu = xc->getCpuPtr();
+ BaseCPU *cpu = tc->getCpuPtr();
cout << cpu->name() << ": nxm_block "
<< hex << uaddr << dec << " " << val
@@ -1001,13 +1004,13 @@ class Tru64 {
/// Unblock thread.
static SyscallReturn
nxm_unblockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace std;
- Addr uaddr = xc->getSyscallArg(0);
+ Addr uaddr = tc->getSyscallArg(0);
- cout << xc->getCpuPtr()->name() << ": nxm_unblock "
+ cout << tc->getCpuPtr()->name() << ": nxm_unblock "
<< hex << uaddr << dec << endl;
return 0;
@@ -1016,7 +1019,7 @@ class Tru64 {
/// Switch thread priority.
static SyscallReturn
swtch_priFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// Attempts to switch to another runnable thread (if there is
// one). Returns false if there are no other threads to run
@@ -1029,7 +1032,7 @@ class Tru64 {
}
- /// Activate exec context waiting on a channel. Just activate one
+ /// Activate thread context waiting on a channel. Just activate one
/// by default.
static int
activate_waiting_context(Addr uaddr, Process *process,
@@ -1045,8 +1048,8 @@ class Tru64 {
while (i != end && (num_activated == 0 || activate_all)) {
if (i->waitChan == uaddr) {
// found waiting process: make it active
- ExecContext *newCtx = i->waitingContext;
- assert(newCtx->status() == ExecContext::Suspended);
+ ThreadContext *newCtx = i->waitingContext;
+ assert(newCtx->status() == ThreadContext::Suspended);
newCtx->activate();
// get rid of this record
@@ -1063,32 +1066,32 @@ class Tru64 {
/// M5 hacked-up lock acquire.
static void
- m5_lock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+ m5_lock_mutex(Addr uaddr, Process *process, ThreadContext *tc)
{
using namespace TheISA;
TypedBufferArg<uint64_t> lockp(uaddr);
- lockp.copyIn(xc->getMemPort());
+ lockp.copyIn(tc->getMemPort());
if (gtoh(*lockp) == 0) {
// lock is free: grab it
*lockp = htog(1);
- lockp.copyOut(xc->getMemPort());
+ lockp.copyOut(tc->getMemPort());
} else {
// lock is busy: disable until free
- process->waitList.push_back(Process::WaitRec(uaddr, xc));
- xc->suspend();
+ process->waitList.push_back(Process::WaitRec(uaddr, tc));
+ tc->suspend();
}
}
/// M5 unlock call.
static void
- m5_unlock_mutex(Addr uaddr, Process *process, ExecContext *xc)
+ m5_unlock_mutex(Addr uaddr, Process *process, ThreadContext *tc)
{
TypedBufferArg<uint64_t> lockp(uaddr);
- lockp.copyIn(xc->getMemPort());
+ lockp.copyIn(tc->getMemPort());
assert(*lockp != 0);
// Check for a process waiting on the lock.
@@ -1097,18 +1100,18 @@ class Tru64 {
// clear lock field if no waiting context is taking over the lock
if (num_waiting == 0) {
*lockp = 0;
- lockp.copyOut(xc->getMemPort());
+ lockp.copyOut(tc->getMemPort());
}
}
/// Lock acquire syscall handler.
static SyscallReturn
m5_mutex_lockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- Addr uaddr = xc->getSyscallArg(0);
+ Addr uaddr = tc->getSyscallArg(0);
- m5_lock_mutex(uaddr, process, xc);
+ m5_lock_mutex(uaddr, process, tc);
// Return 0 since we will always return to the user with the lock
// acquired. We will just keep the context inactive until that is
@@ -1119,19 +1122,19 @@ class Tru64 {
/// Try lock (non-blocking).
static SyscallReturn
m5_mutex_trylockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace TheISA;
- Addr uaddr = xc->getSyscallArg(0);
+ Addr uaddr = tc->getSyscallArg(0);
TypedBufferArg<uint64_t> lockp(uaddr);
- lockp.copyIn(xc->getMemPort());
+ lockp.copyIn(tc->getMemPort());
if (gtoh(*lockp) == 0) {
// lock is free: grab it
*lockp = htog(1);
- lockp.copyOut(xc->getMemPort());
+ lockp.copyOut(tc->getMemPort());
return 0;
} else {
return 1;
@@ -1141,11 +1144,11 @@ class Tru64 {
/// Unlock syscall handler.
static SyscallReturn
m5_mutex_unlockFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- Addr uaddr = xc->getSyscallArg(0);
+ Addr uaddr = tc->getSyscallArg(0);
- m5_unlock_mutex(uaddr, process, xc);
+ m5_unlock_mutex(uaddr, process, tc);
return 0;
}
@@ -1153,9 +1156,9 @@ class Tru64 {
/// Signal ocndition.
static SyscallReturn
m5_cond_signalFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- Addr cond_addr = xc->getSyscallArg(0);
+ Addr cond_addr = tc->getSyscallArg(0);
// Wake up one process waiting on the condition variable.
activate_waiting_context(cond_addr, process);
@@ -1166,9 +1169,9 @@ class Tru64 {
/// Wake up all processes waiting on the condition variable.
static SyscallReturn
m5_cond_broadcastFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- Addr cond_addr = xc->getSyscallArg(0);
+ Addr cond_addr = tc->getSyscallArg(0);
activate_waiting_context(cond_addr, process, true);
@@ -1178,23 +1181,23 @@ class Tru64 {
/// Wait on a condition.
static SyscallReturn
m5_cond_waitFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
using namespace TheISA;
- Addr cond_addr = xc->getSyscallArg(0);
- Addr lock_addr = xc->getSyscallArg(1);
+ Addr cond_addr = tc->getSyscallArg(0);
+ Addr lock_addr = tc->getSyscallArg(1);
TypedBufferArg<uint64_t> condp(cond_addr);
TypedBufferArg<uint64_t> lockp(lock_addr);
// user is supposed to acquire lock before entering
- lockp.copyIn(xc->getMemPort());
+ lockp.copyIn(tc->getMemPort());
assert(gtoh(*lockp) != 0);
- m5_unlock_mutex(lock_addr, process, xc);
+ m5_unlock_mutex(lock_addr, process, tc);
- process->waitList.push_back(Process::WaitRec(cond_addr, xc));
- xc->suspend();
+ process->waitList.push_back(Process::WaitRec(cond_addr, tc));
+ tc->suspend();
return 0;
}
@@ -1202,10 +1205,10 @@ class Tru64 {
/// Thread exit.
static SyscallReturn
m5_thread_exitFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- assert(xc->status() == ExecContext::Active);
- xc->deallocate();
+ assert(tc->status() == ThreadContext::Active);
+ tc->deallocate();
return 0;
}
@@ -1213,21 +1216,21 @@ class Tru64 {
/// Indirect syscall invocation (call #0).
static SyscallReturn
indirectSyscallFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int new_callnum = xc->getSyscallArg(0);
+ int new_callnum = tc->getSyscallArg(0);
LiveProcess *lp = dynamic_cast<LiveProcess*>(process);
assert(lp);
for (int i = 0; i < 5; ++i)
- xc->setSyscallArg(i, xc->getSyscallArg(i+1));
+ tc->setSyscallArg(i, tc->getSyscallArg(i+1));
SyscallDesc *new_desc = lp->getDesc(new_callnum);
if (desc == NULL)
fatal("Syscall %d out of range", callnum);
- new_desc->doSyscall(new_callnum, process, xc);
+ new_desc->doSyscall(new_callnum, process, tc);
return 0;
}
diff --git a/src/kern/tru64/tru64_events.cc b/src/kern/tru64/tru64_events.cc
index 69fc5c55d..69638bde1 100644
--- a/src/kern/tru64/tru64_events.cc
+++ b/src/kern/tru64/tru64_events.cc
@@ -24,9 +24,12 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "kern/system_events.hh"
#include "kern/tru64/tru64_events.hh"
@@ -39,23 +42,23 @@
using namespace TheISA;
-//void SkipFuncEvent::process(ExecContext *xc);
+//void SkipFuncEvent::process(ExecContext *tc);
void
-BadAddrEvent::process(ExecContext *xc)
+BadAddrEvent::process(ThreadContext *tc)
{
// The following gross hack is the equivalent function to the
// annotation for vmunix::badaddr in:
// simos/simulation/apps/tcl/osf/tlaser.tcl
- uint64_t a0 = xc->readIntReg(ArgumentReg0);
+ uint64_t a0 = tc->readIntReg(ArgumentReg0);
AddrRangeList resp;
AddrRangeList snoop;
AddrRangeIter iter;
bool found = false;
- xc->getPhysPort()->getPeerAddressRanges(resp, snoop);
+ tc->getPhysPort()->getPeerAddressRanges(resp, snoop);
for(iter = resp.begin(); iter != resp.end(); iter++)
{
if (*iter == (TheISA::K0Seg2Phys(a0) & EV5::PAddrImplMask))
@@ -65,41 +68,41 @@ BadAddrEvent::process(ExecContext *xc)
if (!TheISA::IsK0Seg(a0) || found ) {
DPRINTF(BADADDR, "badaddr arg=%#x bad\n", a0);
- xc->setIntReg(ReturnValueReg, 0x1);
- SkipFuncEvent::process(xc);
+ tc->setIntReg(ReturnValueReg, 0x1);
+ SkipFuncEvent::process(tc);
}
else
DPRINTF(BADADDR, "badaddr arg=%#x good\n", a0);
}
void
-PrintfEvent::process(ExecContext *xc)
+PrintfEvent::process(ThreadContext *tc)
{
if (DTRACE(Printf)) {
- DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": ";
+ DebugOut() << curTick << ": " << tc->getCpuPtr()->name() << ": ";
- AlphaArguments args(xc);
+ AlphaArguments args(tc);
tru64::Printf(args);
}
}
void
-DebugPrintfEvent::process(ExecContext *xc)
+DebugPrintfEvent::process(ThreadContext *tc)
{
if (DTRACE(DebugPrintf)) {
if (!raw)
- DebugOut() << curTick << ": " << xc->getCpuPtr()->name() << ": ";
+ DebugOut() << curTick << ": " << tc->getCpuPtr()->name() << ": ";
- AlphaArguments args(xc);
+ AlphaArguments args(tc);
tru64::Printf(args);
}
}
void
-DumpMbufEvent::process(ExecContext *xc)
+DumpMbufEvent::process(ThreadContext *tc)
{
if (DTRACE(DebugPrintf)) {
- AlphaArguments args(xc);
+ AlphaArguments args(tc);
tru64::DumpMbuf(args);
}
}
diff --git a/src/kern/tru64/tru64_events.hh b/src/kern/tru64/tru64_events.hh
index 9b5bcfea2..6a1ab2e51 100644
--- a/src/kern/tru64/tru64_events.hh
+++ b/src/kern/tru64/tru64_events.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __TRU64_EVENTS_HH__
@@ -34,14 +37,14 @@
#include "cpu/pc_event.hh"
#include "kern/system_events.hh"
-class ExecContext;
+class ThreadContext;
class BadAddrEvent : public SkipFuncEvent
{
public:
BadAddrEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: SkipFuncEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
class PrintfEvent : public PCEvent
@@ -49,7 +52,7 @@ class PrintfEvent : public PCEvent
public:
PrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
class DebugPrintfEvent : public PCEvent
@@ -61,7 +64,7 @@ class DebugPrintfEvent : public PCEvent
DebugPrintfEvent(PCEventQueue *q, const std::string &desc, Addr addr,
bool r = false)
: PCEvent(q, desc, addr), raw(r) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
class DebugPrintfrEvent : public DebugPrintfEvent
@@ -77,7 +80,7 @@ class DumpMbufEvent : public PCEvent
public:
DumpMbufEvent(PCEventQueue *q, const std::string &desc, Addr addr)
: PCEvent(q, desc, addr) {}
- virtual void process(ExecContext *xc);
+ virtual void process(ThreadContext *tc);
};
#endif // __TRU64_EVENTS_HH__
diff --git a/src/kern/tru64/tru64_syscalls.cc b/src/kern/tru64/tru64_syscalls.cc
index 8aa57dbaa..8051b9efb 100644
--- a/src/kern/tru64/tru64_syscalls.cc
+++ b/src/kern/tru64/tru64_syscalls.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "kern/tru64/tru64_syscalls.hh"
diff --git a/src/kern/tru64/tru64_syscalls.hh b/src/kern/tru64/tru64_syscalls.hh
index 69fa9101c..66f5c2d39 100644
--- a/src/kern/tru64/tru64_syscalls.hh
+++ b/src/kern/tru64/tru64_syscalls.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __KERN_TRU64_TRU64_SYSCALLS_HH__
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index 736e8dc81..29ea2e12f 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -25,6 +25,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
*/
/**
@@ -56,7 +59,7 @@ Bridge::Bridge(const std::string &n, int qsa, int qsb,
}
Port *
-Bridge::getPort(const std::string &if_name)
+Bridge::getPort(const std::string &if_name, int idx)
{
BridgePort *port;
@@ -90,7 +93,17 @@ Bridge::BridgePort::recvTiming(Packet *pkt)
DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
pkt->getSrc(), pkt->getDest(), pkt->getAddr());
- if (pkt->isResponse()) {
+ return otherPort->queueForSendTiming(pkt);
+}
+
+
+bool
+Bridge::BridgePort::queueForSendTiming(Packet *pkt)
+{
+ if (queueFull())
+ return false;
+
+ if (pkt->isResponse()) {
// This is a response for a request we forwarded earlier. The
// corresponding PacketBuffer should be stored in the packet's
// senderState field.
@@ -99,22 +112,16 @@ Bridge::BridgePort::recvTiming(Packet *pkt)
// set up new packet dest & senderState based on values saved
// from original request
buf->fixResponse(pkt);
+ DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n",
+ pkt->senderState, buf);
DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest());
delete buf;
}
- return otherPort->queueForSendTiming(pkt);
-}
-
-
-bool
-Bridge::BridgePort::queueForSendTiming(Packet *pkt)
-{
- if (queueFull())
- return false;
-
Tick readyTime = curTick + delay;
PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+ DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n",
+ buf->origSenderState, buf);
// If we're about to put this packet at the head of the queue, we
// need to schedule an event to do the transmit. Otherwise there
@@ -126,43 +133,16 @@ Bridge::BridgePort::queueForSendTiming(Packet *pkt)
sendQueue.push_back(buf);
- // Did we just become blocked? If yes, let other side know.
- if (queueFull())
- otherPort->sendStatusChange(Port::Blocked);
-
return true;
}
-
-void
-Bridge::BridgePort::finishSend(PacketBuffer *buf)
-{
- if (buf->expectResponse) {
- // Must wait for response. We just need to count outstanding
- // responses (in case we want to cap them); PacketBuffer
- // pointer will be recovered on response.
- ++outstandingResponses;
- DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
- outstandingResponses);
- } else {
- // no response expected... deallocate packet buffer now.
- DPRINTF(BusBridge, " successful: no response expected\n");
- delete buf;
- }
-
- // If there are more packets to send, schedule event to try again.
- if (!sendQueue.empty()) {
- buf = sendQueue.front();
- sendEvent.schedule(std::max(buf->ready, curTick + 1));
- }
-}
-
-
void
Bridge::BridgePort::trySend()
{
assert(!sendQueue.empty());
+ bool was_full = queueFull();
+
PacketBuffer *buf = sendQueue.front();
assert(buf->ready <= curTick);
@@ -176,20 +156,41 @@ Bridge::BridgePort::trySend()
// send successful
sendQueue.pop_front();
buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
- finishSend(buf);
+
+ if (buf->expectResponse) {
+ // Must wait for response. We just need to count outstanding
+ // responses (in case we want to cap them); PacketBuffer
+ // pointer will be recovered on response.
+ ++outstandingResponses;
+ DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
+ outstandingResponses);
+ } else {
+ // no response expected... deallocate packet buffer now.
+ DPRINTF(BusBridge, " successful: no response expected\n");
+ delete buf;
+ }
+
+ // If there are more packets to send, schedule event to try again.
+ if (!sendQueue.empty()) {
+ buf = sendQueue.front();
+ sendEvent.schedule(std::max(buf->ready, curTick + 1));
+ }
+ // Let things start sending again
+ if (was_full) {
+ DPRINTF(BusBridge, "Queue was full, sending retry\n");
+ otherPort->sendRetry();
+ }
+
} else {
DPRINTF(BusBridge, " unsuccessful\n");
}
}
-Packet *
+void
Bridge::BridgePort::recvRetry()
{
- PacketBuffer *buf = sendQueue.front();
- Packet *pkt = buf->pkt;
- finishSend(buf);
- return pkt;
+ trySend();
}
/** Function called by the port when the bus is receiving a Atomic
@@ -223,9 +224,6 @@ Bridge::BridgePort::recvFunctional(Packet *pkt)
void
Bridge::BridgePort::recvStatusChange(Port::Status status)
{
- if (status == Port::Blocked || status == Port::Unblocked)
- return;
-
otherPort->sendStatusChange(status);
}
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
index 8a5cbf92a..b3525d3e0 100644
--- a/src/mem/bridge.hh
+++ b/src/mem/bridge.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
*/
/**
@@ -38,7 +41,6 @@
#include <inttypes.h>
#include <queue>
-
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/port.hh"
@@ -77,7 +79,8 @@ class Bridge : public MemObject
origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
expectResponse(_pkt->needsResponse())
{
- pkt->senderState = this;
+ if (!pkt->isResponse())
+ pkt->senderState = this;
}
void fixResponse(Packet *pkt)
@@ -146,7 +149,7 @@ class Bridge : public MemObject
/** When receiving a retry request from the peer port,
pass it to the bridge. */
- virtual Packet* recvRetry();
+ virtual void recvRetry();
/** When receiving a Atomic requestfrom the peer port,
pass it to the bridge. */
@@ -174,7 +177,7 @@ class Bridge : public MemObject
public:
/** A function used to return the port associated with this bus object. */
- virtual Port *getPort(const std::string &if_name);
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void init();
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index cfc99a64f..19a3dc9e4 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -36,7 +38,7 @@
#include "sim/builder.hh"
Port *
-Bus::getPort(const std::string &if_name)
+Bus::getPort(const std::string &if_name, int idx)
{
// if_name ignored? forced to be empty?
int id = interfaces.size();
@@ -72,9 +74,35 @@ Bus::recvTiming(Packet *pkt)
assert(dest != pkt->getSrc()); // catch infinite loops
port = interfaces[dest];
}
- return port->sendTiming(pkt);
+ if (port->sendTiming(pkt)) {
+ // packet was successfully sent, just return true.
+ return true;
+ }
+
+ // packet not successfully sent
+ retryList.push_back(interfaces[pkt->getSrc()]);
+ return false;
}
+void
+Bus::recvRetry(int id)
+{
+ // Go through all the elements on the list calling sendRetry on each
+ // This is not very efficient at all but it works. Ultimately we should end
+ // up with something that is more intelligent.
+ int initialSize = retryList.size();
+ int i;
+ Port *p;
+
+ for (i = 0; i < initialSize; i++) {
+ assert(retryList.size() > 0);
+ p = retryList.front();
+ retryList.pop_front();
+ p->sendRetry();
+ }
+}
+
+
Port *
Bus::findPort(Addr addr, int id)
{
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index 5eeb07904..9c7054b94 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
/**
@@ -67,6 +70,10 @@ class Bus : public MemObject
transaction.*/
void recvFunctional(Packet *pkt);
+ /** Timing function called by port when it is once again able to process
+ * requests. */
+ void recvRetry(int id);
+
/** Function called by the port when the bus is recieving a status change.*/
void recvStatusChange(Port::Status status, int id);
@@ -126,6 +133,11 @@ class Bus : public MemObject
virtual void recvStatusChange(Status status)
{ bus->recvStatusChange(status, id); }
+ /** When reciving a retry from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRetry()
+ { bus->recvRetry(id); }
+
// This should return all the 'owned' addresses that are
// downstream from this bus, yes? That is, the union of all
// the 'owned' address ranges of all the other interfaces on
@@ -143,10 +155,14 @@ class Bus : public MemObject
connected to this bus.*/
std::vector<Port*> interfaces;
+ /** An array of pointers to ports that retry should be called on because the
+ * original send failed for whatever reason.*/
+ std::list<Port*> retryList;
+
public:
/** A function used to return the port associated with this bus object. */
- virtual Port *getPort(const std::string &if_name);
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
virtual void init();
diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc
new file mode 100644
index 000000000..aaaf1bdef
--- /dev/null
+++ b/src/mem/cache/base_cache.cc
@@ -0,0 +1,341 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definition of BaseCache functions.
+ */
+
+#include "mem/cache/base_cache.hh"
+#include "cpu/smt.hh"
+#include "cpu/base.hh"
+
+using namespace std;
+
+BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
+ bool _isCpuSide)
+ : Port(_name), cache(_cache), isCpuSide(_isCpuSide)
+{
+ blocked = false;
+ //Start ports at null if more than one is created we should panic
+ //cpuSidePort = NULL;
+ //memSidePort = NULL;
+}
+
+void
+BaseCache::CachePort::recvStatusChange(Port::Status status)
+{
+ cache->recvStatusChange(status, isCpuSide);
+}
+
+void
+BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+{
+ cache->getAddressRanges(resp, snoop);
+}
+
+int
+BaseCache::CachePort::deviceBlockSize()
+{
+ return cache->getBlockSize();
+}
+
+bool
+BaseCache::CachePort::recvTiming(Packet *pkt)
+{
+ return cache->doTimingAccess(pkt, this, isCpuSide);
+}
+
+Tick
+BaseCache::CachePort::recvAtomic(Packet *pkt)
+{
+ return cache->doAtomicAccess(pkt, isCpuSide);
+}
+
+void
+BaseCache::CachePort::recvFunctional(Packet *pkt)
+{
+ cache->doFunctionalAccess(pkt, isCpuSide);
+}
+
+void
+BaseCache::CachePort::setBlocked()
+{
+ blocked = true;
+}
+
+void
+BaseCache::CachePort::clearBlocked()
+{
+ blocked = false;
+}
+
+Port*
+BaseCache::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "")
+ {
+ if(cpuSidePort == NULL)
+ cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
+ return cpuSidePort;
+ }
+ if (if_name == "functional")
+ {
+ if(cpuSidePort == NULL)
+ cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
+ return cpuSidePort;
+ }
+ else if (if_name == "mem_side")
+ {
+ if (memSidePort != NULL)
+ panic("Already have a mem side for this cache\n");
+ memSidePort = new CachePort(name() + "-mem_side_port", this, false);
+ return memSidePort;
+ }
+ else panic("Port name %s unrecognized\n", if_name);
+}
+
+void
+BaseCache::regStats()
+{
+ Request temp_req((Addr) NULL, 4, 0);
+ Packet::Command temp_cmd = Packet::ReadReq;
+ Packet temp_pkt(&temp_req, temp_cmd, 0); //@todo FIx command strings so this isn't neccessary
+ temp_pkt.allocate(); //Temp allocate, all need data
+
+ using namespace Stats;
+
+ // Hit statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ hits[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_hits")
+ .desc("number of " + cstr + " hits")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandHits
+ .name(name() + ".demand_hits")
+ .desc("number of demand (read+write) hits")
+ .flags(total)
+ ;
+ demandHits = hits[Packet::ReadReq] + hits[Packet::WriteReq];
+
+ overallHits
+ .name(name() + ".overall_hits")
+ .desc("number of overall hits")
+ .flags(total)
+ ;
+ overallHits = demandHits + hits[Packet::SoftPFReq] + hits[Packet::HardPFReq]
+ + hits[Packet::Writeback];
+
+ // Miss statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ misses[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_misses")
+ .desc("number of " + cstr + " misses")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMisses
+ .name(name() + ".demand_misses")
+ .desc("number of demand (read+write) misses")
+ .flags(total)
+ ;
+ demandMisses = misses[Packet::ReadReq] + misses[Packet::WriteReq];
+
+ overallMisses
+ .name(name() + ".overall_misses")
+ .desc("number of overall misses")
+ .flags(total)
+ ;
+ overallMisses = demandMisses + misses[Packet::SoftPFReq] +
+ misses[Packet::HardPFReq] + misses[Packet::Writeback];
+
+ // Miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ missLatency[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_miss_latency")
+ .desc("number of " + cstr + " miss cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMissLatency
+ .name(name() + ".demand_miss_latency")
+ .desc("number of demand (read+write) miss cycles")
+ .flags(total)
+ ;
+ demandMissLatency = missLatency[Packet::ReadReq] + missLatency[Packet::WriteReq];
+
+ overallMissLatency
+ .name(name() + ".overall_miss_latency")
+ .desc("number of overall miss cycles")
+ .flags(total)
+ ;
+ overallMissLatency = demandMissLatency + missLatency[Packet::SoftPFReq] +
+ missLatency[Packet::HardPFReq];
+
+ // access formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ accesses[access_idx]
+ .name(name() + "." + cstr + "_accesses")
+ .desc("number of " + cstr + " accesses(hits+misses)")
+ .flags(total | nozero | nonan)
+ ;
+
+ accesses[access_idx] = hits[access_idx] + misses[access_idx];
+ }
+
+ demandAccesses
+ .name(name() + ".demand_accesses")
+ .desc("number of demand (read+write) accesses")
+ .flags(total)
+ ;
+ demandAccesses = demandHits + demandMisses;
+
+ overallAccesses
+ .name(name() + ".overall_accesses")
+ .desc("number of overall (read+write) accesses")
+ .flags(total)
+ ;
+ overallAccesses = overallHits + overallMisses;
+
+ // miss rate formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ missRate[access_idx]
+ .name(name() + "." + cstr + "_miss_rate")
+ .desc("miss rate for " + cstr + " accesses")
+ .flags(total | nozero | nonan)
+ ;
+
+ missRate[access_idx] = misses[access_idx] / accesses[access_idx];
+ }
+
+ demandMissRate
+ .name(name() + ".demand_miss_rate")
+ .desc("miss rate for demand accesses")
+ .flags(total)
+ ;
+ demandMissRate = demandMisses / demandAccesses;
+
+ overallMissRate
+ .name(name() + ".overall_miss_rate")
+ .desc("miss rate for overall accesses")
+ .flags(total)
+ ;
+ overallMissRate = overallMisses / overallAccesses;
+
+ // miss latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMissLatency[access_idx]
+ .name(name() + "." + cstr + "_avg_miss_latency")
+ .desc("average " + cstr + " miss latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMissLatency[access_idx] =
+ missLatency[access_idx] / misses[access_idx];
+ }
+
+ demandAvgMissLatency
+ .name(name() + ".demand_avg_miss_latency")
+ .desc("average overall miss latency")
+ .flags(total)
+ ;
+ demandAvgMissLatency = demandMissLatency / demandMisses;
+
+ overallAvgMissLatency
+ .name(name() + ".overall_avg_miss_latency")
+ .desc("average overall miss latency")
+ .flags(total)
+ ;
+ overallAvgMissLatency = overallMissLatency / overallMisses;
+
+ blocked_cycles.init(NUM_BLOCKED_CAUSES);
+ blocked_cycles
+ .name(name() + ".blocked_cycles")
+ .desc("number of cycles access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+
+ blocked_causes.init(NUM_BLOCKED_CAUSES);
+ blocked_causes
+ .name(name() + ".blocked")
+ .desc("number of cycles access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+ avg_blocked
+ .name(name() + ".avg_blocked_cycles")
+ .desc("average number of cycles each access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+ avg_blocked = blocked_cycles / blocked_causes;
+
+ fastWrites
+ .name(name() + ".fast_writes")
+ .desc("number of fast writes performed")
+ ;
+
+ cacheCopies
+ .name(name() + ".cache_copies")
+ .desc("number of cache copies performed")
+ ;
+
+}
diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh
new file mode 100644
index 000000000..2754fab5a
--- /dev/null
+++ b/src/mem/cache/base_cache.hh
@@ -0,0 +1,505 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declares a basic cache interface BaseCache.
+ */
+
+#ifndef __BASE_CACHE_HH__
+#define __BASE_CACHE_HH__
+
+#include <vector>
+#include <string>
+#include <list>
+#include <inttypes.h>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/trace.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+/**
+ * Reasons for Caches to be Blocked.
+ */
+enum BlockedCause{
+ Blocked_NoMSHRs,
+ Blocked_NoTargets,
+ Blocked_NoWBBuffers,
+ Blocked_Coherence,
+ Blocked_Copy,
+ NUM_BLOCKED_CAUSES
+};
+
+/**
+ * Reasons for cache to request a bus.
+ */
+enum RequestCause{
+ Request_MSHR,
+ Request_WB,
+ Request_Coherence,
+ Request_PF
+};
+
+/**
+ * A basic cache interface. Implements some common functions for speed.
+ */
+class BaseCache : public MemObject
+{
+ class CachePort : public Port
+ {
+ BaseCache *cache;
+
+ public:
+ CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
+
+ protected:
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop);
+
+ virtual int deviceBlockSize();
+
+ public:
+ void setBlocked();
+
+ void clearBlocked();
+
+ bool blocked;
+
+ bool isCpuSide;
+ };
+
+ struct CacheEvent : public Event
+ {
+ Packet *pkt;
+ CachePort *cachePort;
+
+ CacheEvent(Packet *pkt, CachePort *cachePort);
+ void process();
+ const char *description();
+ };
+
+ protected:
+ CachePort *cpuSidePort;
+ CachePort *memSidePort;
+
+ public:
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ private:
+ //To be defined in cache_impl.hh not in base class
+ virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ virtual void recvStatusChange(Port::Status status, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ /**
+ * Bit vector of the blocking reasons for the access path.
+ * @sa #BlockedCause
+ */
+ uint8_t blocked;
+
+ /**
+ * Bit vector for the blocking reasons for the snoop path.
+ * @sa #BlockedCause
+ */
+ uint8_t blockedSnoop;
+
+ /**
+ * Bit vector for the outstanding requests for the master interface.
+ */
+ uint8_t masterRequests;
+
+ /**
+ * Bit vector for the outstanding requests for the slave interface.
+ */
+ uint8_t slaveRequests;
+
+ protected:
+
+ /** True if this cache is connected to the CPU. */
+ bool topLevelCache;
+
+ /** Stores time the cache blocked for statistics. */
+ Tick blockedCycle;
+
+ /** Block size of this cache */
+ const int blkSize;
+
+ /** The number of misses to trigger an exit event. */
+ Counter missCount;
+
+ public:
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+
+ /** Number of hits per thread for each type of command. @sa Packet::Command */
+ Stats::Vector<> hits[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[NUM_MEM_CMDS];
+ /** Number of misses for demand accesses. */
+ Stats::Formula demandMisses;
+ /** Number of misses for all accesses. */
+ Stats::Formula overallMisses;
+
+ /**
+ * Total number of cycles per thread/command spent waiting for a miss.
+ * Used to calculate the average miss latency.
+ */
+ Stats::Vector<> missLatency[NUM_MEM_CMDS];
+ /** Total number of cycles spent waiting for demand misses. */
+ Stats::Formula demandMissLatency;
+ /** Total number of cycles spent waiting for all misses. */
+ Stats::Formula overallMissLatency;
+
+ /** The number of accesses per command and thread. */
+ Stats::Formula accesses[NUM_MEM_CMDS];
+ /** The number of demand accesses. */
+ Stats::Formula demandAccesses;
+ /** The number of overall accesses. */
+ Stats::Formula overallAccesses;
+
+ /** The miss rate per command and thread. */
+ Stats::Formula missRate[NUM_MEM_CMDS];
+ /** The miss rate of all demand accesses. */
+ Stats::Formula demandMissRate;
+ /** The miss rate for all accesses. */
+ Stats::Formula overallMissRate;
+
+ /** The average miss latency per command and thread. */
+ Stats::Formula avgMissLatency[NUM_MEM_CMDS];
+ /** The average miss latency for demand misses. */
+ Stats::Formula demandAvgMissLatency;
+ /** The average miss latency for all misses. */
+ Stats::Formula overallAvgMissLatency;
+
+ /** The total number of cycles blocked for each blocked cause. */
+ Stats::Vector<> blocked_cycles;
+ /** The number of times this cache blocked for each blocked cause. */
+ 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;
+
+ /** The number of cache copies performed. */
+ Stats::Scalar<> cacheCopies;
+
+ /**
+ * @}
+ */
+
+ /**
+ * Register stats for this object.
+ */
+ virtual void regStats();
+
+ public:
+
+ class Params
+ {
+ public:
+ /** List of address ranges of this cache. */
+ std::vector<Range<Addr> > addrRange;
+ /** The hit latency for this cache. */
+ int hitLatency;
+ /** The block size of this cache. */
+ int blkSize;
+ /**
+ * The maximum number of misses this cache should handle before
+ * ending the simulation.
+ */
+ Counter maxMisses;
+
+ /**
+ * Construct an instance of this parameter class.
+ */
+ Params(std::vector<Range<Addr> > addr_range,
+ int hit_latency, int _blkSize, Counter max_misses)
+ : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
+ maxMisses(max_misses)
+ {
+ }
+ };
+
+ /**
+ * Create and initialize a basic cache object.
+ * @param name The name of this cache.
+ * @param hier_params Pointer to the HierParams object for this hierarchy
+ * of this cache.
+ * @param params The parameter object for this BaseCache.
+ */
+ BaseCache(const std::string &name, Params &params)
+ : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
+ slaveRequests(0), topLevelCache(false), blkSize(params.blkSize),
+ missCount(params.maxMisses)
+ {
+ //Start ports at null if more than one is created we should panic
+ cpuSidePort = NULL;
+ memSidePort = NULL;
+ }
+
+ /**
+ * Query block size of a cache.
+ * @return The block size
+ */
+ int getBlockSize() const
+ {
+ return blkSize;
+ }
+
+ /**
+ * Returns true if this cache is connect to the CPU.
+ * @return True if this is a L1 cache.
+ */
+ bool isTopLevel()
+ {
+ return topLevelCache;
+ }
+
+ /**
+ * Returns true if the cache is blocked for accesses.
+ */
+ bool isBlocked()
+ {
+ return blocked != 0;
+ }
+
+ /**
+ * Returns true if the cache is blocked for snoops.
+ */
+ bool isBlockedForSnoop()
+ {
+ return blockedSnoop != 0;
+ }
+
+ /**
+ * Marks the access path of the cache as blocked for the given cause. This
+ * also sets the blocked flag in the slave interface.
+ * @param cause The reason for the cache blocking.
+ */
+ void setBlocked(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ if (blocked == 0) {
+ blocked_causes[cause]++;
+ blockedCycle = curTick;
+ }
+ blocked |= flag;
+ DPRINTF(Cache,"Blocking for cause %s\n", cause);
+ cpuSidePort->setBlocked();
+ }
+
+ /**
+ * Marks the snoop path of the cache as blocked for the given cause. This
+ * also sets the blocked flag in the master interface.
+ * @param cause The reason to block the snoop path.
+ */
+ void setBlockedForSnoop(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ blockedSnoop |= flag;
+ memSidePort->setBlocked();
+ }
+
+ /**
+ * Marks the cache as unblocked for the given cause. This also clears the
+ * blocked flags in the appropriate interfaces.
+ * @param cause The newly unblocked cause.
+ * @warning Calling this function can cause a blocked request on the bus to
+ * access the cache. The cache must be in a state to handle that request.
+ */
+ void clearBlocked(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ blocked &= ~flag;
+ blockedSnoop &= ~flag;
+ DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
+ cause, blocked);
+ if (!isBlocked()) {
+ blocked_cycles[cause] += curTick - blockedCycle;
+ DPRINTF(Cache,"Unblocking from all causes\n");
+ cpuSidePort->clearBlocked();
+ }
+ if (!isBlockedForSnoop()) {
+ memSidePort->clearBlocked();
+ }
+
+ }
+
+ /**
+ * True if the master bus should be requested.
+ * @return True if there are outstanding requests for the master bus.
+ */
+ bool doMasterRequest()
+ {
+ return masterRequests != 0;
+ }
+
+ /**
+ * Request the master bus for the given cause and time.
+ * @param cause The reason for the request.
+ * @param time The time to make the request.
+ */
+ void setMasterRequest(RequestCause cause, Tick time)
+ {
+ uint8_t flag = 1<<cause;
+ masterRequests |= flag;
+ assert("Implement\n" && 0);
+// mi->pktuest(time);
+ }
+
+ /**
+ * Clear the master bus request for the given cause.
+ * @param cause The request reason to clear.
+ */
+ void clearMasterRequest(RequestCause cause)
+ {
+ uint8_t flag = 1<<cause;
+ masterRequests &= ~flag;
+ }
+
+ /**
+ * Return true if the slave bus should be requested.
+ * @return True if there are outstanding requests for the slave bus.
+ */
+ bool doSlaveRequest()
+ {
+ return slaveRequests != 0;
+ }
+
+ /**
+ * Request the slave bus for the given reason and time.
+ * @param cause The reason for the request.
+ * @param time The time to make the request.
+ */
+ void setSlaveRequest(RequestCause cause, Tick time)
+ {
+ uint8_t flag = 1<<cause;
+ slaveRequests |= flag;
+ assert("Implement\n" && 0);
+// si->pktuest(time);
+ }
+
+ /**
+ * Clear the slave bus request for the given reason.
+ * @param cause The request reason to clear.
+ */
+ void clearSlaveRequest(RequestCause cause)
+ {
+ uint8_t flag = 1<<cause;
+ slaveRequests &= ~flag;
+ }
+
+ /**
+ * Send a response to the slave interface.
+ * @param req The request being responded to.
+ * @param time The time the response is ready.
+ */
+ void respond(Packet *pkt, Tick time)
+ {
+ assert("Implement\n" && 0);
+// si->respond(pkt,time);
+ }
+
+ /**
+ * Send a reponse to the slave interface and calculate miss latency.
+ * @param req The request to respond to.
+ * @param time The time the response is ready.
+ */
+ void respondToMiss(Packet *pkt, Tick time)
+ {
+ if (!pkt->req->isUncacheable()) {
+ missLatency[pkt->cmdToIndex()][pkt->req->getThreadNum()] += time - pkt->time;
+ }
+ assert("Implement\n" && 0);
+// si->respond(pkt,time);
+ }
+
+ /**
+ * Suppliess the data if cache to cache transfers are enabled.
+ * @param req The bus transaction to fulfill.
+ */
+ void respondToSnoop(Packet *pkt)
+ {
+ assert("Implement\n" && 0);
+// mi->respond(pkt,curTick + hitLatency);
+ }
+
+ /**
+ * Notification from master interface that a address range changed. Nothing
+ * to do for a cache.
+ */
+ void rangeChange() {}
+
+ void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+ {
+ panic("Unimplimented\n");
+ }
+};
+
+#endif //__BASE_CACHE_HH__
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
new file mode 100644
index 000000000..db66c096e
--- /dev/null
+++ b/src/mem/cache/cache.cc
@@ -0,0 +1,146 @@
+/*
+ * 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: Erik Hallnor
+ * Steve Reinhardt
+ * Lisa Hsu
+ * Kevin Lim
+ */
+
+/**
+ * @file
+ * Cache template instantiations.
+ */
+
+#include "mem/config/cache.hh"
+#include "mem/config/compression.hh"
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#if defined(USE_CACHE_LRU)
+#include "mem/cache/tags/lru.hh"
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#include "mem/cache/tags/fa_lru.hh"
+#endif
+
+#if defined(USE_CACHE_IIC)
+#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 "base/compression/null_compression.hh"
+#if defined(USE_LZSS_COMPRESSION)
+#include "base/compression/lzss_compression.hh"
+#endif
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/coherence/simple_coherence.hh"
+
+#include "mem/cache/cache_impl.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+
+#if defined(USE_CACHE_FALRU)
+template class Cache<CacheTags<FALRU,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<FALRU,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_IIC)
+template class Cache<CacheTags<IIC,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<IIC,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_LRU)
+template class Cache<CacheTags<LRU,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<LRU,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+template class Cache<CacheTags<Split,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<Split,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+template class Cache<CacheTags<SplitLIFO,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
new file mode 100644
index 000000000..1243c9d9e
--- /dev/null
+++ b/src/mem/cache/cache.hh
@@ -0,0 +1,279 @@
+/*
+ * 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: Erik Hallnor
+ * Dave Greene
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Describes a cache based on template policies.
+ */
+
+#ifndef __CACHE_HH__
+#define __CACHE_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+#include "cpu/smt.hh" // SMT_MAX_THREADS
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/prefetch/prefetcher.hh"
+
+//Forward decleration
+class MSHR;
+
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering, class Coherence>
+class Cache : public BaseCache
+{
+ public:
+ /** Define the type of cache block to use. */
+ typedef typename TagStore::BlkType BlkType;
+
+ bool prefetchAccess;
+ protected:
+
+ /** Tag and data Storage */
+ TagStore *tags;
+ /** Miss and Writeback handler */
+ Buffering *missQueue;
+ /** Coherence protocol. */
+ Coherence *coherence;
+
+ /** Prefetcher */
+ Prefetcher<TagStore, Buffering> *prefetcher;
+
+ /** Do fast copies in this cache. */
+ bool doCopy;
+
+ /** Block on a delayed copy. */
+ bool blockOnCopy;
+
+ /**
+ * The clock ratio of the outgoing bus.
+ * Used for calculating critical word first.
+ */
+ int busRatio;
+
+ /**
+ * The bus width in bytes of the outgoing bus.
+ * Used for calculating critical word first.
+ */
+ int busWidth;
+
+ /**
+ * The latency of a hit in this device.
+ */
+ int hitLatency;
+
+ /**
+ * A permanent mem req to always be used to cause invalidations.
+ * Used to append to target list, to cause an invalidation.
+ */
+ Packet * invalidatePkt;
+
+ /**
+ * Temporarily move a block into a MSHR.
+ * @todo Remove this when LSQ/SB are fixed and implemented in memtest.
+ */
+ void pseudoFill(Addr addr, int asid);
+
+ /**
+ * Temporarily move a block into an existing MSHR.
+ * @todo Remove this when LSQ/SB are fixed and implemented in memtest.
+ */
+ void pseudoFill(MSHR *mshr);
+
+ public:
+
+ class Params
+ {
+ public:
+ TagStore *tags;
+ Buffering *missQueue;
+ Coherence *coherence;
+ bool doCopy;
+ bool blockOnCopy;
+ BaseCache::Params baseParams;
+ Prefetcher<TagStore, Buffering> *prefetcher;
+ bool prefetchAccess;
+ int hitLatency;
+
+ Params(TagStore *_tags, Buffering *mq, Coherence *coh,
+ bool do_copy, BaseCache::Params params,
+ Prefetcher<TagStore, Buffering> *_prefetcher,
+ bool prefetch_access, int hit_latency)
+ : tags(_tags), missQueue(mq), coherence(coh), doCopy(do_copy),
+ blockOnCopy(false), baseParams(params),
+ prefetcher(_prefetcher), prefetchAccess(prefetch_access),
+ hitLatency(hit_latency)
+ {
+ }
+ };
+
+ /** Instantiates a basic cache object. */
+ Cache(const std::string &_name, Params &params);
+
+ virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort,
+ bool isCpuSide);
+
+ virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide);
+
+ virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide);
+
+ virtual void recvStatusChange(Port::Status status, bool isCpuSide);
+
+ void regStats();
+
+ /**
+ * Performs the access specified by the request.
+ * @param req The request to perform.
+ * @return The result of the access.
+ */
+ bool access(Packet * &pkt);
+
+ /**
+ * Selects a request to send on the bus.
+ * @return The memory request to service.
+ */
+ Packet * getPacket();
+
+ /**
+ * Was the request was sent successfully?
+ * @param req The request.
+ * @param success True if the request was sent successfully.
+ */
+ void sendResult(Packet * &pkt, bool success);
+
+ /**
+ * Handles a response (cache line fill/write ack) from the bus.
+ * @param req The request being responded to.
+ */
+ void handleResponse(Packet * &pkt);
+
+ /**
+ * Start handling a copy transaction.
+ * @param req The copy request to perform.
+ */
+ void startCopy(Packet * &pkt);
+
+ /**
+ * Handle a delayed copy transaction.
+ * @param req The delayed copy request to continue.
+ * @param addr The address being responded to.
+ * @param blk The block of the current response.
+ * @param mshr The mshr being handled.
+ */
+ void handleCopy(Packet * &pkt, Addr addr, BlkType *blk, MSHR *mshr);
+
+ /**
+ * Selects a coherence message to forward to lower levels of the hierarchy.
+ * @return The coherence message to forward.
+ */
+ Packet * getCoherenceReq();
+
+ /**
+ * Snoops bus transactions to maintain coherence.
+ * @param req The current bus transaction.
+ */
+ void snoop(Packet * &pkt);
+
+ void snoopResponse(Packet * &pkt);
+
+ /**
+ * Invalidates the block containing address if found.
+ * @param addr The address to look for.
+ * @param asid The address space ID of the address.
+ * @todo Is this function necessary?
+ */
+ void invalidateBlk(Addr addr, int asid);
+
+ /**
+ * Aquash all requests associated with specified thread.
+ * intended for use by I-cache.
+ * @param req->getThreadNum()ber The thread to squash.
+ */
+ void squash(int threadNum)
+ {
+ missQueue->squash(threadNum);
+ }
+
+ /**
+ * Return the number of outstanding misses in a Cache.
+ * Default returns 0.
+ *
+ * @retval unsigned The number of missing still outstanding.
+ */
+ unsigned outstandingMisses() const
+ {
+ return missQueue->getMisses();
+ }
+
+ /**
+ * Send a response to the slave interface.
+ * @param req The request being responded to.
+ * @param time The time the response is ready.
+ */
+ void respond(Packet * &pkt, Tick time)
+ {
+ //si->respond(pkt,time);
+ cpuSidePort->sendAtomic(pkt);
+ }
+
+ /**
+ * Perform the access specified in the request and return the estimated
+ * time of completion. This function can either update the hierarchy state
+ * or just perform the access wherever the data is found depending on the
+ * state of the update flag.
+ * @param req The memory request to satisfy
+ * @param update If true, update the hierarchy, otherwise just perform the
+ * request.
+ * @return The estimated completion time.
+ */
+ Tick probe(Packet * &pkt, bool update);
+
+ /**
+ * Snoop for the provided request in the cache and return the estimated
+ * time of completion.
+ * @todo Can a snoop probe not change state?
+ * @param req The memory request to satisfy
+ * @param update If true, update the hierarchy, otherwise just perform the
+ * request.
+ * @return The estimated completion time.
+ */
+ Tick snoopProbe(Packet * &pkt, bool update);
+};
+
+#endif // __CACHE_HH__
diff --git a/src/mem/cache/cache_blk.hh b/src/mem/cache/cache_blk.hh
new file mode 100644
index 000000000..67e65d25b
--- /dev/null
+++ b/src/mem/cache/cache_blk.hh
@@ -0,0 +1,198 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/** @file
+ * Definitions of a simple cache block class.
+ */
+
+#ifndef __CACHE_BLK_HH__
+#define __CACHE_BLK_HH__
+
+#include "sim/root.hh" // for Tick
+#include "arch/isa_traits.hh" // for Addr
+
+/**
+ * Cache block status bit assignments
+ */
+enum CacheBlkStatusBits {
+ /** valid, readable */
+ BlkValid = 0x01,
+ /** write permission */
+ BlkWritable = 0x02,
+ /** dirty (modified) */
+ BlkDirty = 0x04,
+ /** compressed */
+ BlkCompressed = 0x08,
+ /** block was referenced */
+ BlkReferenced = 0x10,
+ /** block was a hardware prefetch yet unaccessed*/
+ BlkHWPrefetched = 0x20
+};
+
+/**
+ * A Basic Cache block.
+ * Contains the tag, status, and a pointer to data.
+ */
+class CacheBlk
+{
+ public:
+ /** The address space ID of this block. */
+ int asid;
+ /** Data block tag value. */
+ Addr tag;
+ /**
+ * Contains a copy of the data in this block for easy access. This is used
+ * for efficient execution when the data could be actually stored in
+ * another format (COW, compressed, sub-blocked, etc). In all cases the
+ * data stored here should be kept consistant with the actual data
+ * referenced by this block.
+ */
+ uint8_t *data;
+ /** the number of bytes stored in this block. */
+ int size;
+
+ /** block state: OR of CacheBlkStatusBit */
+ typedef unsigned State;
+
+ /** The current status of this block. @sa CacheBlockStatusBits */
+ State status;
+
+ /** Which curTick will this block be accessable */
+ Tick whenReady;
+
+ /**
+ * The set this block belongs to.
+ * @todo Move this into subclasses when we fix CacheTags to use them.
+ */
+ int set;
+
+ /** Number of references to this block since it was brought in. */
+ int refCount;
+
+ CacheBlk()
+ : asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
+ set(-1), refCount(0)
+ {}
+
+ /**
+ * Copy the state of the given block into this one.
+ * @param rhs The block to copy.
+ * @return a const reference to this block.
+ */
+ const CacheBlk& operator=(const CacheBlk& rhs)
+ {
+ asid = rhs.asid;
+ tag = rhs.tag;
+ data = rhs.data;
+ size = rhs.size;
+ status = rhs.status;
+ whenReady = rhs.whenReady;
+ set = rhs.set;
+ refCount = rhs.refCount;
+ return *this;
+ }
+
+ /**
+ * Checks the write permissions of this block.
+ * @return True if the block is writable.
+ */
+ bool isWritable() const
+ {
+ const int needed_bits = BlkWritable | BlkValid;
+ return (status & needed_bits) == needed_bits;
+ }
+
+ /**
+ * Checks that a block is valid (readable).
+ * @return True if the block is valid.
+ */
+ bool isValid() const
+ {
+ return (status & BlkValid) != 0;
+ }
+
+ /**
+ * Check to see if a block has been written.
+ * @return True if the block is dirty.
+ */
+ bool isModified() const
+ {
+ return (status & BlkDirty) != 0;
+ }
+
+ /**
+ * Check to see if this block contains compressed data.
+ * @return True iF the block's data is compressed.
+ */
+ bool isCompressed() const
+ {
+ return (status & BlkCompressed) != 0;
+ }
+
+ /**
+ * Check if this block has been referenced.
+ * @return True if the block has been referenced.
+ */
+ bool isReferenced() const
+ {
+ return (status & BlkReferenced) != 0;
+ }
+
+ /**
+ * Check if this block was the result of a hardware prefetch, yet to
+ * be touched.
+ * @return True if the block was a hardware prefetch, unaccesed.
+ */
+ bool isPrefetch() const
+ {
+ return (status & BlkHWPrefetched) != 0;
+ }
+
+
+};
+
+/**
+ * Output a CacheBlk to the given ostream.
+ * @param out The stream for the output.
+ * @param blk The cache block to print.
+ *
+ * @return The output stream.
+ */
+inline std::ostream &
+operator<<(std::ostream &out, const CacheBlk &blk)
+{
+ out << std::hex << std::endl;
+ out << " Tag: " << blk.tag << std::endl;
+ out << " Status: " << blk.status << std::endl;
+
+ return(out << std::dec);
+}
+
+#endif //__CACHE_BLK_HH__
diff --git a/src/mem/cache/cache_builder.cc b/src/mem/cache/cache_builder.cc
new file mode 100644
index 000000000..05a149a1c
--- /dev/null
+++ b/src/mem/cache/cache_builder.cc
@@ -0,0 +1,480 @@
+/*
+ * 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: Erik Hallnor
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Simobject instatiation of caches.
+ */
+#include <vector>
+
+// Must be included first to determine which caches we want
+#include "mem/config/cache.hh"
+#include "mem/config/compression.hh"
+#include "mem/config/prefetch.hh"
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/cache.hh"
+#include "mem/bus.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+#include "sim/builder.hh"
+
+// Tag Templates
+#if defined(USE_CACHE_LRU)
+#include "mem/cache/tags/lru.hh"
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#include "mem/cache/tags/fa_lru.hh"
+#endif
+
+#if defined(USE_CACHE_IIC)
+#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
+
+// Compression Templates
+#include "base/compression/null_compression.hh"
+#if defined(USE_LZSS_COMPRESSION)
+#include "base/compression/lzss_compression.hh"
+#endif
+
+// CacheTags Templates
+#include "mem/cache/tags/cache_tags.hh"
+
+// MissQueue Templates
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+// Coherence Templates
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/coherence/simple_coherence.hh"
+
+//Prefetcher Headers
+#if defined(USE_GHB)
+#include "mem/cache/prefetch/ghb_prefetcher.hh"
+#endif
+#if defined(USE_TAGGED)
+#include "mem/cache/prefetch/tagged_prefetcher.hh"
+#endif
+#if defined(USE_STRIDED)
+#include "mem/cache/prefetch/stride_prefetcher.hh"
+#endif
+
+
+using namespace std;
+using namespace TheISA;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(BaseCache)
+
+ Param<int> size;
+ Param<int> assoc;
+ Param<int> block_size;
+ Param<int> latency;
+ Param<int> mshrs;
+ Param<int> tgts_per_mshr;
+ Param<int> write_buffers;
+ Param<bool> prioritizeRequests;
+// SimObjectParam<Bus *> in_bus;
+// SimObjectParam<Bus *> out_bus;
+ Param<bool> do_copy;
+ SimObjectParam<CoherenceProtocol *> protocol;
+ Param<Addr> trace_addr;
+ Param<int> hash_delay;
+#if defined(USE_CACHE_IIC)
+ SimObjectParam<Repl *> repl;
+#endif
+ Param<bool> compressed_bus;
+ Param<bool> store_compressed;
+ Param<bool> adaptive_compression;
+ Param<int> compression_latency;
+ Param<int> subblock_size;
+ Param<Counter> max_miss_count;
+// SimObjectParam<HierParams *> hier;
+ VectorParam<Range<Addr> > addr_range;
+// SimObjectParam<MemTraceWriter *> mem_trace;
+ Param<bool> split;
+ Param<int> split_size;
+ Param<bool> lifo;
+ Param<bool> two_queue;
+ Param<bool> prefetch_miss;
+ Param<bool> prefetch_access;
+ Param<int> prefetcher_size;
+ Param<bool> prefetch_past_page;
+ Param<bool> prefetch_serial_squash;
+ Param<Tick> prefetch_latency;
+ Param<int> prefetch_degree;
+ Param<string> prefetch_policy;
+ Param<bool> prefetch_cache_check_push;
+ Param<bool> prefetch_use_cpu_id;
+ Param<bool> prefetch_data_accesses_only;
+ Param<int> hit_latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(BaseCache)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(BaseCache)
+
+ INIT_PARAM(size, "capacity in bytes"),
+ INIT_PARAM(assoc, "associativity"),
+ INIT_PARAM(block_size, "block size in bytes"),
+ INIT_PARAM(latency, "hit latency in CPU cycles"),
+ INIT_PARAM(mshrs, "number of MSHRs (max outstanding requests)"),
+ INIT_PARAM(tgts_per_mshr, "max number of accesses per MSHR"),
+ INIT_PARAM_DFLT(write_buffers, "number of write buffers", 8),
+ INIT_PARAM_DFLT(prioritizeRequests, "always service demand misses first",
+ false),
+/* INIT_PARAM_DFLT(in_bus, "incoming bus object", NULL),
+ INIT_PARAM(out_bus, "outgoing bus object"),
+*/
+ INIT_PARAM_DFLT(do_copy, "perform fast copies in the cache", false),
+ INIT_PARAM_DFLT(protocol, "coherence protocol to use in the cache", NULL),
+ INIT_PARAM_DFLT(trace_addr, "address to trace", 0),
+
+ INIT_PARAM_DFLT(hash_delay, "time in cycles of hash access",1),
+#if defined(USE_CACHE_IIC)
+ INIT_PARAM_DFLT(repl, "replacement policy",NULL),
+#endif
+ INIT_PARAM_DFLT(compressed_bus,
+ "This cache connects to a compressed memory",
+ false),
+ INIT_PARAM_DFLT(store_compressed, "Store compressed data in the cache",
+ false),
+ INIT_PARAM_DFLT(adaptive_compression, "Use an adaptive compression scheme",
+ false),
+ INIT_PARAM_DFLT(compression_latency,
+ "Latency in cycles of compression algorithm",
+ 0),
+ INIT_PARAM_DFLT(subblock_size,
+ "Size of subblock in IIC used for compression",
+ 0),
+ INIT_PARAM_DFLT(max_miss_count,
+ "The number of misses to handle before calling exit",
+ 0),
+/* INIT_PARAM_DFLT(hier,
+ "Hierarchy global variables",
+ &defaultHierParams),
+*/
+ INIT_PARAM_DFLT(addr_range, "The address range in bytes",
+ vector<Range<Addr> >(1,RangeIn((Addr)0, MaxAddr))),
+// INIT_PARAM_DFLT(mem_trace, "Memory trace to write accesses to", NULL),
+ INIT_PARAM_DFLT(split, "Whether this is a partitioned cache", false),
+ INIT_PARAM_DFLT(split_size, "the number of \"ways\" belonging to the LRU partition", 0),
+ INIT_PARAM_DFLT(lifo, "whether you are using a LIFO repl. policy", false),
+ INIT_PARAM_DFLT(two_queue, "whether the lifo should have two queue replacement", false),
+ INIT_PARAM_DFLT(prefetch_miss, "wheter you are using the hardware prefetcher from Miss stream", false),
+ INIT_PARAM_DFLT(prefetch_access, "wheter you are using the hardware prefetcher from Access stream", false),
+ INIT_PARAM_DFLT(prefetcher_size, "Number of entries in the harware prefetch queue", 100),
+ INIT_PARAM_DFLT(prefetch_past_page, "Allow prefetches to cross virtual page boundaries", false),
+ INIT_PARAM_DFLT(prefetch_serial_squash, "Squash prefetches with a later time on a subsequent miss", false),
+ INIT_PARAM_DFLT(prefetch_latency, "Latency of the prefetcher", 10),
+ INIT_PARAM_DFLT(prefetch_degree, "Degree of the prefetch depth", 1),
+ INIT_PARAM_DFLT(prefetch_policy, "Type of prefetcher to use", "none"),
+ INIT_PARAM_DFLT(prefetch_cache_check_push, "Check if in cash on push or pop of prefetch queue", true),
+ INIT_PARAM_DFLT(prefetch_use_cpu_id, "Use the CPU ID to seperate calculations of prefetches", true),
+ INIT_PARAM_DFLT(prefetch_data_accesses_only, "Only prefetch on data not on instruction accesses", false),
+ INIT_PARAM_DFLT(hit_latency, "Hit Latecny for a succesful access", 1)
+END_INIT_SIM_OBJECT_PARAMS(BaseCache)
+
+
+#define BUILD_CACHE(t, comp, b, c) do { \
+ Prefetcher<CacheTags<t, comp>, b> *pf; \
+ if (pf_policy == "tagged") { \
+ BUILD_TAGGED_PREFETCHER(t, comp, b); \
+ } \
+ else if (pf_policy == "stride") { \
+ BUILD_STRIDED_PREFETCHER(t, comp, b); \
+ } \
+ else if (pf_policy == "ghb") { \
+ BUILD_GHB_PREFETCHER(t, comp, b); \
+ } \
+ else { \
+ BUILD_NULL_PREFETCHER(t, comp, b); \
+ } \
+ Cache<CacheTags<t, comp>, b, c>::Params params(tagStore, mq, coh, \
+ do_copy, base_params, \
+ /*in_bus, out_bus,*/ pf, \
+ prefetch_access, hit_latency); \
+ Cache<CacheTags<t, comp>, b, c> *retval = \
+ new Cache<CacheTags<t, comp>, b, c>(getInstanceName(), /*hier,*/ \
+ params); \
+/* if (in_bus == NULL) { \
+ retval->setSlaveInterface(new MemoryInterface<Cache<CacheTags<t, comp>, b, c> >(getInstanceName(), hier, retval, mem_trace)); \
+ } else { \
+ retval->setSlaveInterface(new SlaveInterface<Cache<CacheTags<t, comp>, b, c>, Bus>(getInstanceName(), hier, retval, in_bus, mem_trace)); \
+ } \
+ retval->setMasterInterface(new MasterInterface<Cache<CacheTags<t, comp>, b, c>, Bus>(getInstanceName(), hier, retval, out_bus)); \
+ out_bus->rangeChange(); \
+ return retval; \
+*/return retval; \
+ } while (0)
+
+#define BUILD_CACHE_PANIC(x) do { \
+ panic("%s not compiled into M5", x); \
+ } while (0)
+
+#if defined(USE_LZSS_COMPRESSION)
+#define BUILD_COMPRESSED_CACHE(TAGS, tags, b, c) do { \
+ if (compressed_bus || store_compressed){ \
+ CacheTags<TAGS, LZSSCompression> *tagStore = \
+ new CacheTags<TAGS, LZSSCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression, \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, LZSSCompression, b, c); \
+ } else { \
+ CacheTags<TAGS, NullCompression> *tagStore = \
+ new CacheTags<TAGS, NullCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression, \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, NullCompression, b, c); \
+ } \
+ } while (0)
+#else
+#define BUILD_COMPRESSED_CACHE(TAGS, tags, b, c) do { \
+ if (compressed_bus || store_compressed){ \
+ BUILD_CACHE_PANIC("compressed caches"); \
+ } else { \
+ CacheTags<TAGS, NullCompression> *tagStore = \
+ new CacheTags<TAGS, NullCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, NullCompression, b, c); \
+ } \
+ } while (0)
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#define BUILD_FALRU_CACHE(b,c) do { \
+ FALRU *tags = new FALRU(block_size, size, latency); \
+ BUILD_COMPRESSED_CACHE(FALRU, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_FALRU_CACHE(b, c) BUILD_CACHE_PANIC("falru cache")
+#endif
+
+#if defined(USE_CACHE_LRU)
+#define BUILD_LRU_CACHE(b, c) do { \
+ LRU *tags = new LRU(numSets, block_size, assoc, latency); \
+ BUILD_COMPRESSED_CACHE(LRU, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_LRU_CACHE(b, c) BUILD_CACHE_PANIC("lru cache")
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+#define BUILD_SPLIT_CACHE(b, c) do { \
+ Split *tags = new Split(numSets, block_size, assoc, split_size, lifo, \
+ two_queue, latency); \
+ BUILD_COMPRESSED_CACHE(Split, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_SPLIT_CACHE(b, c) BUILD_CACHE_PANIC("split cache")
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+#define BUILD_SPLIT_LIFO_CACHE(b, c) do { \
+ SplitLIFO *tags = new SplitLIFO(block_size, size, assoc, \
+ latency, two_queue, -1); \
+ BUILD_COMPRESSED_CACHE(SplitLIFO, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_SPLIT_LIFO_CACHE(b, c) BUILD_CACHE_PANIC("lifo cache")
+#endif
+
+#if defined(USE_CACHE_IIC)
+#define BUILD_IIC_CACHE(b ,c) do { \
+ IIC *tags = new IIC(iic_params); \
+ BUILD_COMPRESSED_CACHE(IIC, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_IIC_CACHE(b, c) BUILD_CACHE_PANIC("iic")
+#endif
+
+#define BUILD_CACHES(b, c) do { \
+ if (repl == NULL) { \
+ if (numSets == 1) { \
+ BUILD_FALRU_CACHE(b, c); \
+ } else { \
+ if (split == true) { \
+ BUILD_SPLIT_CACHE(b, c); \
+ } else if (lifo == true) { \
+ BUILD_SPLIT_LIFO_CACHE(b, c); \
+ } else { \
+ BUILD_LRU_CACHE(b, c); \
+ } \
+ } \
+ } else { \
+ BUILD_IIC_CACHE(b, c); \
+ } \
+ } while (0)
+
+#define BUILD_COHERENCE(b) do { \
+ if (protocol == NULL) { \
+ UniCoherence *coh = new UniCoherence(); \
+ BUILD_CACHES(b, UniCoherence); \
+ } else { \
+ SimpleCoherence *coh = new SimpleCoherence(protocol); \
+ BUILD_CACHES(b, SimpleCoherence); \
+ } \
+ } while (0)
+
+#if defined(USE_TAGGED)
+#define BUILD_TAGGED_PREFETCHER(t, comp, b) pf = new \
+ TaggedPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree)
+#else
+#define BUILD_TAGGED_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("Tagged Prefetcher")
+#endif
+
+#if defined(USE_STRIDED)
+#define BUILD_STRIDED_PREFETCHER(t, comp, b) pf = new \
+ StridePrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree, \
+ prefetch_use_cpu_id)
+#else
+#define BUILD_STRIDED_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("Stride Prefetcher")
+#endif
+
+#if defined(USE_GHB)
+#define BUILD_GHB_PREFETCHER(t, comp, b) pf = new \
+ GHBPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree, \
+ prefetch_use_cpu_id)
+#else
+#define BUILD_GHB_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("GHB Prefetcher")
+#endif
+
+#if defined(USE_TAGGED)
+#define BUILD_NULL_PREFETCHER(t, comp, b) pf = new \
+ TaggedPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree)
+#else
+#define BUILD_NULL_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("NULL Prefetcher (uses Tagged)")
+#endif
+
+CREATE_SIM_OBJECT(BaseCache)
+{
+ string name = getInstanceName();
+ int numSets = size / (assoc * block_size);
+ string pf_policy = prefetch_policy;
+ if (subblock_size == 0) {
+ subblock_size = block_size;
+ }
+
+ // Build BaseCache param object
+ BaseCache::Params base_params(addr_range, latency,
+ block_size, max_miss_count);
+
+ //Warnings about prefetcher policy
+ if (pf_policy == "none" && (prefetch_miss || prefetch_access)) {
+ panic("With no prefetcher, you shouldn't prefetch from"
+ " either miss or access stream\n");
+ }
+ if ((pf_policy == "tagged" || pf_policy == "stride" ||
+ pf_policy == "ghb") && !(prefetch_miss || prefetch_access)) {
+ warn("With this prefetcher you should chose a prefetch"
+ " stream (miss or access)\nNo Prefetching will occur\n");
+ }
+ if ((pf_policy == "tagged" || pf_policy == "stride" ||
+ pf_policy == "ghb") && prefetch_miss && prefetch_access) {
+ panic("Can't do prefetches from both miss and access"
+ " stream\n");
+ }
+ if (pf_policy != "tagged" && pf_policy != "stride" &&
+ pf_policy != "ghb" && pf_policy != "none") {
+ panic("Unrecognized form of a prefetcher: %s, try using"
+ "['none','stride','tagged','ghb']\n", pf_policy);
+ }
+
+#if defined(USE_CACHE_IIC)
+ // Build IIC params
+ IIC::Params iic_params;
+ iic_params.size = size;
+ iic_params.numSets = numSets;
+ iic_params.blkSize = block_size;
+ iic_params.assoc = assoc;
+ iic_params.hashDelay = hash_delay;
+ iic_params.hitLatency = latency;
+ iic_params.rp = repl;
+ iic_params.subblockSize = subblock_size;
+#else
+ const void *repl = NULL;
+#endif
+
+ if (mshrs == 1 /*|| out_bus->doEvents() == false*/) {
+ BlockingBuffer *mq = new BlockingBuffer(true);
+ BUILD_COHERENCE(BlockingBuffer);
+ } else {
+ MissQueue *mq = new MissQueue(mshrs, tgts_per_mshr, write_buffers,
+ true, prefetch_miss);
+ BUILD_COHERENCE(MissQueue);
+ }
+ return NULL;
+}
+
+REGISTER_SIM_OBJECT("BaseCache", BaseCache)
+
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
new file mode 100644
index 000000000..aae5cbf01
--- /dev/null
+++ b/src/mem/cache/cache_impl.hh
@@ -0,0 +1,660 @@
+/*
+ * 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: Erik Hallnor
+ * Dave Greene
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Cache definitions.
+ */
+
+#include <assert.h>
+#include <math.h>
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "cpu/smt.hh"
+
+#include "mem/cache/cache.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/prefetch/prefetcher.hh"
+
+#include "sim/sim_events.hh" // for SimExitEvent
+
+using namespace std;
+
+template<class TagStore, class Buffering, class Coherence>
+bool
+Cache<TagStore,Buffering,Coherence>::
+doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ access(pkt);
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoop(pkt);
+ }
+ return true; //Deal with blocking....
+}
+
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::
+doAtomicAccess(Packet *pkt, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ probe(pkt, true);
+ //TEMP ALWAYS SUCCES FOR NOW
+ pkt->result = Packet::Success;
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoopProbe(pkt, true);
+ }
+ //Fix this timing info
+ return hitLatency;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::
+doFunctionalAccess(Packet *pkt, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ //TEMP USE CPU?THREAD 0 0
+ pkt->req->setThreadContext(0,0);
+ probe(pkt, true);
+ //TEMP ALWAYS SUCCESFUL FOR NOW
+ pkt->result = Packet::Success;
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoopProbe(pkt, true);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::
+recvStatusChange(Port::Status status, bool isCpuSide)
+{
+
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Cache<TagStore,Buffering,Coherence>::
+Cache(const std::string &_name,
+ Cache<TagStore,Buffering,Coherence>::Params &params)
+ : BaseCache(_name, params.baseParams),
+ prefetchAccess(params.prefetchAccess),
+ tags(params.tags), missQueue(params.missQueue),
+ coherence(params.coherence), prefetcher(params.prefetcher),
+ doCopy(params.doCopy), blockOnCopy(params.blockOnCopy)
+{
+//FIX BUS POINTERS
+// if (params.in == NULL) {
+ topLevelCache = true;
+// }
+//PLEASE FIX THIS, BUS SIZES NOT BEING USED
+ tags->setCache(this, blkSize, 1/*params.out->width, params.out->clockRate*/);
+ tags->setPrefetcher(prefetcher);
+ missQueue->setCache(this);
+ missQueue->setPrefetcher(prefetcher);
+ coherence->setCache(this);
+ prefetcher->setCache(this);
+ prefetcher->setTags(tags);
+ prefetcher->setBuffer(missQueue);
+#if 0
+ invalidatePkt = new Packet;
+ invalidatePkt->cmd = Packet::InvalidateReq;
+#endif
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::regStats()
+{
+ BaseCache::regStats();
+ tags->regStats(name());
+ missQueue->regStats(name());
+ coherence->regStats(name());
+ prefetcher->regStats(name());
+}
+
+template<class TagStore, class Buffering, class Coherence>
+bool
+Cache<TagStore,Buffering,Coherence>::access(PacketPtr &pkt)
+{
+//@todo Add back in MemDebug Calls
+// MemDebug::cacheAccess(pkt);
+ BlkType *blk = NULL;
+ PacketList writebacks;
+ int size = blkSize;
+ int lat = hitLatency;
+ if (prefetchAccess) {
+ //We are determining prefetches on access stream, call prefetcher
+ prefetcher->handleMiss(pkt, curTick);
+ }
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->isInvalidate() && !pkt->isRead()
+ && !pkt->isWrite()) {
+ //Upgrade or Invalidate
+ //Look into what happens if two slave caches on bus
+ DPRINTF(Cache, "%s %d %x ? blk_addr: %x\n", pkt->cmdString(),
+ pkt->req->getAsid(), pkt->getAddr() & (((ULL(1))<<48)-1),
+ pkt->getAddr() & ~((Addr)blkSize - 1));
+
+ //@todo Should this return latency have the hit latency in it?
+// respond(pkt,curTick+lat);
+ pkt->flags |= SATISFIED;
+// return MA_HIT; //@todo, return values
+ return true;
+ }
+ blk = tags->handleAccess(pkt, lat, writebacks);
+ } else {
+ size = pkt->getSize();
+ }
+ // If this is a block size write/hint (WH64) allocate the block here
+ // if the coherence protocol allows it.
+ /** @todo make the fast write alloc (wh64) work with coherence. */
+ /** @todo Do we want to do fast writes for writebacks as well? */
+ if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
+ (pkt->cmd == Packet::WriteReq || pkt->cmd == Packet::WriteInvalidateReq) ) {
+ // not outstanding misses, can do this
+ MSHR* outstanding_miss = missQueue->findMSHR(pkt->getAddr(), pkt->req->getAsid());
+ if (pkt->cmd == Packet::WriteInvalidateReq || !outstanding_miss) {
+ if (outstanding_miss) {
+ warn("WriteInv doing a fastallocate"
+ "with an outstanding miss to the same address\n");
+ }
+ blk = tags->handleFill(NULL, pkt, BlkValid | BlkWritable,
+ writebacks);
+ ++fastWrites;
+ }
+ }
+ while (!writebacks.empty()) {
+ missQueue->doWriteback(writebacks.front());
+ writebacks.pop_front();
+ }
+ DPRINTF(Cache, "%s %d %x %s blk_addr: %x pc %x\n", pkt->cmdString(),
+ pkt->req->getAsid(), pkt->getAddr() & (((ULL(1))<<48)-1), (blk) ? "hit" : "miss",
+ pkt->getAddr() & ~((Addr)blkSize - 1), pkt->req->getPC());
+ if (blk) {
+ // Hit
+ hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ // clear dirty bit if write through
+ if (pkt->needsResponse())
+ respond(pkt, curTick+lat);
+// return MA_HIT;
+ return true;
+ }
+
+ // Miss
+ if (!pkt->req->isUncacheable()) {
+ misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ /** @todo Move miss count code into BaseCache */
+ if (missCount) {
+ --missCount;
+ if (missCount == 0)
+ new SimLoopExitEvent(curTick, "A cache reached the maximum miss count");
+ }
+ }
+ missQueue->handleMiss(pkt, size, curTick + hitLatency);
+// return MA_CACHE_MISS;
+ return true;
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Packet *
+Cache<TagStore,Buffering,Coherence>::getPacket()
+{
+ Packet * pkt = missQueue->getPacket();
+ if (pkt) {
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->cmd == Packet::HardPFReq) misses[Packet::HardPFReq][pkt->req->getThreadNum()]++;
+ BlkType *blk = tags->findBlock(pkt);
+ Packet::Command cmd = coherence->getBusCmd(pkt->cmd,
+ (blk)? blk->status : 0);
+ missQueue->setBusCmd(pkt, cmd);
+ }
+ }
+
+ assert(!doMasterRequest() || missQueue->havePending());
+ assert(!pkt || pkt->time <= curTick);
+ return pkt;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::sendResult(PacketPtr &pkt, bool success)
+{
+ if (success) {
+ missQueue->markInService(pkt);
+ //Temp Hack for UPGRADES
+ if (pkt->cmd == Packet::UpgradeReq) {
+ handleResponse(pkt);
+ }
+ } else if (pkt && !pkt->req->isUncacheable()) {
+ missQueue->restoreOrigCmd(pkt);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::handleResponse(Packet * &pkt)
+{
+ BlkType *blk = NULL;
+ if (pkt->senderState) {
+// MemDebug::cacheResponse(pkt);
+ DPRINTF(Cache, "Handling reponse to %x, blk addr: %x\n",pkt->getAddr(),
+ pkt->getAddr() & (((ULL(1))<<48)-1));
+
+ if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
+ blk = tags->findBlock(pkt);
+ CacheBlk::State old_state = (blk) ? blk->status : 0;
+ PacketList writebacks;
+ blk = tags->handleFill(blk, (MSHR*)pkt->senderState,
+ coherence->getNewState(pkt,old_state),
+ writebacks);
+ while (!writebacks.empty()) {
+ missQueue->doWriteback(writebacks.front());
+ }
+ }
+ missQueue->handleResponse(pkt, curTick + hitLatency);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::pseudoFill(Addr addr, int asid)
+{
+ // Need to temporarily move this blk into MSHRs
+ MSHR *mshr = missQueue->allocateTargetList(addr, asid);
+ int lat;
+ PacketList dummy;
+ // Read the data into the mshr
+ BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
+ assert(dummy.empty());
+ assert(mshr->pkt->flags & SATISFIED);
+ // can overload order since it isn't used on non pending blocks
+ mshr->order = blk->status;
+ // temporarily remove the block from the cache.
+ tags->invalidateBlk(addr, asid);
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
+{
+ // Need to temporarily move this blk into MSHRs
+ assert(mshr->pkt->cmd == Packet::ReadReq);
+ int lat;
+ PacketList dummy;
+ // Read the data into the mshr
+ BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
+ assert(dummy.empty());
+ assert(mshr->pkt->flags & SATISFIED);
+ // can overload order since it isn't used on non pending blocks
+ mshr->order = blk->status;
+ // temporarily remove the block from the cache.
+ tags->invalidateBlk(mshr->pkt->getAddr(), mshr->pkt->req->getAsid());
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Packet *
+Cache<TagStore,Buffering,Coherence>::getCoherenceReq()
+{
+ return coherence->getPacket();
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
+{
+
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ BlkType *blk = tags->findBlock(pkt);
+ MSHR *mshr = missQueue->findMSHR(blk_addr, pkt->req->getAsid());
+ if (isTopLevel() && coherence->hasProtocol()) { //@todo Move this into handle bus req
+ //If we find an mshr, and it is in service, we need to NACK or invalidate
+ if (mshr) {
+ if (mshr->inService) {
+ if ((mshr->pkt->isInvalidate() || !mshr->pkt->isCacheFill())
+ && (pkt->cmd != Packet::InvalidateReq && pkt->cmd != Packet::WriteInvalidateReq)) {
+ //If the outstanding request was an invalidate (upgrade,readex,..)
+ //Then we need to ACK the request until we get the data
+ //Also NACK if the outstanding request is not a cachefill (writeback)
+ pkt->flags |= NACKED_LINE;
+ return;
+ }
+ else {
+ //The supplier will be someone else, because we are waiting for
+ //the data. This should cause this cache to be forced to go to
+ //the shared state, not the exclusive even though the shared line
+ //won't be asserted. But for now we will just invlidate ourselves
+ //and allow the other cache to go into the exclusive state.
+ //@todo Make it so a read to a pending read doesn't invalidate.
+ //@todo Make it so that a read to a pending read can't be exclusive now.
+
+ //Set the address so find match works
+ invalidatePkt->addrOverride(pkt->getAddr());
+
+ //Append the invalidate on
+ missQueue->addTarget(mshr,invalidatePkt);
+ DPRINTF(Cache, "Appending Invalidate to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
+ return;
+ }
+ }
+ }
+ //We also need to check the writeback buffers and handle those
+ std::vector<MSHR *> writebacks;
+ if (missQueue->findWrites(blk_addr, pkt->req->getAsid(), writebacks)) {
+ DPRINTF(Cache, "Snoop hit in writeback to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
+
+ //Look through writebacks for any non-uncachable writes, use that
+ for (int i=0; i<writebacks.size(); i++) {
+ mshr = writebacks[i];
+
+ if (!mshr->pkt->req->isUncacheable()) {
+ if (pkt->isRead()) {
+ //Only Upgrades don't get here
+ //Supply the data
+ pkt->flags |= SATISFIED;
+
+ //If we are in an exclusive protocol, make it ask again
+ //to get write permissions (upgrade), signal shared
+ pkt->flags |= SHARED_LINE;
+
+ assert(pkt->isRead());
+ Addr offset = pkt->getAddr() & ~(blkSize - 1);
+ assert(offset < blkSize);
+ assert(pkt->getSize() <= blkSize);
+ assert(offset + pkt->getSize() <=blkSize);
+ memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
+
+ respondToSnoop(pkt);
+ }
+
+ if (pkt->isInvalidate()) {
+ //This must be an upgrade or other cache will take ownership
+ missQueue->markInService(mshr->pkt);
+ }
+ return;
+ }
+ }
+ }
+ }
+ CacheBlk::State new_state;
+ bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
+ if (satisfy) {
+ tags->handleSnoop(blk, new_state, pkt);
+ respondToSnoop(pkt);
+ return;
+ }
+ tags->handleSnoop(blk, new_state);
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::snoopResponse(Packet * &pkt)
+{
+ //Need to handle the response, if NACKED
+ if (pkt->flags & NACKED_LINE) {
+ //Need to mark it as not in service, and retry for bus
+ assert(0); //Yeah, we saw a NACK come through
+
+ //For now this should never get called, we return false when we see a NACK
+ //instead, by doing this we allow the bus_blocked mechanism to handle the retry
+ //For now it retrys in just 2 cycles, need to figure out how to change that
+ //Eventually we will want to also have success come in as a parameter
+ //Need to make sure that we handle the functionality that happens on successufl
+ //return of the sendAddr function
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::invalidateBlk(Addr addr, int asid)
+{
+ tags->invalidateBlk(addr,asid);
+}
+
+
+/**
+ * @todo Fix to not assume write allocate
+ */
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update)
+{
+// MemDebug::cacheProbe(pkt);
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->isInvalidate() && !pkt->isRead()
+ && !pkt->isWrite()) {
+ //Upgrade or Invalidate, satisfy it, don't forward
+ DPRINTF(Cache, "%s %d %x ? blk_addr: %x\n", pkt->cmdString(),
+ pkt->req->getAsid(), pkt->getAddr() & (((ULL(1))<<48)-1),
+ pkt->getAddr() & ~((Addr)blkSize - 1));
+ pkt->flags |= SATISFIED;
+ return 0;
+ }
+ }
+
+ PacketList writebacks;
+ int lat;
+ BlkType *blk = tags->handleAccess(pkt, lat, writebacks, update);
+
+ if (!blk) {
+ // Need to check for outstanding misses and writes
+ Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
+
+ // There can only be one matching outstanding miss.
+ MSHR* mshr = missQueue->findMSHR(blk_addr, pkt->req->getAsid());
+
+ // There can be many matching outstanding writes.
+ vector<MSHR*> writes;
+ missQueue->findWrites(blk_addr, pkt->req->getAsid(), writes);
+
+ if (!update) {
+ memSidePort->sendFunctional(pkt);
+ // Check for data in MSHR and writebuffer.
+ if (mshr) {
+ warn("Found outstanding miss on an non-update probe");
+ MSHR::TargetList *targets = mshr->getTargetList();
+ MSHR::TargetList::iterator i = targets->begin();
+ MSHR::TargetList::iterator end = targets->end();
+ for (; i != end; ++i) {
+ Packet * target = *i;
+ // If the target contains data, and it overlaps the
+ // probed request, need to update data
+ if (target->isWrite() && target->intersect(pkt)) {
+ uint8_t* pkt_data;
+ uint8_t* write_data;
+ int data_size;
+ if (target->getAddr() < pkt->getAddr()) {
+ int offset = pkt->getAddr() - target->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>();
+ write_data = target->getPtr<uint8_t>() + offset;
+ data_size = target->getSize() - offset;
+ assert(data_size > 0);
+ if (data_size > pkt->getSize())
+ data_size = pkt->getSize();
+ } else {
+ int offset = target->getAddr() - pkt->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>() + offset;
+ write_data = target->getPtr<uint8_t>();
+ data_size = pkt->getSize() - offset;
+ assert(data_size > pkt->getSize());
+ if (data_size > target->getSize())
+ data_size = target->getSize();
+ }
+
+ if (pkt->isWrite()) {
+ memcpy(pkt_data, write_data, data_size);
+ } else {
+ memcpy(write_data, pkt_data, data_size);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < writes.size(); ++i) {
+ Packet * write = writes[i]->pkt;
+ if (write->intersect(pkt)) {
+ warn("Found outstanding write on an non-update probe");
+ uint8_t* pkt_data;
+ uint8_t* write_data;
+ int data_size;
+ if (write->getAddr() < pkt->getAddr()) {
+ int offset = pkt->getAddr() - write->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>();
+ write_data = write->getPtr<uint8_t>() + offset;
+ data_size = write->getSize() - offset;
+ assert(data_size > 0);
+ if (data_size > pkt->getSize())
+ data_size = pkt->getSize();
+ } else {
+ int offset = write->getAddr() - pkt->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>() + offset;
+ write_data = write->getPtr<uint8_t>();
+ data_size = pkt->getSize() - offset;
+ assert(data_size > pkt->getSize());
+ if (data_size > write->getSize())
+ data_size = write->getSize();
+ }
+
+ if (pkt->isWrite()) {
+ memcpy(pkt_data, write_data, data_size);
+ } else {
+ memcpy(write_data, pkt_data, data_size);
+ }
+
+ }
+ }
+ return 0;
+ } else {
+ // update the cache state and statistics
+ if (mshr || !writes.empty()){
+ // Can't handle it, return pktuest unsatisfied.
+ return 0;
+ }
+ if (!pkt->req->isUncacheable()) {
+ // Fetch the cache block to fill
+ BlkType *blk = tags->findBlock(pkt);
+ Packet::Command temp_cmd = coherence->getBusCmd(pkt->cmd,
+ (blk)? blk->status : 0);
+
+ Packet * busPkt = new Packet(pkt->req,temp_cmd, -1, blkSize);
+
+ busPkt->allocate();
+
+ busPkt->time = curTick;
+
+ lat = memSidePort->sendAtomic(busPkt);
+
+/* if (!(busPkt->flags & SATISFIED)) {
+ // blocked at a higher level, just return
+ return 0;
+ }
+
+*/ misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+
+ CacheBlk::State old_state = (blk) ? blk->status : 0;
+ tags->handleFill(blk, busPkt,
+ coherence->getNewState(busPkt, old_state),
+ writebacks, pkt);
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ memSidePort->sendAtomic(writebacks.front());
+ writebacks.pop_front();
+ }
+ return lat + hitLatency;
+ } else {
+ return memSidePort->sendAtomic(pkt);
+ }
+ }
+ } else {
+ // There was a cache hit.
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ memSidePort->sendAtomic(writebacks.front());
+ writebacks.pop_front();
+ }
+
+ if (update) {
+ hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ } else if (pkt->isWrite()) {
+ // Still need to change data in all locations.
+ return memSidePort->sendAtomic(pkt);
+ }
+ return curTick + lat;
+ }
+ fatal("Probe not handled.\n");
+ return 0;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::snoopProbe(PacketPtr &pkt, bool update)
+{
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ BlkType *blk = tags->findBlock(pkt);
+ MSHR *mshr = missQueue->findMSHR(blk_addr, pkt->req->getAsid());
+ CacheBlk::State new_state = 0;
+ bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
+ if (satisfy) {
+ tags->handleSnoop(blk, new_state, pkt);
+ return hitLatency;
+ }
+ tags->handleSnoop(blk, new_state);
+ return 0;
+}
+
diff --git a/src/mem/cache/coherence/coherence_protocol.cc b/src/mem/cache/coherence/coherence_protocol.cc
new file mode 100644
index 000000000..bcf3ce9c5
--- /dev/null
+++ b/src/mem/cache/coherence/coherence_protocol.cc
@@ -0,0 +1,567 @@
+/*
+ * 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: Erik Hallnor
+ * Steve Reinhardt
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Definitions of CoherenceProtocol.
+ */
+
+#include <string>
+
+#include "base/misc.hh"
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/cache.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+
+CoherenceProtocol::StateTransition::StateTransition()
+ : busCmd(Packet::InvalidCmd), newState(-1), snoopFunc(invalidTransition)
+{
+}
+
+
+void
+CoherenceProtocol::regStats()
+{
+ // Even though we count all the possible transitions in the
+ // requestCount and snoopCount arrays, most of these are invalid,
+ // so we just select the interesting ones to print here.
+
+ requestCount[Invalid][Packet::ReadReq]
+ .name(name() + ".read_invalid")
+ .desc("read misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::WriteReq]
+ .name(name() +".write_invalid")
+ .desc("write misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::SoftPFReq]
+ .name(name() +".swpf_invalid")
+ .desc("soft prefetch misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::HardPFReq]
+ .name(name() +".hwpf_invalid")
+ .desc("hard prefetch misses to invalid blocks")
+ ;
+
+ requestCount[Shared][Packet::WriteReq]
+ .name(name() + ".write_shared")
+ .desc("write misses to shared blocks")
+ ;
+
+ requestCount[Owned][Packet::WriteReq]
+ .name(name() + ".write_owned")
+ .desc("write misses to owned blocks")
+ ;
+
+ snoopCount[Shared][Packet::ReadReq]
+ .name(name() + ".snoop_read_shared")
+ .desc("read snoops on shared blocks")
+ ;
+
+ snoopCount[Shared][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_shared")
+ .desc("readEx snoops on shared blocks")
+ ;
+
+ snoopCount[Shared][Packet::UpgradeReq]
+ .name(name() + ".snoop_upgrade_shared")
+ .desc("upgradee snoops on shared blocks")
+ ;
+
+ snoopCount[Modified][Packet::ReadReq]
+ .name(name() + ".snoop_read_modified")
+ .desc("read snoops on modified blocks")
+ ;
+
+ snoopCount[Modified][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_modified")
+ .desc("readEx snoops on modified blocks")
+ ;
+
+ snoopCount[Owned][Packet::ReadReq]
+ .name(name() + ".snoop_read_owned")
+ .desc("read snoops on owned blocks")
+ ;
+
+ snoopCount[Owned][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_owned")
+ .desc("readEx snoops on owned blocks")
+ ;
+
+ snoopCount[Owned][Packet::UpgradeReq]
+ .name(name() + ".snoop_upgrade_owned")
+ .desc("upgrade snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::ReadReq]
+ .name(name() + ".snoop_read_exclusive")
+ .desc("read snoops on exclusive blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_exclusive")
+ .desc("readEx snoops on exclusive blocks")
+ ;
+
+ snoopCount[Shared][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_shared")
+ .desc("Invalidate snoops on shared blocks")
+ ;
+
+ snoopCount[Owned][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_owned")
+ .desc("Invalidate snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_exclusive")
+ .desc("Invalidate snoops on exclusive blocks")
+ ;
+
+ snoopCount[Modified][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_modified")
+ .desc("Invalidate snoops on modified blocks")
+ ;
+
+ snoopCount[Invalid][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_invalid")
+ .desc("Invalidate snoops on invalid blocks")
+ ;
+
+ snoopCount[Shared][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_shared")
+ .desc("WriteInvalidate snoops on shared blocks")
+ ;
+
+ snoopCount[Owned][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_owned")
+ .desc("WriteInvalidate snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_exclusive")
+ .desc("WriteInvalidate snoops on exclusive blocks")
+ ;
+
+ snoopCount[Modified][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_modified")
+ .desc("WriteInvalidate snoops on modified blocks")
+ ;
+
+ snoopCount[Invalid][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_invalid")
+ .desc("WriteInvalidate snoops on invalid blocks")
+ ;
+}
+
+
+bool
+CoherenceProtocol::invalidateTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ // invalidate the block
+ new_state = (blk->status & ~stateMask) | Invalid;
+ return false;
+}
+
+
+bool
+CoherenceProtocol::supplyTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state
+ )
+{
+ return true;
+}
+
+
+bool
+CoherenceProtocol::supplyAndGotoSharedTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Shared;
+ pkt->flags |= SHARED_LINE;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+
+bool
+CoherenceProtocol::supplyAndGotoOwnedTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Owned;
+ pkt->flags |= SHARED_LINE;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+
+bool
+CoherenceProtocol::supplyAndInvalidateTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Invalid;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+bool
+CoherenceProtocol::assertShared(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Shared;
+ pkt->flags |= SHARED_LINE;
+ return false;
+}
+
+CoherenceProtocol::CoherenceProtocol(const string &name,
+ const string &protocol,
+ const bool doUpgrades)
+ : SimObject(name)
+{
+ if ((protocol == "mosi" || protocol == "moesi") && !doUpgrades) {
+ cerr << "CoherenceProtocol: ownership protocols require upgrade transactions"
+ << "(write miss on owned block generates ReadExcl, which will clobber dirty block)"
+ << endl;
+ fatal("");
+ }
+
+ Packet::Command writeToSharedCmd = doUpgrades ? Packet::UpgradeReq : Packet::ReadExReq;
+ Packet::Command writeToSharedResp = doUpgrades ? Packet::UpgradeResp : Packet::ReadExResp;
+
+//@todo add in hardware prefetch to this list
+ if (protocol == "msi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Shared);
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoSharedTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+
+ if (doUpgrades) {
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ }
+ }
+
+ else if(protocol == "mesi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Exclusive);
+ //It will move into shared if the shared line is asserted in the
+ //getNewState function
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Exclusive][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoSharedTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+
+ if (doUpgrades) {
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ }
+ }
+
+ else if(protocol == "mosi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ transitionTable[Owned][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Shared);
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+ transitionTable[Owned][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ }
+
+ else if(protocol == "moesi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ transitionTable[Owned][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Exclusive);
+ //It will move into shared if the shared line is asserted in the
+ //getNewState function
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+ transitionTable[Owned][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Exclusive][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ //Transitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ }
+
+ else {
+ cerr << "CoherenceProtocol: unrecognized protocol " << protocol
+ << endl;
+ fatal("");
+ }
+}
+
+
+Packet::Command
+CoherenceProtocol::getBusCmd(Packet::Command cmdIn, CacheBlk::State state,
+ MSHR *mshr)
+{
+ state &= stateMask;
+ int cmd_idx = (int) cmdIn;
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+ Packet::Command cmdOut = transitionTable[state][cmd_idx].busCmd;
+
+ assert(cmdOut != Packet::InvalidCmd);
+
+ ++requestCount[state][cmd_idx];
+
+ return cmdOut;
+}
+
+
+CacheBlk::State
+CoherenceProtocol::getNewState(Packet * &pkt, CacheBlk::State oldState)
+{
+ CacheBlk::State state = oldState & stateMask;
+ int cmd_idx = pkt->cmdToIndex();
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+ CacheBlk::State newState = transitionTable[state][cmd_idx].newState;
+
+ //Check if it's exclusive and the shared line was asserted,
+ //then goto shared instead
+ if (newState == Exclusive && (pkt->flags & SHARED_LINE)) {
+ newState = Shared;
+ }
+
+ assert(newState != -1);
+
+ //Make sure not to loose any other state information
+ newState = (oldState & ~stateMask) | newState;
+ return newState;
+}
+
+
+bool
+CoherenceProtocol::handleBusRequest(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ if (blk == NULL) {
+ // nothing to do if we don't have a block
+ return false;
+ }
+
+ CacheBlk::State state = blk->status & stateMask;
+ int cmd_idx = pkt->cmdToIndex();
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+// assert(mshr == NULL); // can't currently handle outstanding requests
+ //Check first if MSHR, and also insure, if there is one, that it is not in service
+ assert(!mshr || mshr->inService == 0);
+ ++snoopCount[state][cmd_idx];
+
+ bool ret = transitionTable[state][cmd_idx].snoopFunc(cache, pkt, blk, mshr,
+ new_state);
+
+
+
+ return ret;
+}
+
+bool
+CoherenceProtocol::nullTransition(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ // do nothing
+ if (blk)
+ new_state = blk->status;
+ return false;
+}
+
+
+bool
+CoherenceProtocol::invalidTransition(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ panic("Invalid transition");
+ return false;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+ Param<string> protocol;
+ Param<bool> do_upgrades;
+
+END_DECLARE_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+ INIT_PARAM(protocol, "name of coherence protocol"),
+ INIT_PARAM_DFLT(do_upgrades, "use upgrade transactions?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+
+CREATE_SIM_OBJECT(CoherenceProtocol)
+{
+ return new CoherenceProtocol(getInstanceName(), protocol,
+ do_upgrades);
+}
+
+REGISTER_SIM_OBJECT("CoherenceProtocol", CoherenceProtocol)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/coherence/coherence_protocol.hh b/src/mem/cache/coherence/coherence_protocol.hh
new file mode 100644
index 000000000..21351ace4
--- /dev/null
+++ b/src/mem/cache/coherence/coherence_protocol.hh
@@ -0,0 +1,263 @@
+/*
+ * 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: Erik Hallnor
+ * Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Declaration of CoherenceProcotol a basic coherence policy.
+ */
+#ifndef __COHERENCE_PROTOCOL_HH__
+#define __COHERENCE_PROTOCOL_HH__
+
+#include <string>
+
+#include "sim/sim_object.hh"
+#include "mem/packet.hh"
+#include "mem/cache/cache_blk.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class MSHR;
+
+/**
+ * A simple coherence policy for the memory hierarchy. Currently implements
+ * MSI, MESI, and MOESI protocols.
+ */
+class CoherenceProtocol : public SimObject
+{
+ public:
+ /**
+ * Contruct and initialize this policy.
+ * @param name The name of this policy.
+ * @param protocol The string representation of the protocol to use.
+ * @param doUpgrades True if bus upgrades should be used.
+ */
+ CoherenceProtocol(const std::string &name, const std::string &protocol,
+ const bool doUpgrades);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CoherenceProtocol() {};
+
+ /**
+ * Register statistics
+ */
+ virtual void regStats();
+
+ /**
+ * Get the proper bus command for the given command and status.
+ * @param cmd The request's command.
+ * @param status The current state of the cache block.
+ * @param mshr The MSHR matching the request.
+ * @return The proper bus command, as determined by the protocol.
+ */
+ Packet::Command getBusCmd(Packet::Command cmd, CacheBlk::State status,
+ MSHR *mshr = NULL);
+
+ /**
+ * Return the proper state given the current state and the bus response.
+ * @param req The bus response.
+ * @param oldState The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt,
+ CacheBlk::State oldState);
+
+ /**
+ * Handle snooped bus requests.
+ * @param cache The cache that snooped the request.
+ * @param req The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state The new coherence state of the block.
+ * @return True if the request should be satisfied locally.
+ */
+ bool handleBusRequest(BaseCache *cache, Packet * &pkt, CacheBlk *blk,
+ MSHR *mshr, CacheBlk::State &new_state);
+
+ protected:
+ /** Snoop function type. */
+ typedef bool (*SnoopFuncType)(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ //
+ // Standard snoop transition functions
+ //
+
+ /**
+ * Do nothing transition.
+ */
+ static bool nullTransition(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalid transition, basically panic.
+ */
+ static bool invalidTransition(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalidate block, move to Invalid state.
+ */
+ static bool invalidateTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data, no state transition.
+ */
+ static bool supplyTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data and go to Shared state.
+ */
+ static bool supplyAndGotoSharedTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data and go to Owned state.
+ */
+ static bool supplyAndGotoOwnedTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalidate block, supply data, and go to Invalid state.
+ */
+ static bool supplyAndInvalidateTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Assert the shared line for a block that is shared/exclusive.
+ */
+ static bool assertShared(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Definition of protocol state transitions.
+ */
+ class StateTransition
+ {
+ friend class CoherenceProtocol;
+
+ /** The bus command of this transition. */
+ Packet::Command busCmd;
+ /** The state to transition to. */
+ int newState;
+ /** The snoop function for this transition. */
+ SnoopFuncType snoopFunc;
+
+ /**
+ * Constructor, defaults to invalid transition.
+ */
+ StateTransition();
+
+ /**
+ * Initialize bus command.
+ * @param cmd The bus command to use.
+ */
+ void onRequest(Packet::Command cmd)
+ {
+ busCmd = cmd;
+ }
+
+ /**
+ * Set the transition state.
+ * @param s The new state.
+ */
+ void onResponse(CacheBlk::State s)
+ {
+ newState = s;
+ }
+
+ /**
+ * Initialize the snoop function.
+ * @param f The new snoop function.
+ */
+ void onSnoop(SnoopFuncType f)
+ {
+ snoopFunc = f;
+ }
+ };
+
+ friend class CoherenceProtocol::StateTransition;
+
+ /** Mask to select status bits relevant to coherence protocol. */
+ const static CacheBlk::State
+ stateMask = BlkValid | BlkWritable | BlkDirty;
+
+ /** The Modified (M) state. */
+ const static CacheBlk::State
+ Modified = BlkValid | BlkWritable | BlkDirty;
+ /** The Owned (O) state. */
+ const static CacheBlk::State
+ Owned = BlkValid | BlkDirty;
+ /** The Exclusive (E) state. */
+ const static CacheBlk::State
+ Exclusive = BlkValid | BlkWritable;
+ /** The Shared (S) state. */
+ const static CacheBlk::State
+ Shared = BlkValid;
+ /** The Invalid (I) state. */
+ const static CacheBlk::State
+ Invalid = 0;
+
+ /**
+ * Maximum state encoding value (used to size transition lookup
+ * table). Could be more than number of states, depends on
+ * encoding of status bits.
+ */
+ const static int stateMax = stateMask;
+
+ /**
+ * The table of all possible transitions, organized by starting state and
+ * request command.
+ */
+ StateTransition transitionTable[stateMax+1][NUM_MEM_CMDS];
+
+ /**
+ * @addtogroup CoherenceStatistics
+ * @{
+ */
+ /**
+ * State accesses from parent cache.
+ */
+ Stats::Scalar<> requestCount[stateMax+1][NUM_MEM_CMDS];
+ /**
+ * State accesses from snooped requests.
+ */
+ Stats::Scalar<> snoopCount[stateMax+1][NUM_MEM_CMDS];
+ /**
+ * @}
+ */
+};
+
+#endif // __COHERENCE_PROTOCOL_HH__
diff --git a/src/mem/cache/coherence/simple_coherence.hh b/src/mem/cache/coherence/simple_coherence.hh
new file mode 100644
index 000000000..ca9d18beb
--- /dev/null
+++ b/src/mem/cache/coherence/simple_coherence.hh
@@ -0,0 +1,161 @@
+/*
+ * 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: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Declaration of a simple coherence policy.
+ */
+
+#ifndef __SIMPLE_COHERENCE_HH__
+#define __SIMPLE_COHERENCE_HH__
+
+#include <string>
+
+#include "mem/packet.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+
+class BaseCache;
+
+/**
+ * A simple MP coherence policy. This policy assumes an atomic bus and only one
+ * level of cache.
+ */
+class SimpleCoherence
+{
+ protected:
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+ /** Pointer to the coherence protocol. */
+ CoherenceProtocol *protocol;
+
+ public:
+ /**
+ * Construct and initialize this coherence policy.
+ * @param _protocol The coherence protocol to use.
+ */
+ SimpleCoherence(CoherenceProtocol *_protocol)
+ : protocol(_protocol)
+ {
+ }
+
+ /**
+ * Set the pointer to the parent cache.
+ * @param _cache The parent cache.
+ */
+ void setCache(BaseCache *_cache)
+ {
+ cache = _cache;
+ }
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to stat descriptions.
+ */
+ void regStats(const std::string &name)
+ {
+ }
+
+ /**
+ * This policy does not forward invalidates, return NULL.
+ * @return NULL.
+ */
+ Packet * getPacket()
+ {
+ return NULL;
+ }
+
+ /**
+ * Return the proper state given the current state and the bus response.
+ * @param req The bus response.
+ * @param current The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt, CacheBlk::State current)
+ {
+ return protocol->getNewState(pkt, current);
+ }
+
+ /**
+ * Handle snooped bus requests.
+ * @param req The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state Return the new state for the block.
+ */
+ bool handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state)
+ {
+// assert(mshr == NULL);
+//Got rid of, there could be an MSHR, but it can't be in service
+ if (blk != NULL)
+ {
+ if (pkt->cmd != Packet::Writeback) {
+ return protocol->handleBusRequest(cache, pkt, blk, mshr,
+ new_state);
+ }
+ else { //It is a writeback, must be ownership protocol, just keep state
+ new_state = blk->status;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the proper bus command for the given command and status.
+ * @param cmd The request's command.
+ * @param state The current state of the cache block.
+ * @return The proper bus command, as determined by the protocol.
+ */
+ Packet::Command getBusCmd(Packet::Command &cmd, CacheBlk::State state)
+ {
+ if (cmd == Packet::Writeback) return Packet::Writeback;
+ return protocol->getBusCmd(cmd, state);
+ }
+
+ /**
+ * Return true if this coherence policy can handle fast cache writes.
+ */
+ bool allowFastWrites() { return false; }
+
+ bool hasProtocol() { return true; }
+};
+
+#endif //__SIMPLE_COHERENCE_HH__
+
+
+
+
+
+
+
+
diff --git a/src/mem/cache/coherence/uni_coherence.cc b/src/mem/cache/coherence/uni_coherence.cc
new file mode 100644
index 000000000..5ab706269
--- /dev/null
+++ b/src/mem/cache/coherence/uni_coherence.cc
@@ -0,0 +1,86 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/base_cache.hh"
+
+#include "base/trace.hh"
+
+using namespace std;
+
+UniCoherence::UniCoherence()
+ : cshrs(50)
+{
+}
+
+Packet *
+UniCoherence::getPacket()
+{
+ bool unblock = cshrs.isFull();
+ Packet* pkt = cshrs.getReq();
+ cshrs.markInService((MSHR*)pkt->senderState);
+ if (!cshrs.havePending()) {
+ cache->clearSlaveRequest(Request_Coherence);
+ }
+ if (unblock) {
+ //since CSHRs are always used as buffers, should always get rid of one
+ assert(!cshrs.isFull());
+ cache->clearBlocked(Blocked_Coherence);
+ }
+ return pkt;
+}
+
+/**
+ * @todo add support for returning slave requests, not doing them here.
+ */
+bool
+UniCoherence::handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state)
+{
+ new_state = 0;
+ if (pkt->isInvalidate()) {
+ DPRINTF(Cache, "snoop inval on blk %x (blk ptr %x)\n",
+ pkt->getAddr(), blk);
+ if (!cache->isTopLevel()) {
+ // Forward to other caches
+ Packet * tmp = new Packet(pkt->req, Packet::InvalidateReq, -1);
+ cshrs.allocate(tmp);
+ cache->setSlaveRequest(Request_Coherence, curTick);
+ if (cshrs.isFull()) {
+ cache->setBlockedForSnoop(Blocked_Coherence);
+ }
+ }
+ } else {
+ if (blk) {
+ new_state = blk->status;
+ }
+ }
+ return false;
+}
diff --git a/src/mem/cache/coherence/uni_coherence.hh b/src/mem/cache/coherence/uni_coherence.hh
new file mode 100644
index 000000000..764bf6276
--- /dev/null
+++ b/src/mem/cache/coherence/uni_coherence.hh
@@ -0,0 +1,136 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+#ifndef __UNI_COHERENCE_HH__
+#define __UNI_COHERENCE_HH__
+
+#include "base/trace.hh"
+#include "base/misc.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "mem/packet.hh"
+
+class BaseCache;
+
+class UniCoherence
+{
+ protected:
+ /** Buffers to hold forwarded invalidates. */
+ MSHRQueue cshrs;
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+
+ public:
+ /**
+ * Construct and initialize this coherence policy.
+ */
+ UniCoherence();
+
+ /**
+ * Set the pointer to the parent cache.
+ * @param _cache The parent cache.
+ */
+ void setCache(BaseCache *_cache)
+ {
+ cache = _cache;
+ }
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to stat descriptions.
+ */
+ void regStats(const std::string &name)
+ {
+ }
+
+ /**
+ * Return Read.
+ * @param cmd The request's command.
+ * @param state The current state of the cache block.
+ * @return The proper bus command, as determined by the protocol.
+ * @todo Make changes so writebacks don't get here.
+ */
+ Packet::Command getBusCmd(Packet::Command &cmd, CacheBlk::State state)
+ {
+ if (cmd == Packet::HardPFReq && state)
+ warn("Trying to issue a prefetch to a block we already have\n");
+ if (cmd == Packet::Writeback)
+ return Packet::Writeback;
+ return Packet::ReadReq;
+ }
+
+ /**
+ * Just return readable and writeable.
+ * @param req The bus response.
+ * @param current The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt, CacheBlk::State current)
+ {
+ if (pkt->senderState) //Blocking Buffers don't get mshrs
+ {
+ if (((MSHR *)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "Marking a hardware prefetch as such in the state\n");
+ return BlkHWPrefetched | BlkValid | BlkWritable;
+ }
+ else {
+ return BlkValid | BlkWritable;
+ }
+ }
+ //@todo What about prefetching with blocking buffers
+ else
+ return BlkValid | BlkWritable;
+ }
+ /**
+ * Return outstanding invalidate to forward.
+ * @return The next invalidate to forward to lower levels of cache.
+ */
+ Packet * getPacket();
+
+ /**
+ * Handle snooped bus requests.
+ * @param req The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state The new coherence state of the block.
+ * @return True if the request should be satisfied locally.
+ */
+ bool handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state);
+
+ /**
+ * Return true if this coherence policy can handle fast cache writes.
+ */
+ bool allowFastWrites() { return true; }
+
+ bool hasProtocol() { return false; }
+};
+
+#endif //__UNI_COHERENCE_HH__
diff --git a/src/mem/cache/miss/blocking_buffer.cc b/src/mem/cache/miss/blocking_buffer.cc
new file mode 100644
index 000000000..10d53b109
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.cc
@@ -0,0 +1,245 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of a simple buffer for a blocking cache.
+ */
+
+#include "cpu/smt.hh" //for maxThreadsPerCPU
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+#include "sim/eventq.hh" // for Event declaration.
+#include "mem/request.hh"
+
+using namespace TheISA;
+
+/**
+ * @todo Move writebacks into shared BaseBuffer class.
+ */
+void
+BlockingBuffer::regStats(const std::string &name)
+{
+ using namespace Stats;
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+}
+
+void
+BlockingBuffer::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+BlockingBuffer::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+void
+BlockingBuffer::handleMiss(Packet * &pkt, int blk_size, Tick time)
+{
+ Addr blk_addr = pkt->getAddr() & ~(Addr)(blk_size - 1);
+ if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
+ !pkt->needsResponse())) {
+ if (!pkt->needsResponse()) {
+ wb.allocateAsBuffer(pkt);
+ } else {
+ wb.allocate(pkt->cmd, blk_addr, pkt->req->getAsid(), blk_size, pkt);
+ }
+
+ memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), blk_size);
+
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, time);
+ return;
+ }
+
+ if (!pkt->needsResponse()) {
+ miss.allocateAsBuffer(pkt);
+ } else {
+ miss.allocate(pkt->cmd, blk_addr, pkt->req->getAsid(), blk_size, pkt);
+ }
+ if (!pkt->req->isUncacheable()) {
+ miss.pkt->flags |= CACHE_LINE_FILL;
+ }
+ cache->setBlocked(Blocked_NoMSHRs);
+ cache->setMasterRequest(Request_MSHR, time);
+}
+
+Packet *
+BlockingBuffer::getPacket()
+{
+ if (miss.pkt && !miss.inService) {
+ return miss.pkt;
+ }
+ return wb.pkt;
+}
+
+void
+BlockingBuffer::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ MSHR *mshr = (MSHR*) pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill())
+ pkt->cmdOverride(cmd);
+}
+
+void
+BlockingBuffer::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmdOverride(((MSHR*)(pkt->senderState))->originalCmd);
+}
+
+void
+BlockingBuffer::markInService(Packet * &pkt)
+{
+ if (!pkt->isCacheFill() && pkt->isWrite()) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ assert((MSHR*)pkt->senderState == &wb);
+ cache->clearMasterRequest(Request_WB);
+ if (!pkt->needsResponse()) {
+ assert(wb.getNumTargets() == 0);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ wb.inService = true;
+ }
+ } else {
+ assert((MSHR*)pkt->senderState == &miss);
+ cache->clearMasterRequest(Request_MSHR);
+ if (!pkt->needsResponse()) {
+ assert(miss.getNumTargets() == 0);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ //mark in service
+ miss.inService = true;
+ }
+ }
+}
+
+void
+BlockingBuffer::handleResponse(Packet * &pkt, Tick time)
+{
+ if (pkt->isCacheFill()) {
+ // targets were handled in the cache tags
+ assert((MSHR*)pkt->senderState == &miss);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ if (((MSHR*)(pkt->senderState))->hasTargets()) {
+ // Should only have 1 target if we had any
+ assert(((MSHR*)(pkt->senderState))->getNumTargets() == 1);
+ Packet * target = ((MSHR*)(pkt->senderState))->getTarget();
+ ((MSHR*)(pkt->senderState))->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), target->getSize());
+ }
+ cache->respond(target, time);
+ assert(!((MSHR*)(pkt->senderState))->hasTargets());
+ }
+
+ if (pkt->isWrite()) {
+ assert(((MSHR*)(pkt->senderState)) == &wb);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ }
+ }
+}
+
+void
+BlockingBuffer::squash(int threadNum)
+{
+ if (miss.threadNum == threadNum) {
+ Packet * target = miss.getTarget();
+ miss.popTarget();
+ assert(target->req->getThreadNum() == threadNum);
+ target = NULL;
+ assert(!miss.hasTargets());
+ miss.ntargets=0;
+ if (!miss.inService) {
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ }
+}
+
+void
+BlockingBuffer::doWriteback(Addr addr, int asid,
+ int size, uint8_t *data, bool compressed)
+{
+ // Generate request
+ Request * req = new Request(addr, size, 0);
+ Packet * pkt = new Packet(req, Packet::Writeback, -1);
+ pkt->allocate();
+ if (data) {
+ memcpy(pkt->getPtr<uint8_t>(), data, size);
+ }
+
+ if (compressed) {
+ pkt->flags |= COMPRESSED;
+ }
+
+ ///All writebacks charged to same thread @todo figure this out
+ writebacks[pkt->req->getThreadNum()]++;
+
+ wb.allocateAsBuffer(pkt);
+ cache->setMasterRequest(Request_WB, curTick);
+ cache->setBlocked(Blocked_NoWBBuffers);
+}
+
+
+
+void
+BlockingBuffer::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->req->getThreadNum()]++;
+
+ wb.allocateAsBuffer(pkt);
+
+ // Since allocate as buffer copies the request,
+ // need to copy data here.
+ memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
+
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, curTick);
+}
diff --git a/src/mem/cache/miss/blocking_buffer.hh b/src/mem/cache/miss/blocking_buffer.hh
new file mode 100644
index 000000000..39a06a377
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.hh
@@ -0,0 +1,256 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a simple buffer for a blocking cache.
+ */
+
+#ifndef __BLOCKING_BUFFER_HH__
+#define __BLOCKING_BUFFER_HH__
+
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+
+/**
+ * Miss and writeback storage for a blocking cache.
+ */
+class BlockingBuffer
+{
+protected:
+ /** Miss storage. */
+ MSHR miss;
+ /** WB storage. */
+ MSHR wb;
+
+ //Params
+
+ /** Allocate on write misses. */
+ const bool writeAllocate;
+
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ BasePrefetcher* prefetcher;
+
+ /** Block size of the parent cache. */
+ int blkSize;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /**
+ * @}
+ */
+
+public:
+ /**
+ * Builds and initializes this buffer.
+ * @param write_allocate If true, treat write misses the same as reads.
+ */
+ BlockingBuffer(bool write_allocate)
+ : writeAllocate(write_allocate)
+ {
+ }
+
+ /**
+ * Register statistics for this object.
+ * @param name The name of the parent cache.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Called by the parent cache to set the back pointer.
+ * @param _cache A pointer to the parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ void setPrefetcher(BasePrefetcher *_prefetcher);
+
+ /**
+ * Handle a cache miss properly. Requests the bus and marks the cache as
+ * blocked.
+ * @param req The request that missed in the cache.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ */
+ void handleMiss(Packet * &pkt, int blk_size, Tick time);
+
+ /**
+ * Fetch the block for the given address and buffer the given target.
+ * @param addr The address to fetch.
+ * @param asid The address space of the address.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ * @param target The target for the fetch.
+ */
+ MSHR* fetchBlock(Addr addr, int asid, int blk_size, Tick time,
+ Packet * &target)
+ {
+ fatal("Unimplemented");
+ }
+
+ /**
+ * Selects a outstanding request to service.
+ * @return The request to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param req The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param req The request to reset.
+ */
+ void restoreOrigCmd(Packet * &pkt);
+
+ /**
+ * Marks a request as in service (sent on the bus). This can have side
+ * effect since storage for no response commands is deallocated once they
+ * are successfully sent.
+ * @param req The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Frees the resources of the request and unblock the cache.
+ * @param req The request that has been satisfied.
+ * @param time The time when the request is satisfied.
+ */
+ void handleResponse(Packet * &pkt, Tick time);
+
+ /**
+ * Removes all outstanding requests for a given thread number. If a request
+ * has been sent to the bus, this function removes all of its targets.
+ * @param req->getThreadNum()ber The thread number of the requests to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Return the current number of outstanding misses.
+ * @return the number of outstanding misses.
+ */
+ int getMisses()
+ {
+ return miss.getNumTargets();
+ }
+
+ /**
+ * Searches for the supplied address in the miss "queue".
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @return A pointer to miss if it matches.
+ */
+ MSHR* findMSHR(Addr addr, int asid)
+ {
+ if (miss.addr == addr && miss.pkt)
+ return &miss;
+ return NULL;
+ }
+
+ /**
+ * Searches for the supplied address in the write buffer.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @param writes List of pointers to the matching writes.
+ * @return True if there is a matching write.
+ */
+ bool findWrites(Addr addr, int asid, std::vector<MSHR*>& writes)
+ {
+ if (wb.addr == addr && wb.pkt) {
+ writes.push_back(&wb);
+ return true;
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Perform a writeback of dirty data to the given address.
+ * @param addr The address to write to.
+ * @param asid The address space id.
+ * @param size The number of bytes to write.
+ * @param data The data to write, can be NULL.
+ * @param compressed True if the data is compressed.
+ */
+ void doWriteback(Addr addr, int asid,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform a writeback request.
+ * @param req The writeback request.
+ */
+ void doWriteback(Packet * &pkt);
+
+ /**
+ * Returns true if there are outstanding requests.
+ * @return True if there are outstanding requests.
+ */
+ bool havePending()
+ {
+ return !miss.inService || !wb.inService;
+ }
+
+ /**
+ * Add a target to the given MSHR. This assumes it is in the miss queue.
+ * @param mshr The mshr to add a target to.
+ * @param req The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &pkt)
+ {
+ fatal("Shouldn't call this on a blocking buffer.");
+ }
+
+ /**
+ * Dummy implmentation.
+ */
+ MSHR* allocateTargetList(Addr addr, int asid)
+ {
+ fatal("Unimplemented");
+ }
+};
+
+#endif // __BLOCKING_BUFFER_HH__
diff --git a/src/mem/cache/miss/miss_queue.cc b/src/mem/cache/miss/miss_queue.cc
new file mode 100644
index 000000000..da0448ad3
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.cc
@@ -0,0 +1,757 @@
+/*
+ * 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: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Miss and writeback queue definitions.
+ */
+
+#include "cpu/smt.hh" //for maxThreadsPerCPU
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+
+using namespace std;
+
+// simple constructor
+/**
+ * @todo Remove the +16 from the write buffer constructor once we handle
+ * stalling on writebacks do to compression writes.
+ */
+MissQueue::MissQueue(int numMSHRs, int numTargets, int write_buffers,
+ bool write_allocate, bool prefetch_miss)
+ : mq(numMSHRs, 4), wb(write_buffers,numMSHRs+1000), numMSHR(numMSHRs),
+ numTarget(numTargets), writeBuffers(write_buffers),
+ writeAllocate(write_allocate), order(0), prefetchMiss(prefetch_miss)
+{
+ noTargetMSHR = NULL;
+}
+
+void
+MissQueue::regStats(const string &name)
+{
+ Request temp_req((Addr) NULL, 4, 0);
+ Packet::Command temp_cmd = Packet::ReadReq;
+ Packet temp_pkt(&temp_req, temp_cmd, 0); //@todo FIx command strings so this isn't neccessary
+ temp_pkt.allocate();
+
+ using namespace Stats;
+
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+
+ // MSHR hit statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_hits[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_hits")
+ .desc("number of " + cstr + " MSHR hits")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrHits
+ .name(name + ".demand_mshr_hits")
+ .desc("number of demand (read+write) MSHR hits")
+ .flags(total)
+ ;
+ demandMshrHits = mshr_hits[Packet::ReadReq] + mshr_hits[Packet::WriteReq];
+
+ overallMshrHits
+ .name(name + ".overall_mshr_hits")
+ .desc("number of overall MSHR hits")
+ .flags(total)
+ ;
+ overallMshrHits = demandMshrHits + mshr_hits[Packet::SoftPFReq] +
+ mshr_hits[Packet::HardPFReq];
+
+ // MSHR miss statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_misses[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_misses")
+ .desc("number of " + cstr + " MSHR misses")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMisses
+ .name(name + ".demand_mshr_misses")
+ .desc("number of demand (read+write) MSHR misses")
+ .flags(total)
+ ;
+ demandMshrMisses = mshr_misses[Packet::ReadReq] + mshr_misses[Packet::WriteReq];
+
+ overallMshrMisses
+ .name(name + ".overall_mshr_misses")
+ .desc("number of overall MSHR misses")
+ .flags(total)
+ ;
+ overallMshrMisses = demandMshrMisses + mshr_misses[Packet::SoftPFReq] +
+ mshr_misses[Packet::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_miss_latency[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_miss_latency")
+ .desc("number of " + cstr + " MSHR miss cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMissLatency
+ .name(name + ".demand_mshr_miss_latency")
+ .desc("number of demand (read+write) MSHR miss cycles")
+ .flags(total)
+ ;
+ demandMshrMissLatency = mshr_miss_latency[Packet::ReadReq]
+ + mshr_miss_latency[Packet::WriteReq];
+
+ overallMshrMissLatency
+ .name(name + ".overall_mshr_miss_latency")
+ .desc("number of overall MSHR miss cycles")
+ .flags(total)
+ ;
+ overallMshrMissLatency = demandMshrMissLatency +
+ mshr_miss_latency[Packet::SoftPFReq] + mshr_miss_latency[Packet::HardPFReq];
+
+ // MSHR uncacheable statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_uncacheable[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_uncacheable")
+ .desc("number of " + cstr + " MSHR uncacheable")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheable
+ .name(name + ".overall_mshr_uncacheable_misses")
+ .desc("number of overall MSHR uncacheable misses")
+ .flags(total)
+ ;
+ overallMshrUncacheable = mshr_uncacheable[Packet::ReadReq]
+ + mshr_uncacheable[Packet::WriteReq] + mshr_uncacheable[Packet::SoftPFReq]
+ + mshr_uncacheable[Packet::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_uncacheable_lat[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_uncacheable_latency")
+ .desc("number of " + cstr + " MSHR uncacheable cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheableLatency
+ .name(name + ".overall_mshr_uncacheable_latency")
+ .desc("number of overall MSHR uncacheable cycles")
+ .flags(total)
+ ;
+ overallMshrUncacheableLatency = mshr_uncacheable_lat[Packet::ReadReq]
+ + mshr_uncacheable_lat[Packet::WriteReq]
+ + mshr_uncacheable_lat[Packet::SoftPFReq]
+ + mshr_uncacheable_lat[Packet::HardPFReq];
+
+#if 0
+ // MSHR access formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshrAccesses[access_idx]
+ .name(name + "." + cstr + "_mshr_accesses")
+ .desc("number of " + cstr + " mshr accesses(hits+misses)")
+ .flags(total | nozero | nonan)
+ ;
+ mshrAccesses[access_idx] =
+ mshr_hits[access_idx] + mshr_misses[access_idx]
+ + mshr_uncacheable[access_idx];
+ }
+
+ demandMshrAccesses
+ .name(name + ".demand_mshr_accesses")
+ .desc("number of demand (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ demandMshrAccesses = demandMshrHits + demandMshrMisses;
+
+ overallMshrAccesses
+ .name(name + ".overall_mshr_accesses")
+ .desc("number of overall (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ overallMshrAccesses = overallMshrHits + overallMshrMisses
+ + overallMshrUncacheable;
+#endif
+
+ // MSHR miss rate formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshrMissRate[access_idx]
+ .name(name + "." + cstr + "_mshr_miss_rate")
+ .desc("mshr miss rate for " + cstr + " accesses")
+ .flags(total | nozero | nonan)
+ ;
+
+ mshrMissRate[access_idx] =
+ mshr_misses[access_idx] / cache->accesses[access_idx];
+ }
+
+ demandMshrMissRate
+ .name(name + ".demand_mshr_miss_rate")
+ .desc("mshr miss rate for demand accesses")
+ .flags(total)
+ ;
+ demandMshrMissRate = demandMshrMisses / cache->demandAccesses;
+
+ overallMshrMissRate
+ .name(name + ".overall_mshr_miss_rate")
+ .desc("mshr miss rate for overall accesses")
+ .flags(total)
+ ;
+ overallMshrMissRate = overallMshrMisses / cache->overallAccesses;
+
+ // mshrMiss latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMshrMissLatency[access_idx]
+ .name(name + "." + cstr + "_avg_mshr_miss_latency")
+ .desc("average " + cstr + " mshr miss latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrMissLatency[access_idx] =
+ mshr_miss_latency[access_idx] / mshr_misses[access_idx];
+ }
+
+ demandAvgMshrMissLatency
+ .name(name + ".demand_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
+
+ overallAvgMshrMissLatency
+ .name(name + ".overall_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
+
+ // mshrUncacheable latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMshrUncacheableLatency[access_idx]
+ .name(name + "." + cstr + "_avg_mshr_uncacheable_latency")
+ .desc("average " + cstr + " mshr uncacheable latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrUncacheableLatency[access_idx] =
+ mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
+ }
+
+ overallAvgMshrUncacheableLatency
+ .name(name + ".overall_avg_mshr_uncacheable_latency")
+ .desc("average overall mshr uncacheable latency")
+ .flags(total)
+ ;
+ overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
+
+ mshr_cap_events
+ .init(maxThreadsPerCPU)
+ .name(name + ".mshr_cap_events")
+ .desc("number of times MSHR cap was activated")
+ .flags(total)
+ ;
+
+ //software prefetching stats
+ soft_prefetch_mshr_full
+ .init(maxThreadsPerCPU)
+ .name(name + ".soft_prefetch_mshr_full")
+ .desc("number of mshr full events for SW prefetching instrutions")
+ .flags(total)
+ ;
+
+ mshr_no_allocate_misses
+ .name(name +".no_allocate_misses")
+ .desc("Number of misses that were no-allocate")
+ ;
+
+}
+
+void
+MissQueue::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+MissQueue::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+
+MSHR*
+MissQueue::allocateMiss(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = mq.allocate(pkt, size);
+ mshr->order = order++;
+ if (!pkt->req->isUncacheable() ){//&& !pkt->isNoAllocate()) {
+ // Mark this as a cache line fill
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ }
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ if (pkt->cmd != Packet::HardPFReq) {
+ //If we need to request the bus (not on HW prefetch), do so
+ cache->setMasterRequest(Request_MSHR, time);
+ }
+ return mshr;
+}
+
+
+MSHR*
+MissQueue::allocateWrite(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = wb.allocate(pkt,pkt->getSize());
+ mshr->order = order++;
+
+//REMOVING COMPRESSION FOR NOW
+#if 0
+ if (pkt->isCompressed()) {
+ mshr->pkt->deleteData();
+ mshr->pkt->actualSize = pkt->actualSize;
+ mshr->pkt->data = new uint8_t[pkt->actualSize];
+ memcpy(mshr->pkt->data, pkt->data, pkt->actualSize);
+ } else {
+#endif
+ memcpy(mshr->pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
+ //{
+
+ if (wb.isFull()) {
+ cache->setBlocked(Blocked_NoWBBuffers);
+ }
+
+ cache->setMasterRequest(Request_WB, time);
+
+ return mshr;
+}
+
+
+/**
+ * @todo Remove SW prefetches on mshr hits.
+ */
+void
+MissQueue::handleMiss(Packet * &pkt, int blkSize, Tick time)
+{
+// if (!cache->isTopLevel())
+ if (prefetchMiss) prefetcher->handleMiss(pkt, time);
+
+ int size = blkSize;
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
+ MSHR* mshr = NULL;
+ if (!pkt->req->isUncacheable()) {
+ mshr = mq.findMatch(blkAddr, pkt->req->getAsid());
+ if (mshr) {
+ //@todo remove hw_pf here
+ mshr_hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ if (mshr->threadNum != pkt->req->getThreadNum()) {
+ mshr->threadNum = -1;
+ }
+ mq.allocateTarget(mshr, pkt);
+ if (mshr->pkt->isNoAllocate() && !pkt->isNoAllocate()) {
+ //We are adding an allocate after a no-allocate
+ mshr->pkt->flags &= ~NO_ALLOCATE;
+ }
+ if (mshr->getNumTargets() == numTarget) {
+ noTargetMSHR = mshr;
+ cache->setBlocked(Blocked_NoTargets);
+ mq.moveToFront(mshr);
+ }
+ return;
+ }
+ if (pkt->isNoAllocate()) {
+ //Count no-allocate requests differently
+ mshr_no_allocate_misses++;
+ }
+ else {
+ mshr_misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ }
+ } else {
+ //Count uncacheable accesses
+ mshr_uncacheable[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ size = pkt->getSize();
+ }
+ if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
+ !pkt->needsResponse())) {
+ /**
+ * @todo Add write merging here.
+ */
+ mshr = allocateWrite(pkt, pkt->getSize(), time);
+ return;
+ }
+
+ mshr = allocateMiss(pkt, size, time);
+}
+
+MSHR*
+MissQueue::fetchBlock(Addr addr, int asid, int blk_size, Tick time,
+ Packet * &target)
+{
+ Addr blkAddr = addr & ~(Addr)(blk_size - 1);
+ assert(mq.findMatch(addr, asid) == NULL);
+ MSHR *mshr = mq.allocateFetch(blkAddr, asid, blk_size, target);
+ mshr->order = order++;
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ cache->setMasterRequest(Request_MSHR, time);
+ return mshr;
+}
+
+Packet *
+MissQueue::getPacket()
+{
+ Packet * pkt = mq.getReq();
+ if (((wb.isFull() && wb.inServiceMSHRs == 0) || !pkt ||
+ pkt->time > curTick) && wb.havePending()) {
+ pkt = wb.getReq();
+ // Need to search for earlier miss.
+ MSHR *mshr = mq.findPending(pkt);
+ if (mshr && mshr->order < ((MSHR*)(pkt->senderState))->order) {
+ // Service misses in order until conflict is cleared.
+ return mq.getReq();
+ }
+ }
+ if (pkt) {
+ MSHR* mshr = wb.findPending(pkt);
+ if (mshr /*&& mshr->order < pkt->senderState->order*/) {
+ // The only way this happens is if we are
+ // doing a write and we didn't have permissions
+ // then subsequently saw a writeback(owned got evicted)
+ // We need to make sure to perform the writeback first
+ // To preserve the dirty data, then we can issue the write
+ return wb.getReq();
+ }
+ }
+ else if (!mq.isFull()){
+ //If we have a miss queue slot, we can try a prefetch
+ pkt = prefetcher->getPacket();
+ if (pkt) {
+ //Update statistic on number of prefetches issued (hwpf_mshr_misses)
+ mshr_misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ //It will request the bus for the future, but should clear that immedieatley
+ allocateMiss(pkt, pkt->getSize(), curTick);
+ pkt = mq.getReq();
+ assert(pkt); //We should get back a req b/c we just put one in
+ }
+ }
+ return pkt;
+}
+
+void
+MissQueue::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ assert(pkt->senderState != 0);
+ MSHR * mshr = (MSHR*)pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill() || pkt->isNoAllocate())
+ pkt->cmd = cmd;
+}
+
+void
+MissQueue::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmd = ((MSHR*)(pkt->senderState))->originalCmd;
+}
+
+void
+MissQueue::markInService(Packet * &pkt)
+{
+ assert(pkt->senderState != 0);
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ /**
+ * @todo Should include MSHRQueue pointer in MSHR to select the correct
+ * one.
+ */
+ if ((!pkt->isCacheFill() && pkt->isWrite())) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ unblock = wb.isFull();
+ wb.markInService((MSHR*)pkt->senderState);
+ if (!wb.havePending()){
+ cache->clearMasterRequest(Request_WB);
+ }
+ if (unblock) {
+ // Do we really unblock?
+ unblock = !wb.isFull();
+ cause = Blocked_NoWBBuffers;
+ }
+ } else {
+ unblock = mq.isFull();
+ mq.markInService((MSHR*)pkt->senderState);
+ if (!mq.havePending()){
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (((MSHR*)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n",
+ cache->name());
+ //Also clear pending if need be
+ if (!prefetcher->havePending())
+ {
+ cache->clearMasterRequest(Request_PF);
+ }
+ }
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ if (unblock) {
+ cache->clearBlocked(cause);
+ }
+}
+
+
+void
+MissQueue::handleResponse(Packet * &pkt, Tick time)
+{
+ MSHR* mshr = (MSHR*)pkt->senderState;
+ if (((MSHR*)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "%s:Handling the response to a HW_PF\n",
+ cache->name());
+ }
+#ifndef NDEBUG
+ int num_targets = mshr->getNumTargets();
+#endif
+
+ bool unblock = false;
+ bool unblock_target = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
+ mshr_miss_latency[mshr->originalCmd][pkt->req->getThreadNum()] +=
+ curTick - pkt->time;
+ // targets were handled in the cache tags
+ if (mshr == noTargetMSHR) {
+ // we always clear at least one target
+ unblock_target = true;
+ cause = Blocked_NoTargets;
+ noTargetMSHR = NULL;
+ }
+
+ if (mshr->hasTargets()) {
+ // Didn't satisfy all the targets, need to resend
+ Packet::Command cmd = mshr->getTarget()->cmd;
+ mq.markPending(mshr, cmd);
+ mshr->order = order++;
+ cache->setMasterRequest(Request_MSHR, time);
+ }
+ else {
+ unblock = mq.isFull();
+ mq.deallocate(mshr);
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ } else {
+ if (pkt->req->isUncacheable()) {
+ mshr_uncacheable_lat[pkt->cmd][pkt->req->getThreadNum()] +=
+ curTick - pkt->time;
+ }
+ if (mshr->hasTargets() && pkt->req->isUncacheable()) {
+ // Should only have 1 target if we had any
+ assert(num_targets == 1);
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
+ target->getSize());
+ }
+ cache->respond(target, time);
+ assert(!mshr->hasTargets());
+ }
+ else if (mshr->hasTargets()) {
+ //Must be a no_allocate with possibly more than one target
+ assert(mshr->pkt->isNoAllocate());
+ while (mshr->hasTargets()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
+ target->getSize());
+ }
+ cache->respond(target, time);
+ }
+ }
+
+ if (pkt->isWrite()) {
+ // If the wrtie buffer is full, we might unblock now
+ unblock = wb.isFull();
+ wb.deallocate(mshr);
+ if (unblock) {
+ // Did we really unblock?
+ unblock = !wb.isFull();
+ cause = Blocked_NoWBBuffers;
+ }
+ } else {
+ unblock = mq.isFull();
+ mq.deallocate(mshr);
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ }
+ if (unblock || unblock_target) {
+ cache->clearBlocked(cause);
+ }
+}
+
+void
+MissQueue::squash(int threadNum)
+{
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (noTargetMSHR && noTargetMSHR->threadNum == threadNum) {
+ noTargetMSHR = NULL;
+ unblock = true;
+ cause = Blocked_NoTargets;
+ }
+ if (mq.isFull()) {
+ unblock = true;
+ cause = Blocked_NoMSHRs;
+ }
+ mq.squash(threadNum);
+ if (!mq.havePending()) {
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (unblock && !mq.isFull()) {
+ cache->clearBlocked(cause);
+ }
+
+}
+
+MSHR*
+MissQueue::findMSHR(Addr addr, int asid) const
+{
+ return mq.findMatch(addr,asid);
+}
+
+bool
+MissQueue::findWrites(Addr addr, int asid, vector<MSHR*> &writes) const
+{
+ return wb.findMatches(addr,asid,writes);
+}
+
+void
+MissQueue::doWriteback(Addr addr, int asid,
+ int size, uint8_t *data, bool compressed)
+{
+ // Generate request
+ Request * req = new Request(addr, size, 0);
+ Packet * pkt = new Packet(req, Packet::Writeback, -1);
+ pkt->allocate();
+ if (data) {
+ memcpy(pkt->getPtr<uint8_t>(), data, size);
+ }
+
+ if (compressed) {
+ pkt->flags |= COMPRESSED;
+ }
+
+ ///All writebacks charged to same thread @todo figure this out
+ writebacks[pkt->req->getThreadNum()]++;
+
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+void
+MissQueue::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->req->getThreadNum()]++;
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+MSHR*
+MissQueue::allocateTargetList(Addr addr, int asid)
+{
+ MSHR* mshr = mq.allocateTargetList(addr, asid, blkSize);
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ return mshr;
+}
+
+bool
+MissQueue::havePending()
+{
+ return mq.havePending() || wb.havePending() || prefetcher->havePending();
+}
diff --git a/src/mem/cache/miss/miss_queue.hh b/src/mem/cache/miss/miss_queue.hh
new file mode 100644
index 000000000..b88b7038c
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.hh
@@ -0,0 +1,349 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Miss and writeback queue declarations.
+ */
+
+#ifndef __MISS_QUEUE_HH__
+#define __MISS_QUEUE_HH__
+
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+/**
+ * Manages cache misses and writebacks. Contains MSHRs to store miss data
+ * and the writebuffer for writes/writebacks.
+ * @todo need to handle data on writes better (encapsulate).
+ * @todo need to make replacements/writebacks happen in Cache::access
+ */
+class MissQueue
+{
+ protected:
+ /** The MSHRs. */
+ MSHRQueue mq;
+ /** Write Buffer. */
+ MSHRQueue wb;
+
+ // PARAMTERS
+
+ /** The number of MSHRs in the miss queue. */
+ const int numMSHR;
+ /** The number of targets for each MSHR. */
+ const int numTarget;
+ /** The number of write buffers. */
+ const int writeBuffers;
+ /** True if the cache should allocate on a write miss. */
+ const bool writeAllocate;
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ /** The Prefetcher */
+ BasePrefetcher *prefetcher;
+
+ /** The block size of the parent cache. */
+ int blkSize;
+
+ /** Increasing order number assigned to each incoming request. */
+ uint64_t order;
+
+ bool prefetchMiss;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /** Number of misses that hit in the MSHRs per command and thread. */
+ Stats::Vector<> mshr_hits[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[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[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[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[NUM_MEM_CMDS];
+ /** Total cycle latency of overall MSHR misses. */
+ Stats::Formula overallMshrUncacheableLatency;
+
+ /** The total number of MSHR accesses per command and thread. */
+ Stats::Formula mshrAccesses[NUM_MEM_CMDS];
+ /** The total number of demand MSHR accesses. */
+ Stats::Formula demandMshrAccesses;
+ /** The total number of MSHR accesses. */
+ Stats::Formula overallMshrAccesses;
+
+ /** The miss rate in the MSHRs pre command and thread. */
+ Stats::Formula mshrMissRate[NUM_MEM_CMDS];
+ /** The demand miss rate in the MSHRs. */
+ Stats::Formula demandMshrMissRate;
+ /** The overall miss rate in the MSHRs. */
+ Stats::Formula overallMshrMissRate;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrMissLatency[NUM_MEM_CMDS];
+ /** The average latency of a demand MSHR miss. */
+ Stats::Formula demandAvgMshrMissLatency;
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrMissLatency;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrUncacheableLatency[NUM_MEM_CMDS];
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrUncacheableLatency;
+
+ /** The number of times a thread hit its MSHR cap. */
+ Stats::Vector<> mshr_cap_events;
+ /** The number of times software prefetches caused the MSHR to block. */
+ Stats::Vector<> soft_prefetch_mshr_full;
+
+ Stats::Scalar<> mshr_no_allocate_misses;
+
+ /**
+ * @}
+ */
+
+ private:
+ /** Pointer to the MSHR that has no targets. */
+ MSHR* noTargetMSHR;
+
+ /**
+ * Allocate a new MSHR to handle the provided miss.
+ * @param req The miss to buffer.
+ * @param size The number of bytes to fetch.
+ * @param time The time the miss occurs.
+ * @return A pointer to the new MSHR.
+ */
+ MSHR* allocateMiss(Packet * &pkt, int size, Tick time);
+
+ /**
+ * Allocate a new WriteBuffer to handle the provided write.
+ * @param req The write to handle.
+ * @param size The number of bytes to write.
+ * @param time The time the write occurs.
+ * @return A pointer to the new write buffer.
+ */
+ MSHR* allocateWrite(Packet * &pkt, int size, Tick time);
+
+ public:
+ /**
+ * Simple Constructor. Initializes all needed internal storage and sets
+ * parameters.
+ * @param numMSHRs The number of outstanding misses to handle.
+ * @param numTargets The number of outstanding targets to each miss.
+ * @param write_buffers The number of outstanding writes to handle.
+ * @param write_allocate If true, treat write misses the same as reads.
+ */
+ MissQueue(int numMSHRs, int numTargets, int write_buffers,
+ bool write_allocate, bool prefetch_miss);
+
+ /**
+ * Deletes all allocated internal storage.
+ */
+ ~MissQueue();
+
+ /**
+ * Register statistics for this object.
+ * @param name The name of the parent cache.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Called by the parent cache to set the back pointer.
+ * @param _cache A pointer to the parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ void setPrefetcher(BasePrefetcher *_prefetcher);
+
+ /**
+ * Handle a cache miss properly. Either allocate an MSHR for the request,
+ * or forward it through the write buffer.
+ * @param req The request that missed in the cache.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ */
+ void handleMiss(Packet * &pkt, int blk_size, Tick time);
+
+ /**
+ * Fetch the block for the given address and buffer the given target.
+ * @param addr The address to fetch.
+ * @param asid The address space of the address.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ * @param target The target for the fetch.
+ */
+ MSHR* fetchBlock(Addr addr, int asid, int blk_size, Tick time,
+ Packet * &target);
+
+ /**
+ * Selects a outstanding request to service.
+ * @return The request to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param req The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param req The request to reset.
+ */
+ void restoreOrigCmd(Packet * &pkt);
+
+ /**
+ * Marks a request as in service (sent on the bus). This can have side
+ * effect since storage for no response commands is deallocated once they
+ * are successfully sent.
+ * @param req The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Collect statistics and free resources of a satisfied request.
+ * @param req The request that has been satisfied.
+ * @param time The time when the request is satisfied.
+ */
+ void handleResponse(Packet * &pkt, Tick time);
+
+ /**
+ * Removes all outstanding requests for a given thread number. If a request
+ * has been sent to the bus, this function removes all of its targets.
+ * @param req->getThreadNum()ber The thread number of the requests to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Return the current number of outstanding misses.
+ * @return the number of outstanding misses.
+ */
+ int getMisses()
+ {
+ return mq.getAllocatedTargets();
+ }
+
+ /**
+ * Searches for the supplied address in the miss queue.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @return The MSHR that contains the address, NULL if not found.
+ * @warning Currently only searches the miss queue. If non write allocate
+ * might need to search the write buffer for coherence.
+ */
+ MSHR* findMSHR(Addr addr, int asid) const;
+
+ /**
+ * Searches for the supplied address in the write buffer.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @param writes The list of writes that match the address.
+ * @return True if any writes are found
+ */
+ bool findWrites(Addr addr, int asid, std::vector<MSHR*>& writes) const;
+
+ /**
+ * Perform a writeback of dirty data to the given address.
+ * @param addr The address to write to.
+ * @param asid The address space id.
+ * @param xc The execution context of the address space.
+ * @param size The number of bytes to write.
+ * @param data The data to write, can be NULL.
+ * @param compressed True if the data is compressed.
+ */
+ void doWriteback(Addr addr, int asid,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform the given writeback request.
+ * @param req The writeback request.
+ */
+ void doWriteback(Packet * &pkt);
+
+ /**
+ * Returns true if there are outstanding requests.
+ * @return True if there are outstanding requests.
+ */
+ bool havePending();
+
+ /**
+ * Add a target to the given MSHR. This assumes it is in the miss queue.
+ * @param mshr The mshr to add a target to.
+ * @param req The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &pkt)
+ {
+ mq.allocateTarget(mshr, pkt);
+ }
+
+ /**
+ * Allocate a MSHR to hold a list of targets to a block involved in a copy.
+ * If the block is marked done then the MSHR already holds the data to
+ * fill the block. Otherwise the block needs to be fetched.
+ * @param addr The address to buffer.
+ * @param asid The address space ID.
+ * @return A pointer to the allocated MSHR.
+ */
+ MSHR* allocateTargetList(Addr addr, int asid);
+
+};
+
+#endif //__MISS_QUEUE_HH__
diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc
new file mode 100644
index 000000000..1a85d3018
--- /dev/null
+++ b/src/mem/cache/miss/mshr.cc
@@ -0,0 +1,181 @@
+/*
+ * 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: Erik Hallnor
+ * Dave Greene
+ */
+
+/**
+ * @file
+ * Miss Status and Handling Register (MSHR) definitions.
+ */
+
+#include <assert.h>
+#include <string>
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "sim/root.hh" // for curTick
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "mem/cache/cache.hh"
+
+using namespace std;
+
+MSHR::MSHR()
+{
+ inService = false;
+ ntargets = 0;
+ threadNum = -1;
+}
+
+void
+MSHR::allocate(Packet::Command cmd, Addr _addr, int _asid, int size,
+ Packet * &target)
+{
+ if (target)
+ {
+ //Have a request, just use it
+ pkt = new Packet(target->req, cmd, Packet::Broadcast, size);
+ pkt->time = curTick;
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState *)this;
+ allocateTarget(target);
+ }
+ else
+ {
+ //need a request first
+ Request * req = new Request();
+ req->setPhys(addr, size, 0);
+ //Thread context??
+ pkt = new Packet(req, cmd, Packet::Broadcast, size);
+ pkt->time = curTick;
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState *)this;
+ }
+}
+
+// Since we aren't sure if data is being used, don't copy here.
+/**
+ * @todo When we have a "global" data flag, might want to copy data here.
+ */
+void
+MSHR::allocateAsBuffer(Packet * &target)
+{
+ addr = target->getAddr();
+ asid = target->req->getAsid();
+ threadNum = target->req->getThreadNum();
+ pkt = new Packet(target->req, target->cmd, -1);
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState*)this;
+ pkt->time = curTick;
+}
+
+void
+MSHR::deallocate()
+{
+ assert(targets.empty());
+ assert(ntargets == 0);
+ pkt = NULL;
+ inService = false;
+ allocIter = NULL;
+ readyIter = NULL;
+}
+
+/*
+ * Adds a target to an MSHR
+ */
+void
+MSHR::allocateTarget(Packet * &target)
+{
+ //If we append an invalidate and we issued a read to the bus,
+ //but now have some pending writes, we need to move
+ //the invalidate to before the first non-read
+ if (inService && pkt->isRead() && target->isInvalidate()) {
+ std::list<Packet *> temp;
+
+ while (!targets.empty()) {
+ if (!targets.front()->isRead()) break;
+ //Place on top of temp stack
+ temp.push_front(targets.front());
+ //Remove from targets
+ targets.pop_front();
+ }
+
+ //Now that we have all the reads off until first non-read, we can
+ //place the invalidate on
+ targets.push_front(target);
+
+ //Now we pop off the temp_stack and put them back
+ while (!temp.empty()) {
+ targets.push_front(temp.front());
+ temp.pop_front();
+ }
+ }
+ else {
+ targets.push_back(target);
+ }
+
+ ++ntargets;
+ assert(targets.size() == ntargets);
+ /**
+ * @todo really prioritize the target commands.
+ */
+
+ if (!inService && target->isWrite()) {
+ pkt->cmd = Packet::WriteReq;
+ }
+}
+
+
+
+void
+MSHR::dump()
+{
+ ccprintf(cerr,
+ "inService: %d thread: %d\n"
+ "Addr: %x asid: %d ntargets %d\n"
+ "Targets:\n",
+ inService, threadNum, addr, asid, ntargets);
+
+ TargetListIterator tar_it = targets.begin();
+ for (int i = 0; i < ntargets; i++) {
+ assert(tar_it != targets.end());
+
+ ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n",
+ i, (*tar_it)->getAddr(), (*tar_it)->cmdToIndex());
+
+ tar_it++;
+ }
+ ccprintf(cerr, "\n");
+}
+
+MSHR::~MSHR()
+{
+ if (pkt)
+ pkt = NULL;
+}
diff --git a/src/mem/cache/miss/mshr.hh b/src/mem/cache/miss/mshr.hh
new file mode 100644
index 000000000..167aa26cd
--- /dev/null
+++ b/src/mem/cache/miss/mshr.hh
@@ -0,0 +1,179 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Miss Status and Handling Register (MSHR) declaration.
+ */
+
+#ifndef __MSHR_HH__
+#define __MSHR_HH__
+
+#include "mem/packet.hh"
+#include <list>
+#include <deque>
+
+class MSHR;
+
+/**
+ * Miss Status and handling Register. This class keeps all the information
+ * needed to handle a cache miss including a list of target requests.
+ */
+class MSHR {
+ public:
+ /** Defines the Data structure of the MSHR targetlist. */
+ typedef std::list<Packet *> TargetList;
+ /** Target list iterator. */
+ typedef std::list<Packet *>::iterator TargetListIterator;
+ /** A list of MSHRs. */
+ typedef std::list<MSHR *> List;
+ /** MSHR list iterator. */
+ typedef List::iterator Iterator;
+ /** MSHR list const_iterator. */
+ typedef List::const_iterator ConstIterator;
+
+ /** Address of the miss. */
+ Addr addr;
+ /** Adress space id of the miss. */
+ short asid;
+ /** True if the request has been sent to the bus. */
+ bool inService;
+ /** Thread number of the miss. */
+ int threadNum;
+ /** The request that is forwarded to the next level of the hierarchy. */
+ Packet * pkt;
+ /** The number of currently allocated targets. */
+ short ntargets;
+ /** The original requesting command. */
+ Packet::Command originalCmd;
+ /** Order number of assigned by the miss queue. */
+ uint64_t order;
+
+ /**
+ * Pointer to this MSHR on the ready list.
+ * @sa MissQueue, MSHRQueue::readyList
+ */
+ Iterator readyIter;
+ /**
+ * Pointer to this MSHR on the allocated list.
+ * @sa MissQueue, MSHRQueue::allocatedList
+ */
+ Iterator allocIter;
+
+private:
+ /** List of all requests that match the address */
+ TargetList targets;
+
+public:
+ /**
+ * Allocate a miss to this MSHR.
+ * @param cmd The requesting command.
+ * @param addr The address of the miss.
+ * @param asid The address space id of the miss.
+ * @param size The number of bytes to request.
+ * @param req The original miss.
+ */
+ void allocate(Packet::Command cmd, Addr addr, int asid, int size,
+ Packet * &pkt);
+
+ /**
+ * Allocate this MSHR as a buffer for the given request.
+ * @param target The memory request to buffer.
+ */
+ void allocateAsBuffer(Packet * &target);
+
+ /**
+ * Mark this MSHR as free.
+ */
+ void deallocate();
+
+ /**
+ * Add a request to the list of targets.
+ * @param target The target.
+ */
+ void allocateTarget(Packet * &target);
+
+ /** A simple constructor. */
+ MSHR();
+ /** A simple destructor. */
+ ~MSHR();
+
+ /**
+ * Returns the current number of allocated targets.
+ * @return The current number of allocated targets.
+ */
+ int getNumTargets()
+ {
+ return(ntargets);
+ }
+
+ /**
+ * Returns a pointer to the target list.
+ * @return a pointer to the target list.
+ */
+ TargetList* getTargetList()
+ {
+ return &targets;
+ }
+
+ /**
+ * Returns a reference to the first target.
+ * @return A pointer to the first target.
+ */
+ Packet * getTarget()
+ {
+ return targets.front();
+ }
+
+ /**
+ * Pop first target.
+ */
+ void popTarget()
+ {
+ --ntargets;
+ targets.pop_front();
+ }
+
+ /**
+ * Returns true if there are targets left.
+ * @return true if there are targets
+ */
+ bool hasTargets()
+ {
+ return !targets.empty();
+ }
+
+ /**
+ * Prints the contents of this MSHR to stderr.
+ */
+ void dump();
+};
+
+#endif //__MSHR_HH__
diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc
new file mode 100644
index 000000000..6516a99f8
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/** @file
+ * Definition of the MSHRQueue.
+ */
+
+#include "mem/cache/miss/mshr_queue.hh"
+#include "sim/eventq.hh"
+
+using namespace std;
+
+MSHRQueue::MSHRQueue(int num_mshrs, int reserve)
+ : numMSHRs(num_mshrs + reserve - 1), numReserve(reserve)
+{
+ allocated = 0;
+ inServiceMSHRs = 0;
+ allocatedTargets = 0;
+ registers = new MSHR[numMSHRs];
+ for (int i = 0; i < numMSHRs; ++i) {
+ freeList.push_back(&registers[i]);
+ }
+}
+
+MSHRQueue::~MSHRQueue()
+{
+ delete [] registers;
+}
+
+MSHR*
+MSHRQueue::findMatch(Addr addr, int asid) const
+{
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ return mshr;
+ }
+ }
+ return NULL;
+}
+
+bool
+MSHRQueue::findMatches(Addr addr, int asid, vector<MSHR*>& matches) const
+{
+ // Need an empty vector
+ assert(matches.empty());
+ bool retval = false;
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ retval = true;
+ matches.push_back(mshr);
+ }
+ }
+ return retval;
+
+}
+
+MSHR*
+MSHRQueue::findPending(Packet * &pkt) const
+{
+ MSHR::ConstIterator i = pendingList.begin();
+ MSHR::ConstIterator end = pendingList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr < pkt->getAddr()) {
+ if (mshr->addr + mshr->pkt->getSize() > pkt->getAddr()) {
+ return mshr;
+ }
+ } else {
+ if (pkt->getAddr() + pkt->getSize() > mshr->addr) {
+ return mshr;
+ }
+ }
+
+ //need to check destination address for copies.
+ //TEMP NOT DOING COPIES
+#if 0
+ if (mshr->pkt->cmd == Copy) {
+ Addr dest = mshr->pkt->dest;
+ if (dest < pkt->addr) {
+ if (dest + mshr->pkt->size > pkt->addr) {
+ return mshr;
+ }
+ } else {
+ if (pkt->addr + pkt->size > dest) {
+ return mshr;
+ }
+ }
+ }
+#endif
+ }
+ return NULL;
+}
+
+MSHR*
+MSHRQueue::allocate(Packet * &pkt, int size)
+{
+ Addr aligned_addr = pkt->getAddr() & ~((Addr)size - 1);
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+
+ if (!pkt->needsResponse()) {
+ mshr->allocateAsBuffer(pkt);
+ } else {
+ assert(size !=0);
+ mshr->allocate(pkt->cmd, aligned_addr, pkt->req->getAsid(), size, pkt);
+ allocatedTargets += 1;
+ }
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateFetch(Addr addr, int asid, int size, Packet * &target)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ mshr->allocate(Packet::ReadReq, addr, asid, size, target);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateTargetList(Addr addr, int asid, int size)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ Packet * dummy;
+ mshr->allocate(Packet::ReadReq, addr, asid, size, dummy);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->inService = true;
+ ++inServiceMSHRs;
+ ++allocated;
+ return mshr;
+}
+
+
+void
+MSHRQueue::deallocate(MSHR* mshr)
+{
+ deallocateOne(mshr);
+}
+
+MSHR::Iterator
+MSHRQueue::deallocateOne(MSHR* mshr)
+{
+ MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
+ freeList.push_front(mshr);
+ allocated--;
+ allocatedTargets -= mshr->getNumTargets();
+ if (mshr->inService) {
+ inServiceMSHRs--;
+ } else {
+ pendingList.erase(mshr->readyIter);
+ }
+ mshr->deallocate();
+ return retval;
+}
+
+void
+MSHRQueue::moveToFront(MSHR *mshr)
+{
+ if (!mshr->inService) {
+ assert(mshr == *(mshr->readyIter));
+ pendingList.erase(mshr->readyIter);
+ mshr->readyIter = pendingList.insert(pendingList.begin(), mshr);
+ }
+}
+
+void
+MSHRQueue::markInService(MSHR* mshr)
+{
+ //assert(mshr == pendingList.front());
+ if (!mshr->pkt->needsResponse()) {
+ assert(mshr->getNumTargets() == 0);
+ deallocate(mshr);
+ return;
+ }
+ mshr->inService = true;
+ pendingList.erase(mshr->readyIter);
+ mshr->readyIter = NULL;
+ inServiceMSHRs += 1;
+ //pendingList.pop_front();
+}
+
+void
+MSHRQueue::markPending(MSHR* mshr, Packet::Command cmd)
+{
+ assert(mshr->readyIter == NULL);
+ mshr->pkt->cmd = cmd;
+ mshr->pkt->flags &= ~SATISFIED;
+ mshr->inService = false;
+ --inServiceMSHRs;
+ /**
+ * @ todo might want to add rerequests to front of pending list for
+ * performance.
+ */
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+}
+
+void
+MSHRQueue::squash(int threadNum)
+{
+ MSHR::Iterator i = allocatedList.begin();
+ MSHR::Iterator end = allocatedList.end();
+ for (; i != end;) {
+ MSHR *mshr = *i;
+ if (mshr->threadNum == threadNum) {
+ while (mshr->hasTargets()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+
+ assert(target->req->getThreadNum() == threadNum);
+ target = NULL;
+ }
+ assert(!mshr->hasTargets());
+ assert(mshr->ntargets==0);
+ if (!mshr->inService) {
+ i = deallocateOne(mshr);
+ } else {
+ //mshr->pkt->flags &= ~CACHE_LINE_FILL;
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+}
diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh
new file mode 100644
index 000000000..a67f1b9a6
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.hh
@@ -0,0 +1,239 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/** @file
+ * Declaration of a structure to manage MSHRs.
+ */
+
+#ifndef __MSHR_QUEUE_HH__
+#define __MSHR_QUEUE_HH__
+
+#include <vector>
+#include "mem/cache/miss/mshr.hh"
+
+/**
+ * A Class for maintaining a list of pending and allocated memory requests.
+ */
+class MSHRQueue {
+ private:
+ /** MSHR storage. */
+ MSHR* registers;
+ /** Holds pointers to all allocated MSHRs. */
+ MSHR::List allocatedList;
+ /** Holds pointers to MSHRs that haven't been sent to the bus. */
+ MSHR::List pendingList;
+ /** Holds non allocated MSHRs. */
+ MSHR::List freeList;
+
+ // Parameters
+ /**
+ * The total number of MSHRs in this queue. This number is set as the
+ * number of MSHRs requested plus (numReserve - 1). This allows for
+ * the same number of effective MSHRs while still maintaining the reserve.
+ */
+ const int numMSHRs;
+
+ /**
+ * The number of MSHRs to hold in reserve. This is needed because copy
+ * operations can allocate upto 4 MSHRs at one time.
+ */
+ const int numReserve;
+
+ public:
+ /** The number of allocated MSHRs. */
+ int allocated;
+ /** The number of MSHRs that have been forwarded to the bus. */
+ int inServiceMSHRs;
+ /** The number of targets waiting for response. */
+ int allocatedTargets;
+
+ /**
+ * Create a queue with a given number of MSHRs.
+ * @param num_mshrs The number of MSHRs in this queue.
+ * @param reserve The minimum number of MSHRs needed to satisfy any access.
+ */
+ MSHRQueue(int num_mshrs, int reserve = 1);
+
+ /** Destructor */
+ ~MSHRQueue();
+
+ /**
+ * Find the first MSHR that matches the provide address and asid.
+ * @param addr The address to find.
+ * @param asid The address space id.
+ * @return Pointer to the matching MSHR, null if not found.
+ */
+ MSHR* findMatch(Addr addr, int asid) const;
+
+ /**
+ * Find and return all the matching MSHRs in the provided vector.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param matches The vector to return pointers to the matching MSHRs.
+ * @return True if any matches are found, false otherwise.
+ * @todo Typedef the vector??
+ */
+ bool findMatches(Addr addr, int asid, std::vector<MSHR*>& matches) const;
+
+ /**
+ * Find any pending requests that overlap the given request.
+ * @param req The request to find.
+ * @return A pointer to the earliest matching MSHR.
+ */
+ MSHR* findPending(Packet * &pkt) const;
+
+ /**
+ * Allocates a new MSHR for the request and size. This places the request
+ * as the first target in the MSHR.
+ * @param req The request to handle.
+ * @param size The number in bytes to fetch from memory.
+ * @return The a pointer to the MSHR allocated.
+ *
+ * @pre There are free MSHRs.
+ */
+ MSHR* allocate(Packet * &pkt, int size = 0);
+
+ /**
+ * Allocate a read request for the given address, and places the given
+ * target on the target list.
+ * @param addr The address to fetch.
+ * @param asid The address space for the fetch.
+ * @param size The number of bytes to request.
+ * @param target The first target for the request.
+ * @return Pointer to the new MSHR.
+ */
+ MSHR* allocateFetch(Addr addr, int asid, int size, Packet * &target);
+
+ /**
+ * Allocate a target list for the given address.
+ * @param addr The address to fetch.
+ * @param asid The address space for the fetch.
+ * @param size The number of bytes to request.
+ * @return Pointer to the new MSHR.
+ */
+ MSHR* allocateTargetList(Addr addr, int asid, int size);
+
+ /**
+ * Removes the given MSHR from the queue. This places the MSHR on the
+ * free list.
+ * @param mshr
+ */
+ void deallocate(MSHR* mshr);
+
+ /**
+ * Allocates a target to the given MSHR. Used to keep track of the number
+ * of outstanding targets.
+ * @param mshr The MSHR to allocate the target to.
+ * @param req The target request.
+ */
+ void allocateTarget(MSHR* mshr, Packet * &pkt)
+ {
+ mshr->allocateTarget(pkt);
+ allocatedTargets += 1;
+ }
+
+ /**
+ * Remove a MSHR from the queue. Returns an iterator into the allocatedList
+ * for faster squash implementation.
+ * @param mshr The MSHR to remove.
+ * @return An iterator to the next entry in the allocatedList.
+ */
+ MSHR::Iterator deallocateOne(MSHR* mshr);
+
+ /**
+ * Moves the MSHR to the front of the pending list if it is not in service.
+ * @param mshr The mshr to move.
+ */
+ void moveToFront(MSHR *mshr);
+
+ /**
+ * Mark the given MSHR as in service. This removes the MSHR from the
+ * pendingList. Deallocates the MSHR if it does not expect a response.
+ * @param mshr The MSHR to mark in service.
+ */
+ void markInService(MSHR* mshr);
+
+ /**
+ * Mark an in service mshr as pending, used to resend a request.
+ * @param mshr The MSHR to resend.
+ * @param cmd The command to resend.
+ */
+ void markPending(MSHR* mshr, Packet::Command cmd);
+
+ /**
+ * Squash outstanding requests with the given thread number. If a request
+ * is in service, just squashes the targets.
+ * @param req->getThreadNum()ber The thread to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Returns true if the pending list is not empty.
+ * @return True if there are outstanding requests.
+ */
+ bool havePending() const
+ {
+ return !pendingList.empty();
+ }
+
+ /**
+ * Returns true if there are no free MSHRs.
+ * @return True if this queue is full.
+ */
+ bool isFull() const
+ {
+ return (allocated > numMSHRs - numReserve);
+ }
+
+ /**
+ * Returns the request at the head of the pendingList.
+ * @return The next request to service.
+ */
+ Packet * getReq() const
+ {
+ if (pendingList.empty()) {
+ return NULL;
+ }
+ MSHR* mshr = pendingList.front();
+ return mshr->pkt;
+ }
+
+ /**
+ * Returns the number of outstanding targets.
+ * @return the number of allocated targets.
+ */
+ int getAllocatedTargets() const
+ {
+ return allocatedTargets;
+ }
+
+};
+
+#endif //__MSHR_QUEUE_HH__
diff --git a/src/mem/cache/prefetch/base_prefetcher.cc b/src/mem/cache/prefetch/base_prefetcher.cc
new file mode 100644
index 000000000..897551989
--- /dev/null
+++ b/src/mem/cache/prefetch/base_prefetcher.cc
@@ -0,0 +1,249 @@
+/*
+ * 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: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Hardware Prefetcher Definition.
+ */
+
+#include "base/trace.hh"
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+#include "mem/request.hh"
+#include <list>
+
+BasePrefetcher::BasePrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData)
+ :size(size), pageStop(pageStop), serialSquash(serialSquash),
+ cacheCheckPush(cacheCheckPush), only_data(onlyData)
+{
+}
+
+void
+BasePrefetcher::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+BasePrefetcher::regStats(const std::string &name)
+{
+ pfIdentified
+ .name(name + ".prefetcher.num_hwpf_identified")
+ .desc("number of hwpf identified")
+ ;
+
+ pfMSHRHit
+ .name(name + ".prefetcher.num_hwpf_already_in_mshr")
+ .desc("number of hwpf that were already in mshr")
+ ;
+
+ pfCacheHit
+ .name(name + ".prefetcher.num_hwpf_already_in_cache")
+ .desc("number of hwpf that were already in the cache")
+ ;
+
+ pfBufferHit
+ .name(name + ".prefetcher.num_hwpf_already_in_prefetcher")
+ .desc("number of hwpf that were already in the prefetch queue")
+ ;
+
+ pfRemovedFull
+ .name(name + ".prefetcher.num_hwpf_evicted")
+ .desc("number of hwpf removed due to no buffer left")
+ ;
+
+ pfRemovedMSHR
+ .name(name + ".prefetcher.num_hwpf_removed_MSHR_hit")
+ .desc("number of hwpf removed because MSHR allocated")
+ ;
+
+ pfIssued
+ .name(name + ".prefetcher.num_hwpf_issued")
+ .desc("number of hwpf issued")
+ ;
+
+ pfSpanPage
+ .name(name + ".prefetcher.num_hwpf_span_page")
+ .desc("number of hwpf spanning a virtual page")
+ ;
+
+ pfSquashed
+ .name(name + ".prefetcher.num_hwpf_squashed_from_miss")
+ .desc("number of hwpf that got squashed due to a miss aborting calculation time")
+ ;
+}
+
+Packet *
+BasePrefetcher::getPacket()
+{
+ DPRINTF(HWPrefetch, "%s:Requesting a hw_pf to issue\n", cache->name());
+
+ if (pf.empty()) {
+ DPRINTF(HWPrefetch, "%s:No HW_PF found\n", cache->name());
+ return NULL;
+ }
+
+ Packet * pkt;
+ bool keepTrying = false;
+ do {
+ pkt = *pf.begin();
+ pf.pop_front();
+ if (!cacheCheckPush) {
+ keepTrying = inCache(pkt);
+ }
+ if (pf.empty()) {
+ cache->clearMasterRequest(Request_PF);
+ if (keepTrying) return NULL; //None left, all were in cache
+ }
+ } while (keepTrying);
+
+ pfIssued++;
+ return pkt;
+}
+
+void
+BasePrefetcher::handleMiss(Packet * &pkt, Tick time)
+{
+ if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && only_data))
+ {
+ //Calculate the blk address
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
+
+ //Check if miss is in pfq, if so remove it
+ std::list<Packet *>::iterator iter = inPrefetch(blkAddr);
+ if (iter != pf.end()) {
+ DPRINTF(HWPrefetch, "%s:Saw a miss to a queued prefetch, removing it\n", cache->name());
+ pfRemovedMSHR++;
+ pf.erase(iter);
+ if (pf.empty())
+ cache->clearMasterRequest(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
+ if (serialSquash) {
+ iter = pf.end();
+ iter--;
+ while (!pf.empty() && ((*iter)->time >= time)) {
+ pfSquashed++;
+ pf.pop_back();
+ iter--;
+ }
+ if (pf.empty())
+ cache->clearMasterRequest(Request_PF);
+ }
+
+
+ std::list<Addr> addresses;
+ 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...
+ pfIdentified++;
+ //create a prefetch memreq
+ Request * prefetchReq = new Request(*addr, blkSize, 0);
+ Packet * prefetch;
+ prefetch = new Packet(prefetchReq, Packet::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 (inCache(prefetch)) {
+ addr++;
+ delay++;
+ continue;
+ }
+ }
+
+ //Check if it is already in the miss_queue
+ if (inMissQueue(prefetch->getAddr(), prefetch->req->getAsid())) {
+ addr++;
+ delay++;
+ continue;
+ }
+
+ //Check if it is already in the pf buffer
+ if (inPrefetch(prefetch->getAddr()) != pf.end()) {
+ pfBufferHit++;
+ addr++;
+ delay++;
+ 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());
+ pfRemovedFull++;
+ pf.pop_front();
+ }
+
+ pf.push_back(prefetch);
+ prefetch->flags |= CACHE_LINE_FILL;
+
+ //Make sure to request the bus, with proper delay
+ cache->setMasterRequest(Request_PF, prefetch->time);
+
+ //Increment through the list
+ addr++;
+ delay++;
+ }
+ }
+}
+
+std::list<Packet *>::iterator
+BasePrefetcher::inPrefetch(Addr address)
+{
+ //Guaranteed to only be one match, we always check before inserting
+ std::list<Packet *>::iterator iter;
+ for (iter=pf.begin(); iter != pf.end(); iter++) {
+ if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) {
+ return iter;
+ }
+ }
+ return pf.end();
+}
+
+
diff --git a/src/mem/cache/prefetch/base_prefetcher.hh b/src/mem/cache/prefetch/base_prefetcher.hh
new file mode 100644
index 000000000..3e4fc89d1
--- /dev/null
+++ b/src/mem/cache/prefetch/base_prefetcher.hh
@@ -0,0 +1,117 @@
+/*
+ * 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: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Miss and writeback queue declarations.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
+
+#include "mem/packet.hh"
+#include <list>
+
+class BaseCache;
+class BasePrefetcher
+{
+ protected:
+
+ /** The Prefetch Queue. */
+ std::list<Packet *> pf;
+
+ // PARAMETERS
+
+ /** The number of MSHRs in the Prefetch Queue. */
+ const int size;
+
+ /** Pointr to the parent cache. */
+ BaseCache* cache;
+
+ /** The block size of the parent cache. */
+ int blkSize;
+
+ /** Do we prefetch across page boundaries. */
+ bool pageStop;
+
+ /** Do we remove prefetches with later times than a new miss.*/
+ bool serialSquash;
+
+ /** Do we check if it is in the cache when inserting into buffer,
+ or removing.*/
+ bool cacheCheckPush;
+
+ /** Do we prefetch on only data reads, or on inst reads as well. */
+ bool only_data;
+
+ 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;
+
+ void regStats(const std::string &name);
+
+ public:
+ BasePrefetcher(int numMSHRS, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData);
+
+ virtual ~BasePrefetcher() {}
+
+ void setCache(BaseCache *_cache);
+
+ void handleMiss(Packet * &pkt, Tick time);
+
+ Packet * getPacket();
+
+ bool havePending()
+ {
+ return !pf.empty();
+ }
+
+ virtual void calculatePrefetch(Packet * &pkt,
+ std::list<Addr> &addresses,
+ std::list<Tick> &delays) = 0;
+
+ virtual bool inCache(Packet * &pkt) = 0;
+
+ virtual bool inMissQueue(Addr address, int asid) = 0;
+
+ std::list<Packet *>::iterator inPrefetch(Addr address);
+};
+
+
+#endif //__MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/ghb_prefetcher.cc b/src/mem/cache/prefetch/ghb_prefetcher.cc
new file mode 100644
index 000000000..247ec6e8b
--- /dev/null
+++ b/src/mem/cache/prefetch/ghb_prefetcher.cc
@@ -0,0 +1,54 @@
+/*
+ * 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: Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * GHB Prefetcher template instantiations.
+ */
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#include "mem/cache/tags/lru.hh"
+
+#include "base/compression/null_compression.hh"
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/prefetch/ghb_prefetcher.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template class GHBPrefetcher<CacheTags<LRU,NullCompression>, MissQueue>;
+template class GHBPrefetcher<CacheTags<LRU,NullCompression>, BlockingBuffer>;
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/prefetch/ghb_prefetcher.hh b/src/mem/cache/prefetch/ghb_prefetcher.hh
new file mode 100644
index 000000000..c22b763d1
--- /dev/null
+++ b/src/mem/cache/prefetch/ghb_prefetcher.hh
@@ -0,0 +1,114 @@
+/*
+ * 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: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a ghb prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class GHBPrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ Addr second_last_miss_addr[64/*MAX_CPUS*/];
+ Addr last_miss_addr[64/*MAX_CPUS*/];
+
+ Tick latency;
+ int degree;
+ bool useCPUId;
+
+ public:
+
+ GHBPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree, bool useCPUId)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree), useCPUId(useCPUId)
+ {
+ }
+
+ ~GHBPrefetcher() {}
+
+ void calculatePrefetch(Packet * &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;
+
+
+ int new_stride = blkAddr - last_miss_addr[cpuID];
+ int old_stride = last_miss_addr[cpuID] -
+ second_last_miss_addr[cpuID];
+
+ second_last_miss_addr[cpuID] = last_miss_addr[cpuID];
+ last_miss_addr[cpuID] = blkAddr;
+
+ 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;
+ return;
+ }
+ else
+ {
+ addresses.push_back(newAddr);
+ delays.push_back(latency);
+ }
+ }
+ }
+ }
+};
+
+#endif // __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/stride_prefetcher.cc b/src/mem/cache/prefetch/stride_prefetcher.cc
new file mode 100644
index 000000000..93a096468
--- /dev/null
+++ b/src/mem/cache/prefetch/stride_prefetcher.cc
@@ -0,0 +1,54 @@
+/*
+ * 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: Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Stride Prefetcher template instantiations.
+ */
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#include "mem/cache/tags/lru.hh"
+
+#include "base/compression/null_compression.hh"
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/prefetch/stride_prefetcher.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template class StridePrefetcher<CacheTags<LRU,NullCompression>, MissQueue>;
+template class StridePrefetcher<CacheTags<LRU,NullCompression>, BlockingBuffer>;
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/prefetch/stride_prefetcher.hh b/src/mem/cache/prefetch/stride_prefetcher.hh
new file mode 100644
index 000000000..4a8ee7de4
--- /dev/null
+++ b/src/mem/cache/prefetch/stride_prefetcher.hh
@@ -0,0 +1,149 @@
+/*
+ * 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: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a strided prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class StridePrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ class strideEntry
+ {
+ public:
+ Addr IAddr;
+ Addr MAddr;
+ int stride;
+ int64_t confidence;
+
+/* bool operator < (strideEntry a,strideEntry b)
+ {
+ if (a.confidence == b.confidence) {
+ return true; //??????
+ }
+ else return a.confidence < b.confidence;
+ }*/
+ };
+ Addr* lastMissAddr[64/*MAX_CPUS*/];
+
+ std::list<strideEntry*> table[64/*MAX_CPUS*/];
+ Tick latency;
+ int degree;
+ bool useCPUId;
+
+
+ public:
+
+ StridePrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree, bool useCPUId)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree), useCPUId(useCPUId)
+ {
+ }
+
+ ~StridePrefetcher() {}
+
+ void calculatePrefetch(Packet * &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
+
+ }
+*/ }
+};
+
+#endif // __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/tagged_prefetcher.hh b/src/mem/cache/prefetch/tagged_prefetcher.hh
new file mode 100644
index 000000000..17f500dd8
--- /dev/null
+++ b/src/mem/cache/prefetch/tagged_prefetcher.hh
@@ -0,0 +1,71 @@
+/*
+ * 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: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a tagged prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class TaggedPrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ Tick latency;
+ int degree;
+
+ public:
+
+ TaggedPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree);
+
+ ~TaggedPrefetcher() {}
+
+ void calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
+ std::list<Tick> &delays);
+};
+
+#endif // __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/tagged_prefetcher_impl.hh b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
index 6c27256a9..db5c94820 100644
--- a/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
+++ b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -47,10 +49,10 @@ TaggedPrefetcher(int size, bool pageStop, bool serialSquash,
template <class TagStore, class Buffering>
void
TaggedPrefetcher<TagStore, Buffering>::
-calculatePrefetch(MemReqPtr &req, std::list<Addr> &addresses,
+calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
std::list<Tick> &delays)
{
- Addr blkAddr = req->paddr & ~(Addr)(this->blkSize-1);
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1);
for (int d=1; d <= degree; d++) {
Addr newAddr = blkAddr + d*(this->blkSize);
diff --git a/src/mem/cache/tags/base_tags.cc b/src/mem/cache/tags/base_tags.cc
new file mode 100644
index 000000000..153737300
--- /dev/null
+++ b/src/mem/cache/tags/base_tags.cc
@@ -0,0 +1,91 @@
+/*
+ * 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: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Definitions of BaseTags.
+ */
+
+#include "mem/cache/tags/base_tags.hh"
+
+#include "mem/cache/base_cache.hh"
+#include "cpu/smt.hh" //maxThreadsPerCPU
+#include "sim/sim_exit.hh"
+
+using namespace std;
+
+void
+BaseTags::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ objName = cache->name();
+}
+
+void
+BaseTags::regStats(const string &name)
+{
+ using namespace Stats;
+ replacements
+ .init(maxThreadsPerCPU)
+ .name(name + ".replacements")
+ .desc("number of replacements")
+ .flags(total)
+ ;
+
+ tagsInUse
+ .name(name + ".tagsinuse")
+ .desc("Cycle average of tags in use")
+ ;
+
+ totalRefs
+ .name(name + ".total_refs")
+ .desc("Total number of references to valid blocks.")
+ ;
+
+ sampledRefs
+ .name(name + ".sampled_refs")
+ .desc("Sample count of references to valid blocks.")
+ ;
+
+ avgRefs
+ .name(name + ".avg_refs")
+ .desc("Average number of references to valid blocks.")
+ ;
+
+ avgRefs = totalRefs/sampledRefs;
+
+ warmupCycle
+ .name(name + ".warmup_cycle")
+ .desc("Cycle when the warmup percentage was hit.")
+ ;
+
+ registerExitCallback(new BaseTagsCallback(this));
+}
diff --git a/src/mem/cache/tags/base_tags.hh b/src/mem/cache/tags/base_tags.hh
new file mode 100644
index 000000000..b7b0c7ef0
--- /dev/null
+++ b/src/mem/cache/tags/base_tags.hh
@@ -0,0 +1,143 @@
+/*
+ * 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: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Declaration of a common base class for cache tagstore objects.
+ */
+
+#ifndef __BASE_TAGS_HH__
+#define __BASE_TAGS_HH__
+
+#include <string>
+#include "base/statistics.hh"
+#include "base/callback.hh"
+
+class BaseCache;
+
+/**
+ * A common base class of Cache tagstore objects.
+ */
+class BaseTags
+{
+ protected:
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+
+ /** Local copy of the parent cache name. Used for DPRINTF. */
+ std::string objName;
+
+ /**
+ * The number of tags that need to be touched to meet the warmup
+ * percentage.
+ */
+ int warmupBound;
+ /** Marked true when the cache is warmed up. */
+ bool warmedUp;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+
+ /** Number of replacements of valid blocks per thread. */
+ Stats::Vector<> replacements;
+ /** Per cycle average of the number of tags that hold valid data. */
+ Stats::Average<> tagsInUse;
+
+ /** The total number of references to a block before it is replaced. */
+ 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;
+
+ /**
+ * Average number of references to a block before is was replaced.
+ * @todo This should change to an average stat once we have them.
+ */
+ Stats::Formula avgRefs;
+
+ /** The cycle that the warmup percentage was hit. */
+ Stats::Scalar<> warmupCycle;
+ /**
+ * @}
+ */
+
+ public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~BaseTags() {}
+
+ /**
+ * Set the parent cache back pointer. Also copies the cache name to
+ * objName.
+ * @param _cache Pointer to parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ /**
+ * Return the parent cache name.
+ * @return the parent cache name.
+ */
+ const std::string &name() const
+ {
+ return objName;
+ }
+
+ /**
+ * Register local statistics.
+ * @param name The name to preceed each statistic name.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Average in the reference count for valid blocks when the simulation
+ * exits.
+ */
+ virtual void cleanupRefs() {}
+};
+
+class BaseTagsCallback : public Callback
+{
+ BaseTags *tags;
+ public:
+ BaseTagsCallback(BaseTags *t) : tags(t) {}
+ virtual void process() { tags->cleanupRefs(); };
+};
+
+#endif //__BASE_TAGS_HH__
diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
new file mode 100644
index 000000000..82d2c410d
--- /dev/null
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -0,0 +1,334 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions a fully associative LRU tagstore.
+ */
+
+#include <sstream>
+
+#include <assert.h>
+
+#include "mem/cache/tags/fa_lru.hh"
+#include "base/intmath.hh"
+#include "base/misc.hh"
+
+using namespace std;
+
+FALRU::FALRU(int _blkSize, int _size, int hit_latency)
+ : blkSize(_blkSize), size(_size),
+ numBlks(size/blkSize), hitLatency(hit_latency)
+{
+ if (!isPowerOf2(blkSize))
+ fatal("cache block size (in bytes) `%d' must be a power of two",
+ blkSize);
+ if (!(hitLatency > 0))
+ fatal("Access latency in cycles must be at least one cycle");
+ if (!isPowerOf2(size))
+ fatal("Cache Size must be power of 2 for now");
+
+ // Track all cache sizes from 128K up by powers of 2
+ numCaches = floorLog2(size) - 17;
+ if (numCaches >0){
+ cacheBoundaries = new FALRUBlk *[numCaches];
+ cacheMask = (1 << numCaches) - 1;
+ } else {
+ cacheMask = 0;
+ }
+
+ warmedUp = false;
+ warmupBound = size/blkSize;
+
+ blks = new FALRUBlk[numBlks];
+ head = &(blks[0]);
+ tail = &(blks[numBlks-1]);
+
+ head->prev = NULL;
+ head->next = &(blks[1]);
+ head->inCache = cacheMask;
+
+ tail->prev = &(blks[numBlks-2]);
+ tail->next = NULL;
+ tail->inCache = 0;
+
+ int index = (1 << 17) / blkSize;
+ int j = 0;
+ int flags = cacheMask;
+ for (int i = 1; i < numBlks-1; i++) {
+ blks[i].inCache = flags;
+ if (i == index - 1){
+ cacheBoundaries[j] = &(blks[i]);
+ flags &= ~ (1<<j);
+ ++j;
+ index = index << 1;
+ }
+ blks[i].prev = &(blks[i-1]);
+ blks[i].next = &(blks[i+1]);
+ blks[i].isTouched = false;
+ }
+ assert(j == numCaches);
+ assert(index == numBlks);
+ //assert(check());
+}
+
+void
+FALRU::regStats(const string &name)
+{
+ using namespace Stats;
+ BaseTags::regStats(name);
+ hits
+ .init(numCaches+1)
+ .name(name + ".falru_hits")
+ .desc("The number of hits in each cache size.")
+ ;
+ misses
+ .init(numCaches+1)
+ .name(name + ".falru_misses")
+ .desc("The number of misses in each cache size.")
+ ;
+ accesses
+ .name(name + ".falru_accesses")
+ .desc("The number of accesses to the FA LRU cache.")
+ ;
+
+ for (int i = 0; i < numCaches+1; ++i) {
+ stringstream size_str;
+ if (i < 3){
+ size_str << (1<<(i+7)) <<"K";
+ } else {
+ size_str << (1<<(i-3)) <<"M";
+ }
+
+ hits.subname(i, size_str.str());
+ hits.subdesc(i, "Hits in a " + size_str.str() +" cache");
+ misses.subname(i, size_str.str());
+ misses.subdesc(i, "Misses in a " + size_str.str() +" cache");
+ }
+}
+
+FALRUBlk *
+FALRU::hashLookup(Addr addr) const
+{
+ tagIterator iter = tagHash.find(addr);
+ if (iter != tagHash.end()) {
+ return (*iter).second;
+ }
+ return NULL;
+}
+
+bool
+FALRU::probe(int asid, Addr addr) const
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+ return blk && blk->tag == blkAddr && blk->isValid();
+}
+
+void
+FALRU::invalidateBlk(int asid, Addr addr)
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = (*tagHash.find(blkAddr)).second;
+ if (blk) {
+ assert(blk->tag == blkAddr);
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+FALRUBlk*
+FALRU::findBlock(Addr addr, int asid, int &lat, int *inCache)
+{
+ accesses++;
+ int tmp_in_cache = 0;
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ tmp_in_cache = blk->inCache;
+ for (int i = 0; i < numCaches; i++) {
+ if (1<<i & blk->inCache) {
+ hits[i]++;
+ } else {
+ misses[i]++;
+ }
+ }
+ hits[numCaches]++;
+ if (blk != head){
+ moveToHead(blk);
+ }
+ } else {
+ blk = NULL;
+ for (int i = 0; i < numCaches+1; ++i) {
+ misses[i]++;
+ }
+ }
+ if (inCache) {
+ *inCache = tmp_in_cache;
+ }
+
+ lat = hitLatency;
+ //assert(check());
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findBlock(Packet * &pkt, int &lat, int *inCache)
+{
+ Addr addr = pkt->getAddr();
+
+ accesses++;
+ int tmp_in_cache = 0;
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ tmp_in_cache = blk->inCache;
+ for (int i = 0; i < numCaches; i++) {
+ if (1<<i & blk->inCache) {
+ hits[i]++;
+ } else {
+ misses[i]++;
+ }
+ }
+ hits[numCaches]++;
+ if (blk != head){
+ moveToHead(blk);
+ }
+ } else {
+ blk = NULL;
+ for (int i = 0; i < numCaches+1; ++i) {
+ misses[i]++;
+ }
+ }
+ if (inCache) {
+ *inCache = tmp_in_cache;
+ }
+
+ lat = hitLatency;
+ //assert(check());
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findBlock(Addr addr, int asid) const
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ } else {
+ blk = NULL;
+ }
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ FALRUBlk * blk = tail;
+ assert(blk->inCache == 0);
+ moveToHead(blk);
+ tagHash.erase(blk->tag);
+ tagHash[blkAlign(pkt->getAddr())] = blk;
+ if (blk->isValid()) {
+ replacements[0]++;
+ } else {
+ tagsInUse++;
+ blk->isTouched = true;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+ }
+ //assert(check());
+ return blk;
+}
+
+void
+FALRU::moveToHead(FALRUBlk *blk)
+{
+ int updateMask = blk->inCache ^ cacheMask;
+ for (int i = 0; i < numCaches; i++){
+ if ((1<<i) & updateMask) {
+ cacheBoundaries[i]->inCache &= ~(1<<i);
+ cacheBoundaries[i] = cacheBoundaries[i]->prev;
+ } else if (cacheBoundaries[i] == blk) {
+ cacheBoundaries[i] = blk->prev;
+ }
+ }
+ blk->inCache = cacheMask;
+ if (blk != head) {
+ if (blk == tail){
+ assert(blk->next == NULL);
+ tail = blk->prev;
+ tail->next = NULL;
+ } else {
+ blk->prev->next = blk->next;
+ blk->next->prev = blk->prev;
+ }
+ blk->next = head;
+ blk->prev = NULL;
+ head->prev = blk;
+ head = blk;
+ }
+}
+
+bool
+FALRU::check()
+{
+ FALRUBlk* blk = head;
+ int size = 0;
+ int boundary = 1<<17;
+ int j = 0;
+ int flags = cacheMask;
+ while (blk) {
+ size += blkSize;
+ if (blk->inCache != flags) {
+ return false;
+ }
+ if (size == boundary && blk != tail) {
+ if (cacheBoundaries[j] != blk) {
+ return false;
+ }
+ flags &=~(1 << j);
+ boundary = boundary<<1;
+ ++j;
+ }
+ blk = blk->next;
+ }
+ return true;
+}
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
new file mode 100644
index 000000000..566e36c27
--- /dev/null
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -0,0 +1,346 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a fully associative LRU tag store.
+ */
+
+#ifndef __FA_LRU_HH__
+#define __FA_LRU_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh"
+#include "mem/packet.hh"
+#include "base/hashmap.hh"
+#include "mem/cache/tags/base_tags.hh"
+
+/**
+ * A fully associative cache block.
+ */
+class FALRUBlk : public CacheBlk
+{
+public:
+ /** The previous block in LRU order. */
+ FALRUBlk *prev;
+ /** The next block in LRU order. */
+ FALRUBlk *next;
+ /** Has this block been touched? */
+ bool isTouched;
+
+ /**
+ * A bit mask of the sizes of cache that this block is resident in.
+ * Each bit represents a power of 2 in MB size cache.
+ * If bit 0 is set, this block is in a 1MB cache
+ * If bit 2 is set, this block is in a 4MB cache, etc.
+ * There is one bit for each cache smaller than the full size (default
+ * 16MB).
+ */
+ int inCache;
+};
+
+/**
+ * A fully associative LRU cache. Keeps statistics for accesses to a number of
+ * cache sizes at once.
+ */
+class FALRU : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this class. */
+ typedef FALRUBlk BlkType;
+ /** Typedef a list of pointers to the local block type. */
+ typedef std::list<FALRUBlk*> BlkList;
+ protected:
+ /** The block size of the cache. */
+ const int blkSize;
+ /** The size of the cache. */
+ const int size;
+ /** The number of blocks in the cache. */
+ const int numBlks; // calculated internally
+ /** The hit latency of the cache. */
+ const int hitLatency;
+
+ /** Array of pointers to blocks at the cache size boundaries. */
+ FALRUBlk **cacheBoundaries;
+ /** A mask for the FALRUBlk::inCache bits. */
+ int cacheMask;
+ /** The number of different size caches being tracked. */
+ int numCaches;
+
+ /** The cache blocks. */
+ FALRUBlk *blks;
+
+ /** The MRU block. */
+ FALRUBlk *head;
+ /** The LRU block. */
+ FALRUBlk *tail;
+
+ /** Hash table type mapping addresses to cache block pointers. */
+ typedef m5::hash_map<Addr, FALRUBlk *, m5::hash<Addr> > hash_t;
+ /** Iterator into the address hash table. */
+ typedef hash_t::const_iterator tagIterator;
+
+ /** The address hash table. */
+ hash_t tagHash;
+
+ /**
+ * Find the cache block for the given address.
+ * @param addr The address to find.
+ * @return The cache block of the address, if any.
+ */
+ FALRUBlk * hashLookup(Addr addr) const;
+
+ /**
+ * Move a cache block to the MRU position.
+ * @param blk The block to promote.
+ */
+ void moveToHead(FALRUBlk *blk);
+
+ /**
+ * Check to make sure all the cache boundaries are still where they should
+ * be. Used for debugging.
+ * @return True if everything is correct.
+ */
+ bool check();
+
+ /**
+ * @defgroup FALRUStats Fully Associative LRU specific statistics
+ * The FA lru stack lets us track multiple cache sizes at once. These
+ * statistics track the hits and misses for different cache sizes.
+ * @{
+ */
+
+ /** Hits in each cache size >= 128K. */
+ Stats::Vector<> hits;
+ /** Misses in each cache size >= 128K. */
+ Stats::Vector<> misses;
+ /** Total number of accesses. */
+ Stats::Scalar<> accesses;
+
+ /**
+ * @}
+ */
+
+public:
+ /**
+ * Construct and initialize this cache tagstore.
+ * @param blkSize The block size of the cache.
+ * @param size The size of the cache.
+ * @param hit_latency The hit latency of the cache.
+ */
+ FALRU(int blkSize, int size, int hit_latency);
+
+ /**
+ * Register the stats for this object.
+ * @param name The name to prepend to the stats name.
+ */
+ 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(int asid, Addr addr) const;
+
+ /**
+ * Invalidate the cache block that contains the given addr.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * Find the block in the cache and update the replacement data. Returns
+ * the access latency and the in cache 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 asid, int &lat, int *inCache = 0);
+
+ /**
+ * Find the block in the cache and update the replacement data. Returns
+ * the access latency and the in cache flags as a side effect
+ * @param req The req whose block to find
+ * @param lat The latency of the access.
+ * @param inCache The FALRUBlk::inCache flags.
+ * @return Pointer to the cache block.
+ */
+ FALRUBlk* findBlock(Packet * &pkt, int &lat, int *inCache = 0);
+
+ /**
+ * Find the block in the cache, do not update the replacement data.
+ * @param addr The address to look for.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block.
+ */
+ FALRUBlk* findBlock(Addr addr, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ FALRUBlk* findReplacement(Packet * &pkt, PacketList & writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Return the hit latency of this cache.
+ * @return The hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Return the block size of this cache.
+ * @return The block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size of this cache, always the block size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The aligned address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)(blkSize-1));
+ }
+
+ /**
+ * Generate the tag from the addres. For fully associative this is just the
+ * block address.
+ * @param addr The address to get the tag from.
+ * @param blk ignored here
+ * @return The tag.
+ */
+ Addr extractTag(Addr addr, FALRUBlk *blk) const
+ {
+ return blkAlign(addr);
+ }
+
+ /**
+ * Return the set of an address. Only one set in a fully associative cache.
+ * @param addr The address to get the set from.
+ * @return 0.
+ */
+ int extractSet(Addr addr) const
+ {
+ return 0;
+ }
+
+ /**
+ * Calculate the block offset of an address.
+ * @param addr the address to get the offset of.
+ * @return the block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & (Addr)(blkSize-1));
+ }
+
+ /**
+ * Regenerate the block address from the tag and the set.
+ * @param tag The tag of the block.
+ * @param set The set the block belongs to.
+ * @return the block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, int set) const
+ {
+ 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)
+ {
+ }
+
+ /**
+ * Unimplemented. Perform a cache block copy from block aligned addresses.
+ * @param source The block aligned source address.
+ * @param dest The block aligned destination adddress.
+ * @param asid The address space ID.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Unimplemented.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+};
+
+#endif
diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc
new file mode 100644
index 000000000..847fabc88
--- /dev/null
+++ b/src/mem/cache/tags/iic.cc
@@ -0,0 +1,880 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of the Indirect Index Cache tagstore.
+ */
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/tags/iic.hh"
+#include "base/intmath.hh"
+#include "sim/root.hh" // for curTick
+
+#include "base/trace.hh" // for DPRINTF
+
+
+using namespace std;
+
+/** Track the number of accesses to each cache set. */
+#define PROFILE_IIC 1
+
+IIC::IIC(IIC::Params &params) :
+ hashSets(params.numSets), blkSize(params.blkSize), assoc(params.assoc),
+ hitLatency(params.hitLatency), subSize(params.subblockSize),
+ numSub(blkSize/subSize),
+ trivialSize((floorLog2(params.size/subSize)*numSub)/8),
+ tagShift(floorLog2(blkSize)), blkMask(blkSize - 1),
+ subShift(floorLog2(subSize)), subMask(numSub - 1),
+ hashDelay(params.hashDelay),
+ numBlocks(params.size/subSize),
+ numTags(hashSets * assoc + params.size/blkSize -1),
+ numSecondary(params.size/blkSize),
+ tagNull(numTags),
+ primaryBound(hashSets * assoc)
+{
+ int i;
+
+ // Check parameters
+ if (blkSize < 4 || !isPowerOf2(blkSize)) {
+ fatal("Block size must be at least 4 and a power of 2");
+ }
+ if (hashSets <= 0 || !isPowerOf2(hashSets)) {
+ fatal("# of hashsets 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");
+ }
+ if (numSub*subSize != blkSize) {
+ fatal("blocksize must be evenly divisible by subblock size");
+ }
+
+ // debug stuff
+ freeSecond = numSecondary;
+
+ warmedUp = false;
+ warmupBound = params.size/blkSize;
+
+ // Replacement Policy Initialization
+ repl = params.rp;
+ repl->setIIC(this);
+
+ //last_miss_time = 0
+
+ // allocate data reference counters
+ dataReferenceCount = new int[numBlocks];
+ memset(dataReferenceCount, 0, numBlocks*sizeof(int));
+
+ // Allocate storage for both internal data and block fast access data.
+ // We allocate it as one large chunk to reduce overhead and to make
+ // deletion easier.
+ int data_index = 0;
+ dataStore = new uint8_t[(numBlocks + numTags) * blkSize];
+ dataBlks = new uint8_t*[numBlocks];
+ for (i = 0; i < numBlocks; ++i) {
+ dataBlks[i] = &dataStore[data_index];
+ freeDataBlock(i);
+ data_index += subSize;
+ }
+
+ assert(data_index == numBlocks * subSize);
+
+ // allocate and init tag store
+ tagStore = new IICTag[numTags];
+
+ int blkIndex = 0;
+ // allocate and init sets
+ sets = new IICSet[hashSets];
+ for (i = 0; i < hashSets; ++i) {
+ sets[i].assoc = assoc;
+ sets[i].tags = new IICTag*[assoc];
+ sets[i].chain_ptr = tagNull;
+
+ for (int j = 0; j < assoc; ++j) {
+ IICTag *tag = &tagStore[blkIndex++];
+ tag->chain_ptr = tagNull;
+ tag->data_ptr.resize(numSub);
+ tag->size = blkSize;
+ tag->trivialData = new uint8_t[trivialSize];
+ tag->numData = 0;
+ sets[i].tags[j] = tag;
+ tag->set = i;
+ tag->data = &dataStore[data_index];
+ data_index += blkSize;
+ }
+ }
+
+ assert(blkIndex == primaryBound);
+
+ for (i = primaryBound; i < tagNull; i++) {
+ tagStore[i].chain_ptr = i+1;
+ //setup data ptrs to subblocks
+ tagStore[i].data_ptr.resize(numSub);
+ tagStore[i].size = blkSize;
+ tagStore[i].trivialData = new uint8_t[trivialSize];
+ tagStore[i].numData = 0;
+ tagStore[i].set = 0;
+ tagStore[i].data = &dataStore[data_index];
+ data_index += blkSize;
+ }
+ freelist = primaryBound;
+}
+
+IIC::~IIC()
+{
+ delete [] dataReferenceCount;
+ delete [] dataStore;
+ delete [] tagStore;
+ delete [] sets;
+}
+
+/* register cache stats */
+void
+IIC::regStats(const string &name)
+{
+ using namespace Stats;
+
+ BaseTags::regStats(name);
+
+ hitHashDepth.init(0, 20, 1);
+ missHashDepth.init(0, 20, 1);
+ setAccess.init(0, hashSets, 1);
+
+ /** IIC Statistics */
+ hitHashDepth
+ .name(name + ".hit_hash_depth_dist")
+ .desc("Dist. of Hash lookup depths")
+ .flags(pdf)
+ ;
+
+ missHashDepth
+ .name(name + ".miss_hash_depth_dist")
+ .desc("Dist. of Hash lookup depths")
+ .flags(pdf)
+ ;
+
+ repl->regStats(name);
+
+ if (PROFILE_IIC)
+ setAccess
+ .name(name + ".set_access_dist")
+ .desc("Dist. of Accesses across sets")
+ .flags(pdf)
+ ;
+
+ missDepthTotal
+ .name(name + ".miss_depth_total")
+ .desc("Total of miss depths")
+ ;
+
+ hashMiss
+ .name(name + ".hash_miss")
+ .desc("Total of misses in hash table")
+ ;
+
+ hitDepthTotal
+ .name(name + ".hit_depth_total")
+ .desc("Total of hit depths")
+ ;
+
+ hashHit
+ .name(name + ".hash_hit")
+ .desc("Total of hites in hash table")
+ ;
+}
+
+// probe cache for presence of given block.
+bool
+IIC::probe(int asid, Addr addr) const
+{
+ return (findBlock(addr,asid) != NULL);
+}
+
+IICTag*
+IIC::findBlock(Addr addr, int asid, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+ int set_lat;
+
+ unsigned long chain_ptr;
+
+ if (PROFILE_IIC)
+ setAccess.sample(set);
+
+ IICTag *tag_ptr = sets[set].findTag(asid, tag, chain_ptr);
+ set_lat = 1;
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(asid, tag, chain_ptr, &secondary_depth);
+ set_lat += secondary_depth;
+ // set depth for statistics fix this later!!! egh
+ sets[set].depth = set_lat;
+
+ if (tag_ptr != NULL) {
+ /* need to move tag into primary table */
+ // need to preserve chain: fix this egh
+ sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
+ tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
+ tag_ptr = sets[set].findTag(asid, tag, chain_ptr);
+ assert(tag_ptr!=NULL);
+ }
+
+ }
+ set_lat = set_lat * hashDelay + hitLatency;
+ if (tag_ptr != NULL) {
+ // IIC replacement: if this is not the first element of
+ // list, reorder
+ sets[set].moveToHead(tag_ptr);
+
+ hitHashDepth.sample(sets[set].depth);
+ hashHit++;
+ hitDepthTotal += sets[set].depth;
+ tag_ptr->status |= BlkReferenced;
+ lat = set_lat;
+ if (tag_ptr->whenReady > curTick && tag_ptr->whenReady - curTick > set_lat) {
+ lat = tag_ptr->whenReady - curTick;
+ }
+
+ tag_ptr->refCount += 1;
+ }
+ else {
+ // fall through: cache block not found, not a hit...
+ missHashDepth.sample(sets[set].depth);
+ hashMiss++;
+ missDepthTotal += sets[set].depth;
+ lat = set_lat;
+ }
+ return tag_ptr;
+}
+
+IICTag*
+IIC::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+ int asid = pkt->req->getAsid();
+
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+ int set_lat;
+
+ unsigned long chain_ptr;
+
+ if (PROFILE_IIC)
+ setAccess.sample(set);
+
+ IICTag *tag_ptr = sets[set].findTag(asid, tag, chain_ptr);
+ set_lat = 1;
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(asid, tag, chain_ptr, &secondary_depth);
+ set_lat += secondary_depth;
+ // set depth for statistics fix this later!!! egh
+ sets[set].depth = set_lat;
+
+ if (tag_ptr != NULL) {
+ /* need to move tag into primary table */
+ // need to preserve chain: fix this egh
+ sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
+ tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
+ tag_ptr = sets[set].findTag(asid, tag, chain_ptr);
+ assert(tag_ptr!=NULL);
+ }
+
+ }
+ set_lat = set_lat * hashDelay + hitLatency;
+ if (tag_ptr != NULL) {
+ // IIC replacement: if this is not the first element of
+ // list, reorder
+ sets[set].moveToHead(tag_ptr);
+
+ hitHashDepth.sample(sets[set].depth);
+ hashHit++;
+ hitDepthTotal += sets[set].depth;
+ tag_ptr->status |= BlkReferenced;
+ lat = set_lat;
+ if (tag_ptr->whenReady > curTick && tag_ptr->whenReady - curTick > set_lat) {
+ lat = tag_ptr->whenReady - curTick;
+ }
+
+ tag_ptr->refCount += 1;
+ }
+ else {
+ // fall through: cache block not found, not a hit...
+ missHashDepth.sample(sets[set].depth);
+ hashMiss++;
+ missDepthTotal += sets[set].depth;
+ lat = set_lat;
+ }
+ return tag_ptr;
+}
+
+IICTag*
+IIC::findBlock(Addr addr, int asid) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+
+ unsigned long chain_ptr;
+
+ IICTag *tag_ptr = sets[set].findTag(asid, tag, chain_ptr);
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(asid, tag, chain_ptr, &secondary_depth);
+ }
+ return tag_ptr;
+}
+
+
+IICTag*
+IIC::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ DPRINTF(IIC, "Finding Replacement for %x\n", pkt->getAddr());
+ unsigned set = hash(pkt->getAddr());
+ IICTag *tag_ptr;
+ unsigned long *tmp_data = new unsigned long[numSub];
+
+ // Get a enough subblocks for a full cache line
+ for (int i = 0; i < numSub; ++i){
+ tmp_data[i] = getFreeDataBlock(writebacks);
+ assert(dataReferenceCount[tmp_data[i]]==0);
+ }
+
+ tag_ptr = getFreeTag(set, writebacks);
+
+ tag_ptr->set = set;
+ for (int i=0; i< numSub; ++i) {
+ tag_ptr->data_ptr[i] = tmp_data[i];
+ dataReferenceCount[tag_ptr->data_ptr[i]]++;
+ }
+ tag_ptr->numData = numSub;
+ assert(tag_ptr - tagStore < primaryBound); // make sure it is in primary
+ tag_ptr->chain_ptr = tagNull;
+ sets[set].moveToHead(tag_ptr);
+ delete [] tmp_data;
+
+ list<unsigned long> tag_indexes;
+ repl->doAdvance(tag_indexes);
+ while (!tag_indexes.empty()) {
+ if (!tagStore[tag_indexes.front()].isCompressed()) {
+ compress_blocks.push_back(&tagStore[tag_indexes.front()]);
+ }
+ tag_indexes.pop_front();
+ }
+
+ tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
+
+ return tag_ptr;
+}
+
+void
+IIC::freeReplacementBlock(PacketList & writebacks)
+{
+ IICTag *tag_ptr;
+ unsigned long data_ptr;
+ /* consult replacement policy */
+ tag_ptr = &tagStore[repl->getRepl()];
+ assert(tag_ptr->isValid());
+
+ DPRINTF(Cache, "Replacing %x in IIC: %s\n",
+ regenerateBlkAddr(tag_ptr->tag,0),
+ tag_ptr->isModified() ? "writeback" : "clean");
+ /* write back replaced block data */
+ if (tag_ptr && (tag_ptr->isValid())) {
+ replacements[0]++;
+ totalRefs += tag_ptr->refCount;
+ ++sampledRefs;
+ tag_ptr->refCount = 0;
+
+ if (tag_ptr->isModified()) {
+/* Packet * writeback =
+ buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
+ tag_ptr->req->asid, tag_ptr->xc, blkSize,
+ tag_ptr->data,
+ tag_ptr->size);
+*/
+ Request *writebackReq = new Request(regenerateBlkAddr(tag_ptr->tag, 0),
+ blkSize, 0);
+ Packet *writeback = new Packet(writebackReq, Packet::Writeback, -1);
+ writeback->allocate();
+ memcpy(writeback->getPtr<uint8_t>(), tag_ptr->data, blkSize);
+
+ writebacks.push_back(writeback);
+ }
+ }
+
+ // free the data blocks
+ for (int i = 0; i < tag_ptr->numData; ++i) {
+ data_ptr = tag_ptr->data_ptr[i];
+ assert(dataReferenceCount[data_ptr]>0);
+ if (--dataReferenceCount[data_ptr] == 0) {
+ freeDataBlock(data_ptr);
+ }
+ }
+ freeTag(tag_ptr);
+}
+
+unsigned long
+IIC::getFreeDataBlock(PacketList & writebacks)
+{
+ struct IICTag *tag_ptr;
+ unsigned long data_ptr;
+
+ tag_ptr = NULL;
+ /* find data block */
+ while (blkFreelist.empty()) {
+ freeReplacementBlock(writebacks);
+ }
+
+ data_ptr = blkFreelist.front();
+ blkFreelist.pop_front();
+ DPRINTF(IICMore,"Found free data at %d\n",data_ptr);
+ return data_ptr;
+}
+
+
+
+IICTag*
+IIC::getFreeTag(int set, PacketList & writebacks)
+{
+ unsigned long tag_index;
+ IICTag *tag_ptr;
+ // Add new tag
+ tag_ptr = sets[set].findFree();
+ // if no free in primary, and secondary exists
+ if (!tag_ptr && numSecondary) {
+ // need to spill a tag into secondary storage
+ while (freelist == tagNull) {
+ // get replacements until one is in secondary
+ freeReplacementBlock(writebacks);
+ }
+
+ tag_index = freelist;
+ freelist = tagStore[freelist].chain_ptr;
+ freeSecond--;
+
+ assert(tag_index != tagNull);
+ tagSwap(tag_index, sets[set].tags[assoc-1] - tagStore);
+ tagStore[tag_index].chain_ptr = sets[set].chain_ptr;
+ sets[set].chain_ptr = tag_index;
+
+ tag_ptr = sets[set].tags[assoc-1];
+ }
+ DPRINTF(IICMore,"Found free tag at %d\n",tag_ptr - tagStore);
+ tagsInUse++;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+
+ return tag_ptr;
+}
+
+void
+IIC::freeTag(IICTag *tag_ptr)
+{
+ unsigned long tag_index, tmp_index;
+ // Fix tag_ptr
+ if (tag_ptr) {
+ // we have a tag to clear
+ DPRINTF(IICMore,"Freeing Tag for %x\n",
+ regenerateBlkAddr(tag_ptr->tag,0));
+ tagsInUse--;
+ tag_ptr->status = 0;
+ tag_ptr->numData = 0;
+ tag_ptr->re = NULL;
+ tag_index = tag_ptr - tagStore;
+ if (tag_index >= primaryBound) {
+ // tag_ptr points to secondary store
+ assert(tag_index < tagNull); // remove this?? egh
+ if (tag_ptr->chain_ptr == tagNull) {
+ // need to fix chain list
+ unsigned tmp_set = hash(tag_ptr->tag << tagShift);
+ if (sets[tmp_set].chain_ptr == tag_index) {
+ sets[tmp_set].chain_ptr = tagNull;
+ } else {
+ tmp_index = sets[tmp_set].chain_ptr;
+ while (tmp_index != tagNull
+ && tagStore[tmp_index].chain_ptr != tag_index) {
+ tmp_index = tagStore[tmp_index].chain_ptr;
+ }
+ assert(tmp_index != tagNull);
+ tagStore[tmp_index].chain_ptr = tagNull;
+ }
+ tag_ptr->chain_ptr = freelist;
+ freelist = tag_index;
+ freeSecond++;
+ } else {
+ // copy next chained entry to this tag location
+ tmp_index = tag_ptr->chain_ptr;
+ tagSwap(tmp_index, tag_index);
+ tagStore[tmp_index].chain_ptr = freelist;
+ freelist = tmp_index;
+ freeSecond++;
+ }
+ } else {
+ // tag_ptr in primary hash table
+ assert(tag_index < primaryBound);
+ tag_ptr->status = 0;
+ unsigned tmp_set = hash(tag_ptr->tag << tagShift);
+ if (sets[tmp_set].chain_ptr != tagNull) { // collapse chain
+ tmp_index = sets[tmp_set].chain_ptr;
+ tagSwap(tag_index, tmp_index);
+ tagStore[tmp_index].chain_ptr = freelist;
+ freelist = tmp_index;
+ freeSecond++;
+ sets[tmp_set].chain_ptr = tag_ptr->chain_ptr;
+ sets[tmp_set].moveToTail(tag_ptr);
+ }
+ }
+ }
+}
+
+void
+IIC::freeDataBlock(unsigned long data_ptr)
+{
+ assert(dataReferenceCount[data_ptr] == 0);
+ DPRINTF(IICMore, "Freeing data at %d\n", data_ptr);
+ blkFreelist.push_front(data_ptr);
+}
+
+/** Use a simple modulo hash. */
+#define SIMPLE_HASH 0
+
+unsigned
+IIC::hash(Addr addr) const {
+#if SIMPLE_HASH
+ return extractTag(addr) % iic_hash_size;
+#else
+ Addr tag, mask, x, y;
+ tag = extractTag(addr);
+ mask = hashSets-1; /* assumes iic_hash_size is a power of 2 */
+ x = tag & mask;
+ y = (tag >> (int)(::log(hashSets)/::log(2))) & mask;
+ assert (x < hashSets && y < hashSets);
+ return x ^ y;
+#endif
+}
+
+
+void
+IICSet::moveToHead(IICTag *tag)
+{
+ if (tags[0] == tag)
+ 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;
+ IICTag *next = tag;
+
+ do {
+ assert(i < assoc);
+ // swap blks[i] and next
+ IICTag *tmp = tags[i];
+ tags[i] = next;
+ next = tmp;
+ ++i;
+ } while (next != tag);
+}
+
+void
+IICSet::moveToTail(IICTag *tag)
+{
+ if (tags[assoc-1] == tag)
+ 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 = assoc - 1;
+ IICTag *next = tag;
+
+ do {
+ assert(i >= 0);
+ // swap blks[i] and next
+ IICTag *tmp = tags[i];
+ tags[i] = next;
+ next = tmp;
+ --i;
+ } while (next != tag);
+}
+
+void
+IIC::tagSwap(unsigned long index1, unsigned long index2)
+{
+ DPRINTF(IIC,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1,
+ tagStore[index1].tag<<tagShift, index2,
+ tagStore[index2].tag<<tagShift);
+ IICTag tmp_tag;
+ tmp_tag = tagStore[index1];
+ tagStore[index1] = tagStore[index2];
+ tagStore[index2] = tmp_tag;
+ if (tagStore[index1].isValid())
+ repl->fixTag(tagStore[index1].re, index2, index1);
+ if (tagStore[index2].isValid())
+ repl->fixTag(tagStore[index2].re, index1, index2);
+}
+
+
+IICTag *
+IIC::secondaryChain(int asid, Addr tag, unsigned long chain_ptr,
+ int *_depth) const
+{
+ int depth = 0;
+ while (chain_ptr != tagNull) {
+ DPRINTF(IIC,"Searching secondary at %d for %x\n", chain_ptr,
+ tag<<tagShift);
+ if (tagStore[chain_ptr].tag == tag &&
+ tagStore[chain_ptr].asid == asid &&
+ (tagStore[chain_ptr].isValid())) {
+ *_depth = depth;
+ return &tagStore[chain_ptr];
+ }
+ depth++;
+ chain_ptr = tagStore[chain_ptr].chain_ptr;
+ }
+ *_depth = depth;
+ return NULL;
+}
+
+void
+IIC::decompressBlock(unsigned long index)
+{
+ IICTag *tag_ptr = &tagStore[index];
+ if (tag_ptr->isCompressed()) {
+ // decompress the data here.
+ }
+}
+
+void
+IIC::compressBlock(unsigned long index)
+{
+ IICTag *tag_ptr = &tagStore[index];
+ if (!tag_ptr->isCompressed()) {
+ // Compress the data here.
+ }
+}
+
+void
+IIC::invalidateBlk(int asid, Addr addr)
+{
+ IICTag* tag_ptr = findBlock(addr, asid);
+ if (tag_ptr) {
+ for (int i = 0; i < tag_ptr->numData; ++i) {
+ dataReferenceCount[tag_ptr->data_ptr[i]]--;
+ if (dataReferenceCount[tag_ptr->data_ptr[i]] == 0) {
+ freeDataBlock(tag_ptr->data_ptr[i]);
+ }
+ }
+ repl->removeEntry(tag_ptr->re);
+ freeTag(tag_ptr);
+ }
+}
+
+void
+IIC::readData(IICTag *blk, uint8_t *data){
+// assert(cache->doData());
+ 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){
+// assert(cache->doData());
+ assert(size < blkSize || !blk->isCompressed());
+ 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
+ /**
+ * @todo
+ * Make this work with copying.
+ */
+ 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);
+ }
+}
+
+
+/**
+ * @todo This code can break if the src is evicted to get a tag for the dest.
+ */
+void
+IIC::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+{
+//Copy unsuported now
+#if 0
+ IICTag *dest_tag = findBlock(dest, asid);
+
+ if (dest_tag) {
+ for (int i = 0; i < dest_tag->numData; ++i) {
+ if (--dataReferenceCount[dest_tag->data_ptr[i]] == 0) {
+ freeDataBlock(dest_tag->data_ptr[i]);
+ }
+ }
+ // Reset replacement entry
+ } else {
+ dest_tag = getFreeTag(hash(dest), writebacks);
+ dest_tag->re = (void*) repl->add(dest_tag - tagStore);
+ dest_tag->set = hash(dest);
+ dest_tag->tag = extractTag(dest);
+ dest_tag->asid = asid;
+ dest_tag->status = BlkValid | BlkWritable;
+ }
+ // Find the source tag here since it might move if we need to find a
+ // tag for the destination.
+ IICTag *src_tag = findBlock(source, asid);
+ assert(src_tag);
+ assert(!cache->doData() || src_tag->size <= trivialSize
+ || src_tag->numData > 0);
+ // point dest to source data and inc counter
+ for (int i = 0; i < src_tag->numData; ++i) {
+ dest_tag->data_ptr[i] = src_tag->data_ptr[i];
+ ++dataReferenceCount[dest_tag->data_ptr[i]];
+ }
+
+ // Maintain fast access data.
+ memcpy(dest_tag->data, src_tag->data, blkSize);
+
+ dest_tag->xc = src_tag->xc;
+ dest_tag->size = src_tag->size;
+ dest_tag->numData = src_tag->numData;
+ if (src_tag->numData == 0) {
+ // Data is stored in the trivial data, just copy it.
+ memcpy(dest_tag->trivialData, src_tag->trivialData, src_tag->size);
+ }
+
+ dest_tag->status |= BlkDirty;
+ if (dest_tag->size < blkSize) {
+ dest_tag->status |= BlkCompressed;
+ } else {
+ dest_tag->status &= ~BlkCompressed;
+ }
+#endif
+}
+
+void
+IIC::fixCopy(Packet * &pkt, PacketList &writebacks)
+{
+#if 0
+ // if reference counter is greater than 1, do copy
+ // else do write
+ Addr blk_addr = blkAlign(pkt->getAddr);
+ IICTag* blk = findBlock(blk_addr, pkt->req->getAsid());
+
+ if (blk->numData > 0 && dataReferenceCount[blk->data_ptr[0]] != 1) {
+ // copy the data
+ // Mark the block as referenced so it doesn't get replaced.
+ blk->status |= BlkReferenced;
+ for (int i = 0; i < blk->numData; ++i){
+ unsigned long new_data = getFreeDataBlock(writebacks);
+ // Need to refresh pointer
+ /**
+ * @todo Remove this refetch once we change IIC to pointer based
+ */
+ blk = findBlock(blk_addr, pkt->req->getAsid());
+ assert(blk);
+ if (cache->doData()) {
+ memcpy(&(dataBlks[new_data][0]),
+ &(dataBlks[blk->data_ptr[i]][0]),
+ subSize);
+ }
+ dataReferenceCount[blk->data_ptr[i]]--;
+ dataReferenceCount[new_data]++;
+ blk->data_ptr[i] = new_data;
+ }
+ }
+#endif
+}
+
+void
+IIC::cleanupRefs()
+{
+ for (int i = 0; i < numTags; ++i) {
+ if (tagStore[i].isValid()) {
+ totalRefs += tagStore[i].refCount;
+ ++sampledRefs;
+ }
+ }
+}
diff --git a/src/mem/cache/tags/iic.hh b/src/mem/cache/tags/iic.hh
new file mode 100644
index 000000000..6628f7e7a
--- /dev/null
+++ b/src/mem/cache/tags/iic.hh
@@ -0,0 +1,574 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of the Indirect Index Cache (IIC) tags store.
+ */
+
+#ifndef __IIC_HH__
+#define __IIC_HH__
+
+#include <list>
+#include <vector>
+
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/tags/repl/repl.hh"
+#include "mem/packet.hh"
+#include "base/statistics.hh"
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache; // Forward declaration
+
+/**
+ * IIC cache blk.
+ */
+class IICTag : public CacheBlk
+{
+ public:
+ /**
+ * Copy the contents of the given IICTag into this one.
+ * @param rhs The tag to copy.
+ * @return const reference to this tag.
+ */
+ const IICTag& operator=(const IICTag& rhs)
+ {
+ CacheBlk::operator=(rhs);
+ chain_ptr = rhs.chain_ptr;
+ re = rhs.re;
+ set = rhs.set;
+ trivialData = rhs.trivialData;
+ numData = rhs.numData;
+ data_ptr.clear();
+ for (int i = 0; i < rhs.numData; ++i) {
+ data_ptr.push_back(rhs.data_ptr[i]);
+ }
+ return *this;
+ }
+
+ /** Hash chain pointer into secondary store. */
+ unsigned long chain_ptr;
+ /** Data array pointers for each subblock. */
+ std::vector<unsigned long> data_ptr;
+ /** Replacement Entry pointer. */
+ void *re;
+ /**
+ * An array to store small compressed data. Conceputally the same size
+ * as the unsused data array pointers.
+ */
+ uint8_t *trivialData;
+ /**
+ * The number of allocated subblocks.
+ */
+ int numData;
+};
+
+/**
+ * A hash set for the IIC primary lookup table.
+ */
+class IICSet{
+ public:
+ /** The associativity of the primary table. */
+ int assoc;
+
+ /** The number of hash chains followed when finding the last block. */
+ int depth;
+ /** The current number of blocks on the chain. */
+ int size;
+
+ /** Tag pointer into the secondary tag storage. */
+ unsigned long chain_ptr;
+
+ /** The LRU list of the primary table. MRU is at 0 index. */
+ IICTag ** tags;
+
+ /**
+ * Find the addr in this set, return the chain pointer to the secondary if
+ * it isn't found.
+ * @param asid The address space ID.
+ * @param tag The address to find.
+ * @param chain_ptr The chain pointer to start the search of the secondary
+ * @return Pointer to the tag, NULL if not found.
+ */
+ IICTag* findTag(int asid, Addr tag, unsigned long &chain_ptr)
+ {
+ depth = 1;
+ for (int i = 0; i < assoc; ++i) {
+ if (tags[i]->tag == tag && tags[i]->isValid()) {
+ return tags[i];
+ }
+ }
+ chain_ptr = this->chain_ptr;
+ return 0;
+ }
+
+ /**
+ * Find an usused tag in this set.
+ * @return Pointer to the unused tag, NULL if none are free.
+ */
+ IICTag* findFree()
+ {
+ for (int i = 0; i < assoc; ++i) {
+ if (!tags[i]->isValid()) {
+ return tags[i];
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Move a tag to the head of the LRU list
+ * @param tag The tag to move.
+ */
+ void moveToHead(IICTag *tag);
+
+ /**
+ * Move a tag to the tail (LRU) of the LRU list
+ * @param tag The tag to move.
+ */
+ void moveToTail(IICTag *tag);
+};
+
+/**
+ * The IIC tag store. This is a hardware-realizable, fully-associative tag
+ * store that uses software replacement, e.g. Gen.
+ */
+class IIC : public BaseTags
+{
+ public:
+ /** Typedef of the block type used in this class. */
+ typedef IICTag BlkType;
+ /** Typedef for list of pointers to the local block type. */
+ typedef std::list<IICTag*> BlkList;
+ protected:
+ /** The number of set in the primary table. */
+ const int hashSets;
+ /** The block size in bytes. */
+ const int blkSize;
+ /** The associativity of the primary table. */
+ const int assoc;
+ /** The base hit latency. */
+ const int hitLatency;
+ /** The subblock size, used for compression. */
+ const int subSize;
+
+ /** The number of subblocks */
+ const int numSub;
+ /** The number of bytes used by data pointers */
+ const int trivialSize;
+
+ /** The amount to shift address to get the tag. */
+ const int tagShift;
+ /** The mask to get block offset bits. */
+ const unsigned blkMask;
+
+ /** The amount to shift to get the subblock number. */
+ const int subShift;
+ /** The mask to get the correct subblock number. */
+ const unsigned subMask;
+
+ /** The latency of a hash lookup. */
+ const int hashDelay;
+ /** The number of data blocks. */
+ const int numBlocks;
+ /** The total number of tags in primary and secondary. */
+ const int numTags;
+ /** The number of tags in the secondary tag store. */
+ const int numSecondary;
+
+ /** The Null tag pointer. */
+ const int tagNull;
+ /** The last tag in the primary table. */
+ const int primaryBound;
+
+ /** All of the tags */
+ IICTag *tagStore;
+ /**
+ * Pointer to the head of the secondary freelist (maintained with chain
+ * pointers.
+ */
+ unsigned long freelist;
+ /**
+ * The data block freelist.
+ */
+ std::list<unsigned long> blkFreelist;
+
+ /** The primary table. */
+ IICSet *sets;
+
+ /** The replacement policy. */
+ Repl *repl;
+
+ /** An array of data reference counters. */
+ int *dataReferenceCount;
+
+ /** The data blocks. */
+ uint8_t *dataStore;
+
+ /** Storage for the fast access data of each cache block. */
+ uint8_t **dataBlks;
+
+ /**
+ * Count of the current number of free secondary tags.
+ * Used for debugging.
+ */
+ int freeSecond;
+
+ // IIC Statistics
+ /**
+ * @addtogroup IICStatistics IIC Statistics
+ * @{
+ */
+
+ /** Hash hit depth of cache hits. */
+ Stats::Distribution<> hitHashDepth;
+ /** Hash depth for cache misses. */
+ Stats::Distribution<> missHashDepth;
+ /** Count of accesses to each hash set. */
+ Stats::Distribution<> setAccess;
+
+ /** The total hash depth for every miss. */
+ Stats::Scalar<> missDepthTotal;
+ /** The total hash depth for all hits. */
+ Stats::Scalar<> hitDepthTotal;
+ /** The number of hash misses. */
+ Stats::Scalar<> hashMiss;
+ /** The number of hash hits. */
+ Stats::Scalar<> hashHit;
+ /** @} */
+
+ public:
+ /**
+ * Collection of parameters for the IIC.
+ */
+ class Params {
+ public:
+ /** The size in bytes of the cache. */
+ int size;
+ /** The number of sets in the primary table. */
+ int numSets;
+ /** The block size in bytes. */
+ int blkSize;
+ /** The associativity of the primary table. */
+ int assoc;
+ /** The number of cycles for each hash lookup. */
+ int hashDelay;
+ /** The number of cycles to read the data. */
+ int hitLatency;
+ /** The replacement policy. */
+ Repl *rp;
+ /** The subblock size in bytes. */
+ int subblockSize;
+ };
+
+ /**
+ * Construct and initialize this tag store.
+ * @param params The IIC parameters.
+ * @todo
+ * Should make a way to have less tags in the primary than blks in the
+ * cache. Also should be able to specify number of secondary blks.
+ */
+ IIC(Params &params);
+
+ /**
+ * Destructor.
+ */
+ virtual ~IIC();
+
+ /**
+ * Register the statistics.
+ * @param name The name to prepend to the statistic descriptions.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set Not needed for the iic.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, int set) {
+ return (((Addr)tag << tagShift));
+ }
+
+ /**
+ * Return the block size.
+ * @return The block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size.
+ * @return The subblock size.
+ */
+ int getSubBlockSize()
+ {
+ return subSize;
+ }
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Generate the tag from the address.
+ * @param addr The address to a get a tag for.
+ * @param blk Ignored here.
+ * @return the tag.
+ */
+ Addr extractTag(Addr addr, IICTag *blk) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Generate the tag from the address.
+ * @param addr The address to a get a tag for.
+ * @return the tag.
+ */
+ Addr extractTag(Addr addr) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Return the set, always 0 for IIC.
+ * @return 0.
+ */
+ int extractSet(Addr addr) const
+ {
+ return 0;
+ }
+
+ /**
+ * Get the block offset of an address.
+ * @param addr The address to get the offset of.
+ * @return the block offset of the address.
+ */
+ 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);
+ }
+
+ /**
+ * 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(int asid, Addr addr) const;
+
+ /**
+ * Swap the position of two tags.
+ * @param index1 The first tag location.
+ * @param index2 The second tag location.
+ */
+ void tagSwap(unsigned long index1, unsigned long index2);
+
+ /**
+ * Clear the reference bit of the tag and return its old value.
+ * @param index The pointer of the tag to manipulate.
+ * @return The previous state of the reference bit.
+ */
+ bool clearRef(unsigned long index)
+ {
+ bool tmp = tagStore[index].isReferenced();
+ tagStore[index].status &= ~BlkReferenced;
+ return tmp;
+ }
+
+ /**
+ * Decompress a block if it is compressed.
+ * @param index The tag store index for the block to uncompress.
+ */
+ void decompressBlock(unsigned long index);
+
+ /**
+ * Try and compress a block if it is not already compressed.
+ * @param index The tag store index for the block to compress.
+ */
+ void compressBlock(unsigned long index);
+
+ /**
+ * Invalidate the block containing the address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * Find the block and update the replacement data. This call also 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 A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Addr addr, int asid, int &lat);
+
+ /**
+ * Find the block and update the replacement data. This call also returns
+ * the access latency as a side effect.
+ * @param req The req whose block to find
+ * @param lat The access latency.
+ * @return A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Find the block, do not update the replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Addr addr, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ IICTag* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * 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);
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks);
+
+ /**
+ * If a block is currently marked copy on write, copy it before writing.
+ * @param req The write request.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks);
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+private:
+ /**
+ * Return the hash of the address.
+ * @param addr The address to hash.
+ * @return the hash of the address.
+ */
+ unsigned hash(Addr addr) const;
+
+ /**
+ * Search for a block in the secondary tag store. Returns the number of
+ * hash lookups as a side effect.
+ * @param asid The address space ID.
+ * @param tag The tag to match.
+ * @param chain_ptr The first entry to search.
+ * @param depth The number of hash lookups made while searching.
+ * @return A pointer to the block if found.
+ */
+ IICTag *secondaryChain(int asid, Addr tag, unsigned long chain_ptr,
+ int *depth) const;
+
+ /**
+ * Free the resources associated with the next replacement block.
+ * @param writebacks A list of any writebacks to perform.
+ */
+ void freeReplacementBlock(PacketList & writebacks);
+
+ /**
+ * Return the pointer to a free data block.
+ * @param writebacks A list of any writebacks to perform.
+ * @return A pointer to a free data block.
+ */
+ unsigned long getFreeDataBlock(PacketList & writebacks);
+
+ /**
+ * Get a free tag in the given hash set.
+ * @param set The hash set to search.
+ * @param writebacks A list of any writebacks to perform.
+ * @return a pointer to a free tag.
+ */
+ IICTag* getFreeTag(int set, PacketList & writebacks);
+
+ /**
+ * Free the resources associated with the given tag.
+ * @param tag_ptr The tag to free.
+ */
+ void freeTag(IICTag *tag_ptr);
+
+ /**
+ * Mark the given data block as being available.
+ * @param data_ptr The data block to free.
+ */
+ void freeDataBlock(unsigned long data_ptr);
+};
+#endif // __IIC_HH__
+
diff --git a/src/mem/cache/tags/lru.cc b/src/mem/cache/tags/lru.cc
new file mode 100644
index 000000000..556025a3a
--- /dev/null
+++ b/src/mem/cache/tags/lru.cc
@@ -0,0 +1,310 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of LRU tag store.
+ */
+
+#include <string>
+
+#include "mem/cache/base_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/lru.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+LRUBlk*
+CacheSet::findBlk(int asid, Addr tag) const
+{
+ for (int i = 0; i < assoc; ++i) {
+ if (blks[i]->tag == tag && blks[i]->isValid()) {
+ return blks[i];
+ }
+ }
+ return 0;
+}
+
+
+void
+CacheSet::moveToHead(LRUBlk *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;
+ LRUBlk *next = blk;
+
+ do {
+ assert(i < assoc);
+ // swap blks[i] and next
+ LRUBlk *tmp = blks[i];
+ blks[i] = next;
+ next = tmp;
+ ++i;
+ } while (next != blk);
+}
+
+
+// create and initialize a LRU/MRU cache structure
+LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
+ numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency)
+{
+ // 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");
+ }
+
+ LRUBlk *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 CacheSet[numSets];
+ blks = new LRUBlk[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 LRUBlk*[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->asid = -1;
+ blk->isTouched = false;
+ blk->size = blkSize;
+ sets[i].blks[j]=blk;
+ blk->set = i;
+ }
+ }
+}
+
+LRU::~LRU()
+{
+ delete [] dataBlks;
+ delete [] blks;
+ delete [] sets;
+}
+
+// probe cache for presence of given block.
+bool
+LRU::probe(int asid, Addr addr) const
+{
+ // return(findBlock(Read, addr, asid) != 0);
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ LRUBlk *blk = sets[myset].findBlk(asid, tag);
+
+ return (blk != NULL); // true if in cache
+}
+
+LRUBlk*
+LRU::findBlock(Addr addr, int asid, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(asid, 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;
+ }
+
+ return blk;
+}
+
+LRUBlk*
+LRU::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+ int asid = 0;//pkt->req->getAsid();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(asid, 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;
+ }
+
+ return blk;
+}
+
+LRUBlk*
+LRU::findBlock(Addr addr, int asid) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(asid, tag);
+ return blk;
+}
+
+LRUBlk*
+LRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+ // grab a replacement candidate
+ LRUBlk *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;
+ }
+ }
+
+ return blk;
+}
+
+void
+LRU::invalidateBlk(int asid, Addr addr)
+{
+ LRUBlk *blk = findBlock(addr, asid);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+void
+LRU::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+{
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ LRUBlk *source_blk = findBlock(source, asid);
+ assert(source_blk);
+ LRUBlk *dest_blk = findBlock(dest, asid);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Request *search = new Request(dest,1,0);
+ Packet * pkt = new Packet(search, Packet::ReadReq, -1);
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+/* pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->req->asid,
+ dest_blk->xc,
+ blkSize,
+ dest_blk->data,
+ dest_blk->size);
+*/
+ Request *writebackReq = new Request(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ blkSize, 0);
+ Packet *writeback = new Packet(writebackReq, Packet::Writeback, -1);
+ writeback->allocate();
+ memcpy(writeback->getPtr<uint8_t>(),dest_blk->data, blkSize);
+ writebacks.push_back(writeback);
+ }
+ dest_blk->tag = extractTag(dest);
+ dest_blk->asid = asid;
+ delete search;
+ delete pkt;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+}
+
+void
+LRU::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/lru.hh b/src/mem/cache/tags/lru.hh
new file mode 100644
index 000000000..437244660
--- /dev/null
+++ b/src/mem/cache/tags/lru.hh
@@ -0,0 +1,327 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a LRU tag store.
+ */
+
+#ifndef __LRU_HH__
+#define __LRU_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh" // base class
+#include "mem/packet.hh" // for inlined functions
+#include <assert.h>
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache;
+
+/**
+ * LRU cache block.
+ */
+class LRUBlk : public CacheBlk {
+ public:
+ /** Has this block been touched? Used to aid calculation of warmup time. */
+ bool isTouched;
+};
+
+/**
+ * An associative set of cache blocks.
+ */
+class CacheSet
+{
+ public:
+ /** The associativity of this set. */
+ int assoc;
+
+ /** Cache blocks in this set, maintained in LRU order 0 = MRU. */
+ LRUBlk **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.
+ */
+ LRUBlk* findBlk(int asid, Addr tag) const;
+
+ /**
+ * Move the given block to the head of the list.
+ * @param blk The block to move.
+ */
+ void moveToHead(LRUBlk *blk);
+};
+
+/**
+ * A LRU cache tag store.
+ */
+class LRU : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this tag store. */
+ typedef LRUBlk BlkType;
+ /** Typedef for a list of pointers to the local block class. */
+ typedef std::list<LRUBlk*> 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;
+
+ /** The cache sets. */
+ CacheSet *sets;
+
+ /** The cache blocks. */
+ LRUBlk *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;
+
+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.
+ */
+ LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency);
+
+ /**
+ * Destructor
+ */
+ virtual ~LRU();
+
+ /**
+ * 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(int asid, Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param req The request whose block to find.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ LRUBlk* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * 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.
+ */
+ LRUBlk* findBlock(Addr addr, int asid, 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.
+ */
+ LRUBlk* findBlock(Addr addr, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ LRUBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, LRUBlk *blk) 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(LRUBlk *blk, uint8_t *data)
+ {
+ 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;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+};
+
+#endif
diff --git a/src/mem/cache/tags/repl/gen.cc b/src/mem/cache/tags/repl/gen.cc
new file mode 100644
index 000000000..ec1c2aaf3
--- /dev/null
+++ b/src/mem/cache/tags/repl/gen.cc
@@ -0,0 +1,277 @@
+/*
+ * 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: Erik Hallnor
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Definitions of the Generational replacement policy.
+ */
+
+#include <string>
+
+#include "base/misc.hh"
+#include "mem/cache/tags/iic.hh"
+#include "mem/cache/tags/repl/gen.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+GenRepl::GenRepl(const string &_name,
+ int _num_pools,
+ int _fresh_res,
+ int _pool_res) // fix this, should be set by cache
+ : Repl(_name)
+{
+ num_pools = _num_pools;
+ fresh_res = _fresh_res;
+ pool_res = _pool_res;
+ num_entries = 0;
+ num_pool_entries = 0;
+ misses = 0;
+ pools = new GenPool[num_pools+1];
+}
+
+GenRepl::~GenRepl()
+{
+ delete [] pools;
+}
+
+unsigned long
+GenRepl::getRepl()
+{
+ unsigned long tmp;
+ GenReplEntry *re;
+ int i;
+ int num_seen = 0;
+ if (!(num_pool_entries>0)) {
+ fatal("No blks available to replace");
+ }
+ num_entries--;
+ num_pool_entries--;
+ for (i = 0; i < num_pools; i++) {
+ while ((re = pools[i].pop())) {
+ num_seen++;
+ // Remove invalidated entries
+ if (!re->valid) {
+ delete re;
+ continue;
+ }
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ }
+ else {
+ tmp = re->tag_ptr;
+ delete re;
+
+ repl_pool.sample(i);
+
+ return tmp;
+ }
+ }
+ }
+ fatal("No replacement found");
+ return 0xffffffff;
+}
+
+unsigned long *
+GenRepl::getNRepl(int n)
+{
+ unsigned long *tmp;
+ GenReplEntry *re;
+ int i;
+ if (!(num_pool_entries>(n-1))) {
+ fatal("Not enough blks available to replace");
+ }
+ num_entries -= n;
+ num_pool_entries -= n;
+ tmp = new unsigned long[n]; /* array of cache_blk pointers */
+ int blk_index = 0;
+ for (i = 0; i < num_pools && blk_index < n; i++) {
+ while (blk_index < n && (re = pools[i].pop())) {
+ // Remove invalidated entries
+ if (!re->valid) {
+ delete re;
+ continue;
+ }
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ }
+ else {
+ tmp[blk_index] = re->tag_ptr;
+ blk_index++;
+ delete re;
+ repl_pool.sample(i);
+ }
+ }
+ }
+ if (blk_index >= n)
+ return tmp;
+ /* search the fresh pool */
+
+ fatal("No N replacements found");
+ return NULL;
+}
+
+void
+GenRepl::doAdvance(std::list<unsigned long> &demoted)
+{
+ int i;
+ int num_seen = 0;
+ GenReplEntry *re;
+ misses++;
+ for (i=0; i<num_pools; i++) {
+ while (misses-pools[i].oldest > pool_res && (re = pools[i].pop())!=NULL) {
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ /** @todo Not really demoted, but use it for now. */
+ demoted.push_back(re->tag_ptr);
+ advance_pool.sample(i);
+ }
+ else {
+ pools[(((i-1)<0)?i:i-1)].push(re, misses);
+ demoted.push_back(re->tag_ptr);
+ demote_pool.sample(i);
+ }
+ }
+ num_seen += pools[i].size;
+ }
+ while (misses-pools[num_pools].oldest > fresh_res
+ && (re = pools[num_pools].pop())!=NULL) {
+ num_pool_entries++;
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[num_pools/2].push(re, misses);
+ /** @todo Not really demoted, but use it for now. */
+ demoted.push_back(re->tag_ptr);
+ advance_pool.sample(num_pools);
+ }
+ else {
+ pools[num_pools/2-1].push(re, misses);
+ demoted.push_back(re->tag_ptr);
+ demote_pool.sample(num_pools);
+ }
+ }
+}
+
+void*
+GenRepl::add(unsigned long tag_index)
+{
+ GenReplEntry *re = new GenReplEntry;
+ re->tag_ptr = tag_index;
+ re->valid = true;
+ pools[num_pools].push(re, misses);
+ num_entries++;
+ return (void*)re;
+}
+
+void
+GenRepl::regStats(const string name)
+{
+ using namespace Stats;
+
+ /** GEN statistics */
+ repl_pool
+ .init(0, 16, 1)
+ .name(name + ".repl_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+
+ advance_pool
+ .init(0, 16, 1)
+ .name(name + ".advance_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+
+ demote_pool
+ .init(0, 16, 1)
+ .name(name + ".demote_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+}
+
+int
+GenRepl::fixTag(void* _re, unsigned long old_index, unsigned long new_index)
+{
+ GenReplEntry *re = (GenReplEntry*)_re;
+ assert(re->valid);
+ if (re->tag_ptr == old_index) {
+ re->tag_ptr = new_index;
+ return 1;
+ }
+ fatal("Repl entry: tag ptrs do not match");
+ return 0;
+}
+
+bool
+GenRepl::findTagPtr(unsigned long index)
+{
+ for (int i = 0; i < num_pools + 1; ++i) {
+ list<GenReplEntry*>::const_iterator iter = pools[i].entries.begin();
+ list<GenReplEntry*>::const_iterator end = pools[i].entries.end();
+ for (; iter != end; ++iter) {
+ if ((*iter)->valid && (*iter)->tag_ptr == index) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(GenRepl)
+
+ Param<int> num_pools;
+ Param<int> fresh_res;
+ Param<int> pool_res;
+
+END_DECLARE_SIM_OBJECT_PARAMS(GenRepl)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(GenRepl)
+
+ INIT_PARAM(num_pools, "capacity in bytes"),
+ INIT_PARAM(fresh_res, "associativity"),
+ INIT_PARAM(pool_res, "block size in bytes")
+
+END_INIT_SIM_OBJECT_PARAMS(GenRepl)
+
+
+CREATE_SIM_OBJECT(GenRepl)
+{
+ return new GenRepl(getInstanceName(), num_pools, fresh_res, pool_res);
+}
+
+REGISTER_SIM_OBJECT("GenRepl", GenRepl)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/tags/repl/gen.hh b/src/mem/cache/tags/repl/gen.hh
new file mode 100644
index 000000000..c1ceb3f4e
--- /dev/null
+++ b/src/mem/cache/tags/repl/gen.hh
@@ -0,0 +1,247 @@
+/*
+ * 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: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declarations of generational replacement policy
+ */
+
+#ifndef ___GEN_HH__
+#define __GEN_HH__
+
+#include <list>
+
+#include "base/statistics.hh"
+#include "mem/cache/tags/repl/repl.hh"
+
+/**
+ * Generational Replacement entry.
+ */
+class GenReplEntry
+{
+ public:
+ /** Valid flag, used to quickly invalidate bogus entries. */
+ bool valid;
+ /** The difference between this entry and the previous in the pool. */
+ int delta;
+ /** Pointer to the corresponding tag in the IIC. */
+ unsigned long tag_ptr;
+};
+
+/**
+ * Generational replacement pool
+ */
+class GenPool
+{
+ public:
+ /** The time the last entry was added. */
+ Tick newest;
+ /** The time the oldest entry was added. */
+ Tick oldest;
+ /** List of the replacement entries in this pool. */
+ std::list<GenReplEntry*> entries;
+
+ /** The number of entries in this pool. */
+ int size;
+
+ /**
+ * Simple constructor.
+ */
+ GenPool() {
+ newest = 0;
+ oldest = 0;
+ size = 0;
+ }
+
+ /**
+ * Add an entry to this pool.
+ * @param re The entry to add.
+ * @param now The current time.
+ */
+ void push(GenReplEntry *re, Tick now) {
+ ++size;
+ if (!entries.empty()) {
+ re->delta = now - newest;
+ newest = now;
+ } else {
+ re->delta = 0;
+ newest = oldest = now;
+ }
+ entries.push_back(re);
+ }
+
+ /**
+ * Remove an entry from the pool.
+ * @return The entry at the front of the list.
+ */
+ GenReplEntry* pop() {
+ GenReplEntry *tmp = NULL;
+ if (!entries.empty()) {
+ --size;
+ tmp = entries.front();
+ entries.pop_front();
+ oldest += tmp->delta;
+ }
+ return tmp;
+ }
+
+ /**
+ * Return the entry at the front of the list.
+ * @return the entry at the front of the list.
+ */
+ GenReplEntry* top() {
+ return entries.front();
+ }
+
+ /**
+ * Destructor.
+ */
+ ~GenPool() {
+ while (!entries.empty()) {
+ GenReplEntry *tmp = entries.front();
+ entries.pop_front();
+ delete tmp;
+ }
+ }
+};
+
+/**
+ * Generational replacement policy for use with the IIC.
+ * @todo update to use STL and for efficiency
+ */
+class GenRepl : public Repl
+{
+ public:
+ /** The array of pools. */
+ GenPool *pools;
+ /** The number of pools. */
+ int num_pools;
+ /** The amount of time to stay in the fresh pool. */
+ int fresh_res;
+ /** The amount of time to stay in the normal pools. */
+ int pool_res;
+ /** The maximum number of entries */
+ int num_entries;
+ /** The number of entries currently in the pools. */
+ int num_pool_entries;
+ /** The number of misses. Used as the internal time. */
+ Tick misses;
+
+ // Statistics
+
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** The number of replacements from each pool. */
+ Stats::Distribution<> repl_pool;
+ /** The number of advances out of each pool. */
+ Stats::Distribution<> advance_pool;
+ /** The number of demotions from each pool. */
+ Stats::Distribution<> demote_pool;
+ /**
+ * @}
+ */
+
+ /**
+ * Constructs and initializes this replacement policy.
+ * @param name The name of the policy.
+ * @param num_pools The number of pools to use.
+ * @param fresh_res The amount of time to wait in the fresh pool.
+ * @param pool_res The amount of time to wait in the normal pools.
+ */
+ GenRepl(const std::string &name, int num_pools,
+ int fresh_res, int pool_res);
+
+ /**
+ * Destructor.
+ */
+ ~GenRepl();
+
+ /**
+ * Returns the tag pointer of the cache block to replace.
+ * @return The tag to replace.
+ */
+ virtual unsigned long getRepl();
+
+ /**
+ * Return an array of N tag pointers to replace.
+ * @param n The number of tag pointer to return.
+ * @return An array of tag pointers to replace.
+ */
+ virtual unsigned long *getNRepl(int n);
+
+ /**
+ * Update replacement data
+ */
+ virtual void doAdvance(std::list<unsigned long> &demoted);
+
+ /**
+ * Add a tag to the replacement policy and return a pointer to the
+ * replacement entry.
+ * @param tag_index The tag to add.
+ * @return The replacement entry.
+ */
+ virtual void* add(unsigned long tag_index);
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to statistic descriptions.
+ */
+ virtual void regStats(const std::string name);
+
+ /**
+ * Update the tag pointer to when the tag moves.
+ * @param re The replacement entry of the tag.
+ * @param old_index The old tag pointer.
+ * @param new_index The new tag pointer.
+ * @return 1 if successful, 0 otherwise.
+ */
+ virtual int fixTag(void *re, unsigned long old_index,
+ unsigned long new_index);
+
+ /**
+ * Remove this entry from the replacement policy.
+ * @param re The replacement entry to remove
+ */
+ virtual void removeEntry(void *re)
+ {
+ ((GenReplEntry*)re)->valid = false;
+ }
+
+ protected:
+ /**
+ * Debug function to verify that there is only one repl entry per tag.
+ * @param index The tag index to check.
+ */
+ bool findTagPtr(unsigned long index);
+};
+
+#endif /* __GEN_HH__ */
diff --git a/src/mem/cache/tags/repl/repl.cc b/src/mem/cache/tags/repl/repl.cc
new file mode 100644
index 000000000..ce781eb9f
--- /dev/null
+++ b/src/mem/cache/tags/repl/repl.cc
@@ -0,0 +1,43 @@
+/*
+ * 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: Erik Hallnor
+ * Nathan Binkert
+ */
+
+/**
+ * Definitions of the base replacement class.
+ */
+
+#include "sim/param.hh"
+#include "mem/cache/tags/repl/repl.hh"
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+DEFINE_SIM_OBJECT_CLASS_NAME("Repl", Repl)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/tags/repl/repl.hh b/src/mem/cache/tags/repl/repl.hh
new file mode 100644
index 000000000..7c289a5c1
--- /dev/null
+++ b/src/mem/cache/tags/repl/repl.hh
@@ -0,0 +1,129 @@
+/*
+ * 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: Erik Hallnor
+ * Steve Reinhardt
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Declaration of a base replacement policy class.
+ */
+
+#ifndef __REPL_HH__
+#define __REPL_HH__
+
+#include <string>
+#include <list>
+
+#include "cpu/smt.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+
+class IIC;
+
+/**
+ * A pure virtual base class that defines the interface of a replacement
+ * policy.
+ */
+class Repl : public SimObject
+{
+ public:
+ /** Pointer to the IIC using this policy. */
+ IIC *iic;
+
+ /**
+ * Construct and initialize this polixy.
+ * @param name The instance name of this policy.
+ */
+ Repl (const std::string &name)
+ : SimObject(name)
+ {
+ iic = NULL;
+ }
+
+ /**
+ * Set the back pointer to the IIC.
+ * @param iic_ptr Pointer to the IIC.
+ */
+ void setIIC(IIC *iic_ptr)
+ {
+ iic = iic_ptr;
+ }
+
+ /**
+ * Returns the tag pointer of the cache block to replace.
+ * @return The tag to replace.
+ */
+ virtual unsigned long getRepl() = 0;
+
+ /**
+ * Return an array of N tag pointers to replace.
+ * @param n The number of tag pointer to return.
+ * @return An array of tag pointers to replace.
+ */
+ virtual unsigned long *getNRepl(int n) = 0;
+
+ /**
+ * Update replacement data
+ */
+ virtual void doAdvance(std::list<unsigned long> &demoted) = 0;
+
+ /**
+ * Add a tag to the replacement policy and return a pointer to the
+ * replacement entry.
+ * @param tag_index The tag to add.
+ * @return The replacement entry.
+ */
+ virtual void* add(unsigned long tag_index) = 0;
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to statistic descriptions.
+ */
+ virtual void regStats(const std::string name) = 0;
+
+ /**
+ * Update the tag pointer to when the tag moves.
+ * @param re The replacement entry of the tag.
+ * @param old_index The old tag pointer.
+ * @param new_index The new tag pointer.
+ * @return 1 if successful, 0 otherwise.
+ */
+ virtual int fixTag(void *re, unsigned long old_index,
+ unsigned long new_index) = 0;
+
+ /**
+ * Remove this entry from the replacement policy.
+ * @param re The replacement entry to remove
+ */
+ virtual void removeEntry(void *re) = 0;
+};
+
+#endif /* SMT_REPL_HH */
diff --git a/src/mem/cache/tags/split.cc b/src/mem/cache/tags/split.cc
new file mode 100644
index 000000000..bf23fb8cb
--- /dev/null
+++ b/src/mem/cache/tags/split.cc
@@ -0,0 +1,478 @@
+/*
+ * 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_cache.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(int asid, Addr addr) const
+{
+ bool success = lru->probe(asid, addr);
+ if (!success) {
+ if (lifo && lifo_net)
+ success = lifo_net->probe(asid, addr);
+ else if (lru_net)
+ success = lru_net->probe(asid, addr);
+ }
+
+ return success;
+}
+
+SplitBlk*
+Split::findBlock(Packet * &pkt, int &lat)
+{
+
+ Addr aligned = blkAlign(pkt->getAddr());
+
+ if (memHash.count(aligned)) {
+ memHash[aligned]++;
+ } else if (pkt->nic_pkt()) {
+ memHash[aligned] = 1;
+ }
+
+ SplitBlk *blk = lru->findBlock(pkt->getAddr(), pkt->req->getAsid(), lat);
+ if (blk) {
+ if (pkt->nic_pkt()) {
+ NR_CP_hits++;
+ } else {
+ CR_CP_hits++;
+ }
+ } else {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(pkt->getAddr(), pkt->req->getAsid(), lat);
+
+ } else if (lru_net) {
+ blk = lru_net->findBlock(pkt->getAddr(), pkt->req->getAsid(), lat);
+ }
+ if (blk) {
+ if (pkt->nic_pkt()) {
+ NR_NP_hits++;
+ } else {
+ CR_NP_hits++;
+ }
+ }
+ }
+
+ if (blk) {
+ Tick latency = curTick - blk->ts;
+ if (blk->isNIC) {
+ if (!blk->isUsed && !pkt->nic_pkt()) {
+ useByCPUCycleDist.sample(latency);
+ nicUseByCPUCycleTotal += latency;
+ nicBlksUsedByCPU++;
+ }
+ }
+ blk->isUsed = true;
+
+ if (pkt->nic_pkt()) {
+ DPRINTF(Split, "found block in partition %d\n", blk->part);
+ }
+ }
+ return blk;
+}
+
+SplitBlk*
+Split::findBlock(Addr addr, int asid, int &lat)
+{
+ SplitBlk *blk = lru->findBlock(addr, asid, lat);
+ if (!blk) {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(addr, asid, lat);
+ } else if (lru_net) {
+ blk = lru_net->findBlock(addr, asid, lat);
+ }
+ }
+
+ return blk;
+}
+
+SplitBlk*
+Split::findBlock(Addr addr, int asid) const
+{
+ SplitBlk *blk = lru->findBlock(addr, asid);
+ if (!blk) {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(addr, asid);
+ } else if (lru_net) {
+ blk = lru_net->findBlock(addr, asid);
+ }
+ }
+
+ return blk;
+}
+
+SplitBlk*
+Split::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ SplitBlk *blk;
+
+ if (pkt->nic_pkt()) {
+ DPRINTF(Split, "finding a replacement for nic_req\n");
+ nic_repl++;
+ if (lifo && lifo_net)
+ blk = lifo_net->findReplacement(pkt, writebacks,
+ compress_blocks);
+ else if (lru_net)
+ blk = lru_net->findReplacement(pkt, writebacks,
+ compress_blocks);
+ // in this case, this is an LRU only cache, it's non partitioned
+ else
+ blk = lru->findReplacement(pkt, writebacks, compress_blocks);
+ } else {
+ DPRINTF(Split, "finding replacement for cpu_req\n");
+ blk = lru->findReplacement(pkt, writebacks,
+ compress_blocks);
+ 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;
+
+ return blk;
+}
+
+void
+Split::invalidateBlk(int asid, Addr addr)
+{
+ SplitBlk *blk = lru->findBlock(addr, asid);
+ if (!blk) {
+ if (lifo && lifo_net)
+ blk = lifo_net->findBlock(addr, asid);
+ else if (lru_net)
+ blk = lru_net->findBlock(addr, asid);
+
+ if (!blk)
+ return;
+ }
+
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+}
+
+void
+Split::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+{
+ if (lru->probe(asid, source))
+ lru->doCopy(source, dest, asid, writebacks);
+ else {
+ if (lifo && lifo_net)
+ lifo_net->doCopy(source, dest, asid, writebacks);
+ else if (lru_net)
+ lru_net->doCopy(source, dest, asid, writebacks);
+ }
+}
+
+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, SplitBlk *blk) const
+{
+ 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
new file mode 100644
index 000000000..5e0340269
--- /dev/null
+++ b/src/mem/cache/tags/split.hh
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Declaration of a split/partitioned tag store.
+ */
+
+#ifndef __SPLIT_HH__
+#define __SPLIT_HH__
+
+#include <list>
+
+#include "mem/cache/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_tags.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(int asid, Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * 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 asid, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param req The memory request whose block to find
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, 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, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk The block to find the partition it's in
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) 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");
+ }
+
+ /**
+ * 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)
+ {
+ 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;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * 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
new file mode 100644
index 000000000..f38516180
--- /dev/null
+++ b/src/mem/cache/tags/split_blk.hh
@@ -0,0 +1,68 @@
+/*
+ * 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/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
new file mode 100644
index 000000000..f6493fdd2
--- /dev/null
+++ b/src/mem/cache/tags/split_lifo.cc
@@ -0,0 +1,407 @@
+/*
+ * 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_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/split_lifo.hh"
+#include "sim/root.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+SplitBlk*
+LIFOSet::findBlk(int asid, 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(int asid, Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ SplitBlk* blk = sets[myset].findBlk(asid, tag);
+ return (blk != NULL);
+}
+
+SplitBlk*
+SplitLIFO::findBlock(Addr addr, int asid, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, 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(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+ int asid = pkt->req->getAsid();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, tag);
+
+ if (blk) {
+ DPRINTF(Split, "Found LIFO blk %#x in set %d, with tag %#x\n",
+ addr, set, tag);
+ hits++;
+
+ if (twoQueue) {
+ blk->isUsed = true;
+ sets[set].moveToFirstIn(blk);
+ } else {
+ sets[set].moveToLastIn(blk);
+ }
+ }
+ lat = hitLatency;
+
+ return blk;
+}
+
+SplitBlk*
+SplitLIFO::findBlock(Addr addr, int asid) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, tag);
+
+ return blk;
+}
+
+SplitBlk*
+SplitLIFO::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+
+ 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",
+ pkt->getAddr(), 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(int asid, Addr addr)
+{
+ SplitBlk *blk = findBlock(addr, asid);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ invalidations++;
+ }
+}
+
+void
+SplitLIFO::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+{
+//Copy Unsuported for now
+#if 0
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ SplitBlk *source_blk = findBlock(source, asid);
+ assert(source_blk);
+ SplitBlk *dest_blk = findBlock(dest, asid);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Packet * pkt = new Packet();
+ pkt->paddr = dest;
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+ pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->req->asid,
+ dest_blk->xc,
+ blkSize,
+ (cache->doData())?dest_blk->data:0,
+ dest_blk->size);
+ writebacks.push_back(pkt);
+ }
+ dest_blk->tag = extractTag(dest);
+ dest_blk->req->asid = asid;
+ /**
+ * @todo Do we need to pass in the execution context, or can we
+ * assume its the same?
+ */
+ assert(source_blk->xc);
+ dest_blk->xc = source_blk->xc;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ if (cache->doData()) {
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+ }
+#endif
+}
+
+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
new file mode 100644
index 000000000..dfcaa0b67
--- /dev/null
+++ b/src/mem/cache/tags/split_lifo.hh
@@ -0,0 +1,350 @@
+/*
+ * 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 <list>
+
+#include "mem/cache/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_tags.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(int asid, 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(int asid, Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * 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 asid, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param req The req whose block to find
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, 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, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) 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)
+ {
+ 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;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * 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
new file mode 100644
index 000000000..7fc742001
--- /dev/null
+++ b/src/mem/cache/tags/split_lru.cc
@@ -0,0 +1,333 @@
+/*
+ * 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_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/split_lru.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+SplitBlk*
+SplitCacheSet::findBlk(int asid, 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->asid = -1;
+ 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(int asid, Addr addr) const
+{
+ // return(findBlock(Read, addr, asid) != 0);
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ SplitBlk *blk = sets[myset].findBlk(asid, tag);
+
+ return (blk != NULL); // true if in cache
+}
+
+SplitBlk*
+SplitLRU::findBlock(Addr addr, int asid, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, 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(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+ int asid = pkt->req->getAsid();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, 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, int asid) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(asid, tag);
+ return blk;
+}
+
+SplitBlk*
+SplitLRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+ // 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(int asid, Addr addr)
+{
+ SplitBlk *blk = findBlock(addr, asid);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+void
+SplitLRU::doCopy(Addr source, Addr dest, int asid, PacketList &writebacks)
+{
+//Copy not supported for now
+#if 0
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ SplitBlk *source_blk = findBlock(source, asid);
+ assert(source_blk);
+ SplitBlk *dest_blk = findBlock(dest, asid);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Packet * pkt = new Packet();
+ pkt->paddr = dest;
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+ pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->req->asid,
+ dest_blk->xc,
+ blkSize,
+ (cache->doData())?dest_blk->data:0,
+ dest_blk->size);
+ writebacks.push_back(pkt);
+ }
+ dest_blk->tag = extractTag(dest);
+ dest_blk->req->asid = asid;
+ /**
+ * @todo Do we need to pass in the execution context, or can we
+ * assume its the same?
+ */
+ assert(source_blk->xc);
+ dest_blk->xc = source_blk->xc;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ if (cache->doData()) {
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+ }
+#endif
+}
+
+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
new file mode 100644
index 000000000..03886b1d8
--- /dev/null
+++ b/src/mem/cache/tags/split_lru.hh
@@ -0,0 +1,333 @@
+/*
+ * 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 <list>
+
+#include "mem/cache/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_tags.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(int asid, 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(int asid, Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(int asid, Addr addr);
+
+ /**
+ * 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 asid, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param req The req whose block to find.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, 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, int asid) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param req The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * 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);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) 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)
+ {
+ 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;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback requests.
+ */
+ void doCopy(Addr source, Addr dest, int asid, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * 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
new file mode 100644
index 000000000..24da04021
--- /dev/null
+++ b/src/mem/config/cache.hh
@@ -0,0 +1,42 @@
+/*
+ * 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
+ */
+
+/**
+ * @file
+ * Central location to configure which cache types we want to build
+ * into the simulator. In the future, this should probably be
+ * autogenerated by some sort of configuration script.
+ */
+#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/config/prefetch.hh b/src/mem/config/prefetch.hh
index 03eb570f0..d24db79da 100644
--- a/src/mem/config/prefetch.hh
+++ b/src/mem/config/prefetch.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc
index f579a0727..d4d3fd283 100644
--- a/src/mem/mem_object.cc
+++ b/src/mem/mem_object.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include "mem/mem_object.hh"
diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh
index 58930eccc..c81ea03d8 100644
--- a/src/mem/mem_object.hh
+++ b/src/mem/mem_object.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -48,7 +50,7 @@ class MemObject : public SimObject
public:
/** Additional function to return the Port of a memory object. */
- virtual Port *getPort(const std::string &if_name) = 0;
+ virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
};
#endif //__MEM_MEM_OBJECT_HH__
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index 3b415d77f..91298df8c 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
*/
/**
@@ -54,6 +57,19 @@ Packet::cmdString() const
}
}
+const std::string &
+Packet::cmdIdxToString(Packet::Command idx)
+{
+ switch (idx) {
+ case ReadReq: return ReadReqString;
+ case WriteReq: return WriteReqString;
+ case WriteReqNoAck: return WriteReqNoAckString;
+ case ReadResp: return ReadRespString;
+ case WriteResp: return WriteRespString;
+ default: return OtherCmdString;
+ }
+}
+
/** delete the data pointed to in the data pointer. Ok to call to matter how
* data was allocted. */
void
@@ -97,20 +113,6 @@ Packet::intersect(Packet *p)
return false;
}
-/** Minimally reset a packet so something like simple cpu can reuse it. */
-void
-Packet::reset()
-{
- result = Unknown;
- if (dynamicData) {
- deleteData();
- dynamicData = false;
- arrayData = false;
- time = curTick;
- }
-}
-
-
bool
fixPacket(Packet *func, Packet *timing)
{
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 83f52ede5..2b97ab0c1 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -24,12 +24,15 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
+ * Ali Saidi
*/
/**
* @file
- * Declaration of the Packet Class, a packet is a transaction occuring
- * between a single level of the memory heirarchy (ie L1->L2).
+ * Declaration of the Packet class.
*/
#ifndef __MEM_PACKET_HH__
@@ -38,87 +41,124 @@
#include "mem/request.hh"
#include "arch/isa_traits.hh"
#include "sim/root.hh"
+#include <list>
struct Packet;
typedef Packet* PacketPtr;
typedef uint8_t* PacketDataPtr;
+typedef std::list<PacketPtr> PacketList;
+
+//Coherence Flags
+#define NACKED_LINE 1 << 0
+#define SATISFIED 1 << 1
+#define SHARED_LINE 1 << 2
+#define CACHE_LINE_FILL 1 << 3
+#define COMPRESSED 1 << 4
+#define NO_ALLOCATE 1 << 5
+
+//For statistics we need max number of commands, hard code it at
+//20 for now. @todo fix later
+#define NUM_MEM_CMDS 1 << 9
/**
- * A Packet is the structure to handle requests between two levels
- * of the memory system. The Request is a global object that trancends
- * all of the memory heirarchy, but at each levels interface a packet
- * is created to transfer data/requests. For example, a request would
- * be used to initiate a request to go to memory/IOdevices, as the request
- * passes through the memory system several packets will be created. One
- * will be created to go between the L1 and L2 caches and another to go to
- * the next level and so forth.
- *
- * Packets are assumed to be returned in the case of a single response. If
- * the transaction has no response, then the consumer will delete the packet.
+ * A Packet is used to encapsulate a transfer between two objects in
+ * the memory system (e.g., the L1 and L2 cache). (In contrast, a
+ * single Request travels all the way from the requester to the
+ * ultimate destination and back, possibly being conveyed by several
+ * different Packets along the way.)
*/
class Packet
{
+ public:
+ /** Temporary FLAGS field until cache gets working, this should be in coherence/sender state. */
+ uint64_t flags;
+
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? */
+ /** 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. */
+ /** 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.*/
+ /** the data pointer points to an array (thus delete [] ) needs to
+ * be called on it rather than simply delete.*/
bool arrayData;
- /** The address of the request, could be virtual or physical (depending on
- cache configurations). */
+ /** The address of the request. This address could be virtual or
+ * physical, depending on the system configuration. */
Addr addr;
- /** Indicates the size of the request. */
+ /** The size of the request or transfer. */
int size;
- /** A index of the source of the transaction. */
+ /** 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;
- /** A index to the destination of the transaction. */
+ /** 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;
- bool addrValid;
- bool sizeValid;
+ /** Are the 'addr' and 'size' fields valid? */
+ bool addrSizeValid;
+ /** Is the 'src' field valid? */
bool srcValid;
+
public:
+ /** Used to calculate latencies for each packet.*/
+ Tick time;
+
+ /** The special destination address indicating that the packet
+ * should be routed based on its address. */
static const short Broadcast = -1;
- /** A pointer to the overall request. */
+ /** A pointer to the original request. */
RequestPtr req;
+ /** A virtual base opaque structure used to hold coherence-related
+ * state. A specific subclass would be derived from this to
+ * carry state specific to a particular coherence protocol. */
class CoherenceState {
public:
virtual ~CoherenceState() {}
};
- /** A virtual base opaque structure used to hold
- coherence status messages. */
- CoherenceState *coherence; // virtual base opaque,
- // assert(dynamic_cast<Foo>) etc.
-
+ /** This packet's coherence state. Caches should use
+ * dynamic_cast<> to cast to the state appropriate for the
+ * system's coherence protocol. */
+ CoherenceState *coherence;
+
+ /** 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:
virtual ~SenderState() {}
};
- /** A virtual base opaque structure used to hold the senders state. */
- SenderState *senderState; // virtual base opaque,
- // assert(dynamic_cast<Foo>) etc.
+ /** This packet's sender state. Devices should use dynamic_cast<>
+ * to cast to the state appropriate to the sender. */
+ SenderState *senderState;
private:
/** List of command attributes. */
@@ -131,51 +171,69 @@ class Packet
IsRequest = 1 << 4,
IsResponse = 1 << 5,
NeedsResponse = 1 << 6,
+ IsSWPrefetch = 1 << 7,
+ IsHWPrefetch = 1 << 8
};
public:
/** List of all commands associated with a packet. */
enum Command
{
+ InvalidCmd = 0,
ReadReq = IsRead | IsRequest | NeedsResponse,
WriteReq = IsWrite | IsRequest | NeedsResponse,
WriteReqNoAck = IsWrite | IsRequest,
ReadResp = IsRead | IsResponse,
- WriteResp = IsWrite | IsResponse
+ WriteResp = IsWrite | IsResponse,
+ Writeback = IsWrite | IsRequest,
+ SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
+ HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
+ SoftPFResp = IsRead | IsRequest | IsSWPrefetch | IsResponse,
+ HardPFResp = IsRead | IsRequest | IsHWPrefetch | IsResponse,
+ InvalidateReq = IsInvalidate | IsRequest,
+ WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest,
+ UpgradeReq = IsInvalidate | NeedsResponse,
+ UpgradeResp = IsInvalidate | IsResponse,
+ ReadExReq = IsRead | IsInvalidate | NeedsResponse,
+ ReadExResp = IsRead | IsInvalidate | IsResponse
};
+ /** Return the string name of the cmd field (for debugging and
+ * tracing). */
const std::string &cmdString() const;
- /** The command of the transaction. */
+ /** Reutrn the string to a cmd given by idx. */
+ const std::string &cmdIdxToString(Command idx);
+
+ /** Return the index of this command. */
+ inline int cmdToIndex() const { return (int) cmd; }
+
+ /** The command field of the packet. */
Command cmd;
bool isRead() { return (cmd & IsRead) != 0; }
+ bool isWrite() { return (cmd & IsWrite) != 0; }
bool isRequest() { return (cmd & IsRequest) != 0; }
bool isResponse() { return (cmd & IsResponse) != 0; }
bool needsResponse() { return (cmd & NeedsResponse) != 0; }
+ bool isInvalidate() { return (cmd * IsInvalidate) != 0; }
- void makeTimingResponse() {
- assert(needsResponse());
- int icmd = (int)cmd;
- icmd &= ~(IsRequest | NeedsResponse);
- icmd |= IsResponse;
- cmd = (Command)icmd;
- dest = src;
- srcValid = false;
- }
+ bool isCacheFill() { return (flags & CACHE_LINE_FILL) != 0; }
+ bool isNoAllocate() { return (flags & NO_ALLOCATE) != 0; }
+ bool isCompressed() { return (flags & COMPRESSED) != 0; }
- /** The time this request was responded to. Used to calculate latencies. */
- Tick time;
+ bool nic_pkt() { assert("Unimplemented\n" && 0); }
- /** The result of a particular packets request. */
+ /** Possible results of a packet's request. */
enum Result
{
Success,
BadAddress,
+ Nacked,
Unknown
};
- /** The result of the packet transaction. */
+ /** The result of this packet's request. */
Result result;
/** Accessor function that returns the source index of the packet. */
@@ -187,35 +245,90 @@ class Packet
short getDest() const { return dest; }
void setDest(short _dest) { dest = _dest; }
- Addr getAddr() const { assert(addrValid); return addr; }
- void setAddr(Addr _addr) { addr = _addr; addrValid = true; }
-
- int getSize() const { assert(sizeValid); return size; }
- void setSize(int _size) { size = _size; sizeValid = true; }
+ Addr getAddr() const { assert(addrSizeValid); return addr; }
+ int getSize() const { assert(addrSizeValid); return size; }
+ Addr getOffset(int blkSize) const { return req->getPaddr() & (Addr)(blkSize - 1); }
+ void addrOverride(Addr newAddr) { assert(addrSizeValid); addr = newAddr; }
+ void cmdOverride(Command newCmd) { cmd = newCmd; }
+ /** 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, Command _cmd, short _dest)
: data(NULL), staticData(false), dynamicData(false), arrayData(false),
addr(_req->paddr), size(_req->size), dest(_dest),
- addrValid(_req->validPaddr), sizeValid(_req->validSize),
+ addrSizeValid(_req->validPaddr),
srcValid(false),
req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
- time(curTick), result(Unknown)
+ result(Unknown)
+ {
+ flags = 0;
+ }
+
+ /** 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, Command _cmd, short _dest, int _blkSize)
+ : data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize),
+ dest(_dest),
+ addrSizeValid(_req->validPaddr), srcValid(false),
+ req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
+ result(Unknown)
{
+ flags = 0;
}
+ /** Destructor. */
~Packet()
{ 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);
+ addr = req->paddr;
+ size = req->size;
+ addrSizeValid = true;
+ result = Unknown;
+ if (dynamicData) {
+ deleteData();
+ dynamicData = false;
+ arrayData = false;
+ }
+ }
- /** Minimally reset a packet so something like simple cpu can reuse it. */
- void reset();
+ /** Take a request packet and modify it in place to be suitable
+ * for returning as a response to that request. Used for timing
+ * accesses only. For atomic and functional accesses, the
+ * request packet is always implicitly passed back *without*
+ * modifying the command or destination fields, so this function
+ * should not be called. */
+ void makeTimingResponse() {
+ assert(needsResponse());
+ int icmd = (int)cmd;
+ icmd &= ~(IsRequest | NeedsResponse);
+ icmd |= IsResponse;
+ cmd = (Command)icmd;
+ dest = src;
+ srcValid = false;
+ }
- void reinitFromRequest() {
- if (req->validPaddr) setAddr(req->paddr);
- if (req->validSize) setSize(req->size);
+ /** Take a request packet that has been returned as NACKED and modify it so
+ * that it can be sent out again. Only packets that need a response can be
+ * NACKED, so verify that that is true. */
+ void reinitNacked() {
+ assert(needsResponse() && result == Nacked);
+ dest = Broadcast;
+ result = Unknown;
}
+
/** Set the data pointer to the following value that should not be freed. */
template <typename T>
void dataStatic(T *p);
diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc
index c4e1ea193..a34a0393a 100644
--- a/src/mem/page_table.cc
+++ b/src/mem/page_table.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ron Dreslinski
*/
/**
@@ -51,6 +54,9 @@ PageTable::PageTable(System *_system, Addr _pageSize)
system(_system)
{
assert(isPowerOf2(pageSize));
+ pTableCache[0].vaddr = 0;
+ pTableCache[1].vaddr = 0;
+ pTableCache[2].vaddr = 0;
}
PageTable::~PageTable()
@@ -92,7 +98,7 @@ PageTable::allocate(Addr vaddr, int size)
assert(pageOffset(vaddr) == 0);
for (; size > 0; size -= pageSize, vaddr += pageSize) {
- std::map<Addr,Addr>::iterator iter = pTable.find(vaddr);
+ m5::hash_map<Addr,Addr>::iterator iter = pTable.find(vaddr);
if (iter != pTable.end()) {
// already mapped
@@ -100,6 +106,12 @@ PageTable::allocate(Addr vaddr, int size)
}
pTable[vaddr] = system->new_page();
+ pTableCache[2].paddr = pTableCache[1].paddr;
+ pTableCache[2].vaddr = pTableCache[1].vaddr;
+ pTableCache[1].paddr = pTableCache[0].paddr;
+ pTableCache[1].vaddr = pTableCache[0].vaddr;
+ pTableCache[0].paddr = pTable[vaddr];
+ pTableCache[0].vaddr = vaddr;
}
}
@@ -109,7 +121,22 @@ bool
PageTable::translate(Addr vaddr, Addr &paddr)
{
Addr page_addr = pageAlign(vaddr);
- std::map<Addr,Addr>::iterator iter = pTable.find(page_addr);
+ paddr = 0;
+
+ if (pTableCache[0].vaddr == vaddr) {
+ paddr = pTableCache[0].paddr;
+ return true;
+ }
+ if (pTableCache[1].vaddr == vaddr) {
+ paddr = pTableCache[1].paddr;
+ return true;
+ }
+ if (pTableCache[2].vaddr == vaddr) {
+ paddr = pTableCache[2].paddr;
+ return true;
+ }
+
+ m5::hash_map<Addr,Addr>::iterator iter = pTable.find(page_addr);
if (iter == pTable.end()) {
return false;
@@ -127,7 +154,7 @@ PageTable::translate(RequestPtr &req)
assert(pageAlign(req->getVaddr() + req->getSize() - 1)
== pageAlign(req->getVaddr()));
if (!translate(req->getVaddr(), paddr)) {
- return genMachineCheckFault();
+ return genPageTableFault(req->getVaddr());
}
req->setPaddr(paddr);
return page_check(req->getPaddr(), req->getSize());
diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh
index 26248261a..494c0ce9a 100644
--- a/src/mem/page_table.hh
+++ b/src/mem/page_table.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -35,9 +37,9 @@
#define __PAGE_TABLE__
#include <string>
-#include <map>
#include "arch/isa_traits.hh"
+#include "base/hashmap.hh"
#include "base/trace.hh"
#include "mem/request.hh"
#include "mem/packet.hh"
@@ -51,7 +53,14 @@ class System;
class PageTable
{
protected:
- std::map<Addr,Addr> pTable;
+ m5::hash_map<Addr,Addr> pTable;
+
+ struct cacheElement {
+ Addr paddr;
+ Addr vaddr;
+ } ;
+
+ struct cacheElement pTableCache[3];
const Addr pageSize;
const Addr offsetMask;
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index 26dbef0cd..2d66602ab 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <sys/types.h>
@@ -139,8 +141,7 @@ Tick
PhysicalMemory::doAtomicAccess(Packet *pkt)
{
doFunctionalAccess(pkt);
- pkt->time = curTick + lat;
- return curTick + lat;
+ return lat;
}
void
@@ -172,9 +173,9 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt)
}
Port *
-PhysicalMemory::getPort(const std::string &if_name)
+PhysicalMemory::getPort(const std::string &if_name, int idx)
{
- if (if_name == "") {
+ if (if_name == "port" && idx == -1) {
if (port != NULL)
panic("PhysicalMemory::getPort: additional port requested to memory!");
port = new MemoryPort(name() + "-port", this);
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index 2ced79045..50fa75ed3 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
@@ -106,7 +108,7 @@ class PhysicalMemory : public MemObject
public:
int deviceBlockSize();
void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
- virtual Port *getPort(const std::string &if_name);
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
void virtual init();
// fast back-door memory access for vtophys(), remote gdb, etc.
diff --git a/src/mem/port.cc b/src/mem/port.cc
index 651cb739a..bec9d2274 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -45,13 +47,12 @@ Port::setPeer(Port *port)
void
Port::blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd)
{
- Request req(false);
+ Request req;
Packet pkt(&req, cmd, Packet::Broadcast);
for (ChunkGenerator gen(addr, size, peerBlockSize());
!gen.done(); gen.next()) {
- req.setPaddr(gen.addr());
- req.setSize(gen.size());
+ req.setPhys(gen.addr(), gen.size(), 0);
pkt.reinitFromRequest();
pkt.dataStatic(p);
sendFunctional(&pkt);
diff --git a/src/mem/port.hh b/src/mem/port.hh
index f9103865e..17b1f4a00 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -72,10 +74,19 @@ class Port
private:
/** Descriptive name (for DPRINTF output) */
- const std::string portName;
+ mutable std::string portName;
+
+ /** A pointer to the peer port. Ports always come in pairs, that way they
+ can use a standardized interface to communicate between different
+ memory objects. */
+ Port *peer;
public:
+ Port()
+ : peer(NULL)
+ { }
+
/**
* Constructor.
*
@@ -83,7 +94,7 @@ class Port
* of memory system object to which the port belongs.
*/
Port(const std::string &_name)
- : portName(_name)
+ : portName(_name), peer(NULL)
{ }
/** Return port name (for DPRINTF). */
@@ -92,22 +103,14 @@ class Port
virtual ~Port() {};
// mey be better to use subclasses & RTTI?
- /** Holds the ports status. Keeps track if it is blocked, or has
- calculated a range change. */
+ /** Holds the ports status. Currently just that a range recomputation needs
+ * to be done. */
enum Status {
- Blocked,
- Unblocked,
RangeChange
};
- private:
-
- /** A pointer to the peer port. Ports always come in pairs, that way they
- can use a standardized interface to communicate between different
- memory objects. */
- Port *peer;
-
- public:
+ void setName(const std::string &name)
+ { portName = name; }
/** Function to set the pointer for the peer port.
@todo should be called by the configuration stuff (python).
@@ -140,7 +143,7 @@ class Port
wait. This shouldn't be valid for response paths (IO Devices).
so it is set to panic if it isn't already defined.
*/
- virtual Packet *recvRetry() { panic("??"); }
+ virtual void recvRetry() { panic("??"); }
/** Called by a peer port in order to determine the block size of the
device connected to this port. It sometimes doesn't make sense for
@@ -165,16 +168,17 @@ class Port
port receive function.
@return This function returns if the send was succesful in it's
recieve. If it was a failure, then the port will wait for a recvRetry
- at which point it can issue a successful sendTiming. This is used in
+ at which point it can possibly issue a successful sendTiming. This is used in
case a cache has a higher priority request come in while waiting for
the bus to arbitrate.
*/
bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }
- /** Function called by the associated device to send an atomic access,
- an access in which the data is moved and the state is updated in one
- cycle, without interleaving with other memory accesses.
- */
+ /** Function called by the associated device to send an atomic
+ * access, an access in which the data is moved and the state is
+ * updated in one cycle, without interleaving with other memory
+ * accesses. Returns estimated latency of access.
+ */
Tick sendAtomic(Packet *pkt)
{ return peer->recvAtomic(pkt); }
@@ -194,7 +198,7 @@ class Port
/** When a timing access doesn't return a success, some time later the
Retry will be sent.
*/
- Packet *sendRetry() { return peer->recvRetry(); }
+ void sendRetry() { return peer->recvRetry(); }
/** Called by the associated device if it wishes to find out the blocksize
of the device on attached to the peer port.
@@ -252,6 +256,14 @@ class FunctionalPort : public Port
virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
virtual void recvStatusChange(Status status) {}
+ /** a write function that also does an endian conversion. */
+ template <typename T>
+ inline void writeHtoG(Addr addr, T d);
+
+ /** a read function that also does an endian conversion. */
+ template <typename T>
+ inline T readGtoH(Addr addr);
+
template <typename T>
inline void write(Addr addr, T d)
{
diff --git a/src/mem/port_impl.hh b/src/mem/port_impl.hh
new file mode 100644
index 000000000..e9a159293
--- /dev/null
+++ b/src/mem/port_impl.hh
@@ -0,0 +1,53 @@
+/*
+ * 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 "arch/isa_specific.hh"
+#include "arch/isa_traits.hh"
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+
+template <typename T>
+void
+FunctionalPort::writeHtoG(Addr addr, T d)
+{
+ d = TheISA::htog(d);
+ writeBlob(addr, (uint8_t*)&d, sizeof(T));
+}
+
+
+template <typename T>
+T
+FunctionalPort::readGtoH(Addr addr)
+{
+ T d;
+ readBlob(addr, (uint8_t*)&d, sizeof(T));
+ return TheISA::gtoh(d);
+}
+
diff --git a/src/mem/request.hh b/src/mem/request.hh
index 10550e859..a1524f807 100644
--- a/src/mem/request.hh
+++ b/src/mem/request.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
+ * Ali Saidi
*/
/**
@@ -40,6 +44,7 @@ class Request;
typedef Request* RequestPtr;
+
/** The request is a Load locked/store conditional. */
const unsigned LOCKED = 0x001;
/** The virtual address is also the physical address. */
@@ -58,142 +63,174 @@ const unsigned PF_EXCLUSIVE = 0x100;
const unsigned EVICT_NEXT = 0x200;
/** The request should ignore unaligned access faults */
const unsigned NO_ALIGN_FAULT = 0x400;
+/** The request was an instruction read. */
+const unsigned INST_READ = 0x800;
class Request
{
- //@todo Make Accesor functions, make these private.
- public:
- /** Constructor, needs a bool to signify if it is/isn't Cpu Request. */
- Request(bool isCpu);
-
- /** reset the request to it's initial state so it can be reused.*/
- void resetAll(bool isCpu);
-
- /** reset the request's addrs times, etc, so but not everything to same
- * time. */
- void resetMin();
-
-//First non-cpu request fields
private:
- /** The physical address of the request. */
+ /**
+ * The physical address of the request. Valid only if validPaddr
+ * is set. */
Addr paddr;
- /** Wether or not paddr is valid (has been written yet). */
- bool validPaddr;
- /** The size of the request. */
+ /**
+ * 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. */
int size;
- /** Wether or not size is valid (has been written yet). */
- bool validSize;
-
- /** The time this request was started. Used to calculate latencies. */
- Tick time;
- /** Wether or not time is valid (has been written yet). */
- bool validTime;
-
- /** Destination address if this is a block copy. */
- Addr copyDest;
- /** Wether or not copyDest is valid (has been written yet). */
- bool validCopyDest;
/** Flag structure for the request. */
uint32_t flags;
-//Accsesors for non-cpu request fields
- public:
- /** Accesor for paddr. */
- Addr getPaddr();
- /** Accesor for paddr. */
- void setPaddr(Addr _paddr);
-
- /** Accesor for size. */
- int getSize();
- /** Accesor for size. */
- void setSize(int _size);
-
- /** Accesor for time. */
- Tick getTime();
- /** Accesor for time. */
- void setTime(Tick _time);
-
- /** Accesor for copy dest. */
- Addr getCopyDest();
- /** Accesor for copy dest. */
- void setCopyDest(Addr _copyDest);
-
- /** Accesor for flags. */
- uint32_t getFlags();
- /** Accesor for paddr. */
- void setFlags(uint32_t _flags);
-
-//Now cpu-request fields
- private:
- /** Bool to signify if this is a cpuRequest. */
- bool cpuReq;
-
- /** The virtual address of the request. */
- Addr vaddr;
- /** Wether or not the vaddr is valid. */
- bool validVaddr;
+ /**
+ * The time this request was started. Used to calculate
+ * latencies. This field is set to curTick any time paddr or vaddr
+ * is written. */
+ Tick time;
/** The address space ID. */
int asid;
- /** Wether or not the asid is valid. */
- bool validAsid;
+ /** The virtual address of the request. */
+ Addr vaddr;
/** The return value of store conditional. */
uint64_t scResult;
- /** Wether or not the sc result is valid. */
- bool validScResult;
- /** The cpu number for statistics. */
+ /** The cpu number (for statistics, typically). */
int cpuNum;
- /** Wether or not the cpu number is valid. */
- bool validCpuNum;
-
- /** The requesting thread id. */
+ /** The requesting thread id (for statistics, typically). */
int threadNum;
- /** Wether or not the thread id is valid. */
- bool validThreadNum;
/** program counter of initiating access; for tracing/debugging */
Addr pc;
- /** Wether or not the pc is valid. */
+
+ /** 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 validScResult;
+ /** Whether or not the cpu number & thread ID are valid. */
+ bool validCpuAndThreadNums;
+ /** Whether or not the pc is valid. */
bool validPC;
-//Accessor Functions for cpu request fields
public:
- /** Accesor function to determine if this is a cpu request or not.*/
- bool isCpuRequest();
-
- /** Accesor function for vaddr.*/
- Addr getVaddr();
- /** Accesor function for vaddr.*/
- void setVaddr(Addr _vaddr);
-
- /** Accesor function for asid.*/
- int getAsid();
- /** Accesor function for asid.*/
- void setAsid(int _asid);
-
- /** Accesor function for store conditional return value.*/
- uint64_t getScResult();
- /** Accesor function for store conditional return value.*/
- void setScResult(uint64_t _scResult);
-
- /** Accesor function for cpu number.*/
- int getCpuNum();
- /** Accesor function for cpu number.*/
- void setCpuNum(int _cpuNum);
-
- /** Accesor function for thread number.*/
- int getThreadNum();
- /** Accesor function for thread number.*/
- void setThreadNum(int _threadNum);
-
- /** Accesor function for pc.*/
- Addr getPC();
- /** Accesor function for pc.*/
- void setPC(Addr _pc);
+ /** Minimal constructor. No fields are initialized. */
+ Request()
+ : validPaddr(false), validAsidVaddr(false),
+ validScResult(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); }
+
+ Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc,
+ int _cpuNum, int _threadNum)
+ {
+ setThreadContext(_cpuNum, _threadNum);
+ setVirt(_asid, _vaddr, _size, _flags, _pc);
+ }
+
+ /**
+ * Set up CPU and thread numbers. */
+ void setThreadContext(int _cpuNum, int _threadNum)
+ {
+ cpuNum = _cpuNum;
+ threadNum = _threadNum;
+ validCpuAndThreadNums = true;
+ }
+
+ /**
+ * Set up a physical (e.g. device) request in a previously
+ * allocated Request object. */
+ void setPhys(Addr _paddr, int _size, int _flags)
+ {
+ paddr = _paddr;
+ size = _size;
+ flags = _flags;
+ time = curTick;
+ validPaddr = true;
+ validAsidVaddr = false;
+ validPC = false;
+ validScResult = false;
+ }
+
+ /**
+ * 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)
+ {
+ asid = _asid;
+ vaddr = _vaddr;
+ size = _size;
+ flags = _flags;
+ pc = _pc;
+ time = curTick;
+ validPaddr = false;
+ validAsidVaddr = true;
+ validPC = true;
+ validScResult = false;
+ }
+
+ /** 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)
+ {
+ assert(validAsidVaddr);
+ paddr = _paddr;
+ validPaddr = true;
+ }
+
+ /** Accessor for paddr. */
+ Addr getPaddr() { assert(validPaddr); return paddr; }
+
+ /** Accessor for size. */
+ int getSize() { assert(validPaddr || validAsidVaddr); return size; }
+ /** Accessor for time. */
+ Tick getTime() { assert(validPaddr || validAsidVaddr); return time; }
+
+ /** Accessor for flags. */
+ uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; }
+ /** Accessor for paddr. */
+ void setFlags(uint32_t _flags)
+ { assert(validPaddr || validAsidVaddr); flags = _flags; }
+
+ /** Accessor function for vaddr.*/
+ Addr getVaddr() { assert(validAsidVaddr); return vaddr; }
+
+ /** Accessor function for asid.*/
+ int getAsid() { assert(validAsidVaddr); return asid; }
+
+ /** Accessor function to check if sc result is valid. */
+ bool scResultValid() { return validScResult; }
+ /** Accessor function for store conditional return value.*/
+ uint64_t getScResult() { assert(validScResult); return scResult; }
+ /** Accessor function for store conditional return value.*/
+ void setScResult(uint64_t _scResult)
+ { scResult = _scResult; validScResult = true; }
+
+ /** Accessor function for cpu number.*/
+ int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
+ /** Accessor function for thread number.*/
+ int getThreadNum() { assert(validCpuAndThreadNums); return threadNum; }
+
+ /** Accessor function for pc.*/
+ Addr getPC() { assert(validPC); return pc; }
+
+ /** Accessor Function to Check Cacheability. */
+ bool isUncacheable() { return getFlags() & UNCACHEABLE; }
+
+ bool isInstRead() { return getFlags() & INST_READ; }
friend class Packet;
};
diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc
index ee4d277b6..d2c854086 100644
--- a/src/mem/translating_port.cc
+++ b/src/mem/translating_port.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Reinhardt
*/
#include <string>
diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh
index d078158a3..7354278ba 100644
--- a/src/mem/translating_port.hh
+++ b/src/mem/translating_port.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#ifndef __MEM_TRANSLATING_PROT_HH__
diff --git a/src/mem/vport.cc b/src/mem/vport.cc
index cc569acf3..cd297bb8e 100644
--- a/src/mem/vport.cc
+++ b/src/mem/vport.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -40,8 +42,8 @@ VirtualPort::readBlob(Addr addr, uint8_t *p, int size)
for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
gen.next())
{
- if (xc)
- paddr = TheISA::vtophys(xc,gen.addr());
+ if (tc)
+ paddr = TheISA::vtophys(tc,gen.addr());
else
paddr = TheISA::vtophys(gen.addr());
@@ -57,8 +59,8 @@ VirtualPort::writeBlob(Addr addr, uint8_t *p, int size)
for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
gen.next())
{
- if (xc)
- paddr = TheISA::vtophys(xc,gen.addr());
+ if (tc)
+ paddr = TheISA::vtophys(tc,gen.addr());
else
paddr = TheISA::vtophys(gen.addr());
diff --git a/src/mem/vport.hh b/src/mem/vport.hh
index 0f3b1f09e..697c8e5f3 100644
--- a/src/mem/vport.hh
+++ b/src/mem/vport.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -36,13 +38,13 @@
#ifndef __MEM_VPORT_HH__
#define __MEM_VPORT_HH__
-#include "mem/port.hh"
+#include "mem/port_impl.hh"
#include "config/full_system.hh"
#include "arch/vtophys.hh"
/** A class that translates a virtual address to a physical address and then
- * calls the above read/write functions. If an execution context is provided the
+ * calls the above read/write functions. If a thread context is provided the
* address can alway be translated, If not it can only be translated if it is a
* simple address masking operation (such as alpha super page accesses).
*/
@@ -50,18 +52,19 @@
class VirtualPort : public FunctionalPort
{
private:
- ExecContext *xc;
+ ThreadContext *tc;
public:
- VirtualPort(const std::string &_name, ExecContext *_xc = NULL)
- : FunctionalPort(_name), xc(_xc)
+ VirtualPort(const std::string &_name, ThreadContext *_tc = NULL)
+ : FunctionalPort(_name), tc(_tc)
{}
- /** Return true if we have an exec context. This is used to prevent someone
- * from accidently deleting the cpus statically allocated vport.
- * @return true if an execution context isn't valid
+ /** Return true if we have an thread context. This is used to
+ * prevent someone from accidently deleting the cpus statically
+ * allocated vport.
+ * @return true if a thread context isn't valid
*/
- bool nullExecContext() { return xc != NULL; }
+ bool nullThreadContext() { return tc != NULL; }
/** Version of readblob that translates virt->phys and deals
* with page boundries. */
diff --git a/src/python/SConscript b/src/python/SConscript
index 4407e403d..3a9def9a8 100644
--- a/src/python/SConscript
+++ b/src/python/SConscript
@@ -25,183 +25,82 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
import os, os.path, re, sys
+from zipfile import PyZipFile
-Import('env')
+# handy function for path joins
+def join(*args):
+ return os.path.normpath(os.path.join(*args))
-import scons_helper
-
-def WriteEmbeddedPyFile(target, source, path, name, ext, filename):
- if isinstance(source, str):
- source = file(source, 'r')
-
- if isinstance(target, str):
- target = file(target, 'w')
-
- print >>target, "AddModule(%s, %s, %s, %s, '''\\" % \
- (`path`, `name`, `ext`, `filename`)
-
- for line in source:
- line = line
- # escape existing backslashes
- line = line.replace('\\', '\\\\')
- # escape existing triple quotes
- line = line.replace("'''", r"\'\'\'")
-
- print >>target, line,
-
- print >>target, "''')"
- print >>target
-
-def WriteCFile(target, source, name):
- if isinstance(source, str):
- source = file(source, 'r')
-
- if isinstance(target, str):
- target = file(target, 'w')
-
- print >>target, 'const char %s_string[] = {' % name
-
- count = 0
- from array import array
- try:
- while True:
- foo = array('B')
- foo.fromfile(source, 10000)
- l = [ str(i) for i in foo.tolist() ]
- count += len(l)
- for i in xrange(0,9999,20):
- print >>target, ','.join(l[i:i+20]) + ','
- except EOFError:
- l = [ str(i) for i in foo.tolist() ]
- count += len(l)
- for i in xrange(0,len(l),20):
- print >>target, ','.join(l[i:i+20]) + ','
- print >>target, ','.join(l[i:]) + ','
-
- print >>target, '};'
- print >>target, 'const int %s_length = %d;' % (name, count)
- print >>target
-
-def splitpath(path):
- dir,file = os.path.split(path)
- path = []
- assert(file)
- while dir:
- dir,base = os.path.split(dir)
- path.insert(0, base)
- return path, file
-
-def MakeEmbeddedPyFile(target, source, env):
- target = file(str(target[0]), 'w')
-
- tree = {}
- for src in source:
- src = str(src)
- path,pyfile = splitpath(src)
- node = tree
- for dir in path:
- if not node.has_key(dir):
- node[dir] = { }
- node = node[dir]
-
- name,ext = pyfile.split('.')
- if name == '__init__':
- node['.hasinit'] = True
- node[pyfile] = (src,name,ext,src)
-
- done = False
- while not done:
- done = True
- for name,entry in tree.items():
- if not isinstance(entry, dict): continue
- if entry.has_key('.hasinit'): continue
-
- done = False
- del tree[name]
- for key,val in entry.iteritems():
- if tree.has_key(key):
- raise NameError, \
- "dir already has %s can't add it again" % key
- tree[key] = val
-
- files = []
- def populate(node, path = []):
- names = node.keys()
- names.sort()
- for name in names:
- if name == '.hasinit':
- continue
-
- entry = node[name]
- if isinstance(entry, dict):
- if not entry.has_key('.hasinit'):
- raise NameError, 'package directory missing __init__.py'
- populate(entry, path + [ name ])
- else:
- pyfile,name,ext,filename = entry
- files.append((pyfile, path, name, ext, filename))
- populate(tree)
-
- for pyfile, path, name, ext, filename in files:
- WriteEmbeddedPyFile(target, pyfile, path, name, ext, filename)
+Import('env')
+# This SConscript is in charge of collecting .py files and generating
+# a zip archive that is appended to the m5 binary.
+
+# List of files & directories to include in the zip file. To include
+# a package, list only the root directory of the package, not any
+# internal .py files (else they will get the path stripped off when
+# they are imported into the zip file).
+pyzip_files = []
+
+# List of additional files on which the zip archive depends, but which
+# are not included in pyzip_files... i.e. individual .py files within
+# a package.
+pyzip_dep_files = []
+
+# Add the specified package to the zip archive. Adds the directory to
+# pyzip_files and all included .py files to pyzip_dep_files.
+def addPkg(pkgdir):
+ pyzip_files.append(pkgdir)
+ origdir = os.getcwd()
+ srcdir = join(Dir('.').srcnode().abspath, pkgdir)
+ os.chdir(srcdir)
+ for path, dirs, files in os.walk('.'):
+ for i,dir in enumerate(dirs):
+ if dir == 'SCCS':
+ del dirs[i]
+ break
+
+ for f in files:
+ if f.endswith('.py'):
+ pyzip_dep_files.append(join(pkgdir, path, f))
+
+ os.chdir(origdir)
+
+# Generate Python file that contains a dict specifying the current
+# build_env flags.
def MakeDefinesPyFile(target, source, env):
f = file(str(target[0]), 'w')
- print >>f, "import __main__"
- print >>f, "__main__.m5_build_env = ",
+ print >>f, "m5_build_env = ",
print >>f, source[0]
f.close()
-CFileCounter = 0
-def MakePythonCFile(target, source, env):
- global CFileCounter
- target = file(str(target[0]), 'w')
-
- print >>target, '''\
-#include "base/embedfile.hh"
-
-namespace {
-'''
- for src in source:
- src = str(src)
- fname = os.path.basename(src)
- name = 'embedded_file%d' % CFileCounter
- CFileCounter += 1
- WriteCFile(target, src, name)
- print >>target, '''\
-EmbedMap %(name)s("%(fname)s",
- %(name)s_string, %(name)s_length);
-
-''' % locals()
- print >>target, '''\
-
-/* namespace */ }
-'''
-
-# base list of .py files to embed
-embedded_py_files = [ os.path.join(env['ROOT'], 'util/pbs/jobfile.py') ]
-# add all .py files in python/m5
-objpath = os.path.join(env['SRCDIR'], 'python', 'm5')
-for root, dirs, files in os.walk(objpath, topdown=True):
- for i,dir in enumerate(dirs):
- if dir == 'SCCS':
- del dirs[i]
- break
-
- assert(root.startswith(objpath))
- for f in files:
- if f.endswith('.py'):
- embedded_py_files.append(os.path.join(root, f))
-
-embedfile_hh = os.path.join(env['SRCDIR'], 'base/embedfile.hh')
-
optionDict = dict([(opt, env[opt]) for opt in env.ExportOptions])
-env.Command('defines.py', Value(optionDict), MakeDefinesPyFile)
-
-env.Command('embedded_py.py', embedded_py_files, MakeEmbeddedPyFile)
-env.Depends('embedded_py.cc', embedfile_hh)
-env.Command('embedded_py.cc',
- ['string_importer.py', 'defines.py', 'embedded_py.py'],
- MakePythonCFile)
+env.Command('m5/defines.py', Value(optionDict), MakeDefinesPyFile)
+
+# Now specify the packages & files for the zip archive.
+addPkg('m5')
+pyzip_files.append('m5/defines.py')
+pyzip_files.append(join(env['ROOT'], 'util/pbs/jobfile.py'))
+
+env.Command(['swig/cc_main_wrap.cc', 'm5/cc_main.py'],
+ 'swig/cc_main.i',
+ '$SWIG $SWIGFLAGS -outdir ${TARGETS[1].dir} '
+ '-o ${TARGETS[0]} $SOURCES')
+
+pyzip_dep_files.append('m5/cc_main.py')
+
+# Action function to build the zip archive. Uses the PyZipFile module
+# included in the standard Python library.
+def buildPyZip(target, source, env):
+ pzf = PyZipFile(str(target[0]), 'w')
+ for s in source:
+ pzf.writepy(str(s))
+
+# Add the zip file target to the environment.
+env.Command('m5py.zip', pyzip_files, buildPyZip)
+env.Depends('m5py.zip', pyzip_dep_files)
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
index 9bb68a090..828165d15 100644
--- a/src/python/m5/__init__.py
+++ b/src/python/m5/__init__.py
@@ -23,24 +23,30 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
+
+import sys, os, time, atexit, optparse
+
+# import the SWIG-wrapped main C++ functions
+import cc_main
+# import a few SWIG-wrapped items (those that are likely to be used
+# directly by user scripts) completely into this module for
+# convenience
+from cc_main import simulate, SimLoopExitEvent, setCheckpointDir
-import sys, os
+# import the m5 compile options
+import defines
# define this here so we can use it right away if necessary
def panic(string):
print >>sys.stderr, 'panic:', string
sys.exit(1)
-def m5execfile(f, global_dict):
- # copy current sys.path
- oldpath = sys.path[:]
- # push file's directory onto front of path
- sys.path.insert(0, os.path.abspath(os.path.dirname(f)))
- execfile(f, global_dict)
- # restore original path
- sys.path = oldpath
-
-# Prepend given directory to system module search path.
+# Prepend given directory to system module search path. We may not
+# need this anymore if we can structure our config library more like a
+# Python package.
def AddToPath(path):
# if it's a relative path and we know what directory the current
# python script is in, make the path relative to that directory.
@@ -51,24 +57,236 @@ def AddToPath(path):
# so place the new dir right after that.
sys.path.insert(1, path)
-# find the m5 compile options: must be specified as a dict in
-# __main__.m5_build_env.
-import __main__
-if not hasattr(__main__, 'm5_build_env'):
- panic("__main__ must define m5_build_env")
+
+# The m5 module's pointer to the parsed options object
+options = None
+
+
+# User should call this function after calling parse_args() to pass
+# parsed standard option values back into the m5 module for
+# processing.
+def setStandardOptions(_options):
+ # Set module global var
+ global options
+ options = _options
+ # tell C++ about output directory
+ cc_main.setOutputDir(options.outdir)
+
+# Callback to set trace flags. Not necessarily the best way to do
+# things in the long run (particularly if we change how these global
+# options are handled).
+def setTraceFlags(option, opt_str, value, parser):
+ objects.Trace.flags = value
+
+def setTraceStart(option, opt_str, value, parser):
+ objects.Trace.start = value
+
+def setTraceFile(option, opt_str, value, parser):
+ objects.Trace.file = value
+
+def noPCSymbol(option, opt_str, value, parser):
+ objects.ExecutionTrace.pc_symbol = False
+
+def noPrintCycle(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_cycle = False
+
+def noPrintOpclass(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_opclass = False
+
+def noPrintThread(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_thread = False
+
+def noPrintEA(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_effaddr = False
+
+def noPrintData(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_data = False
+
+def printFetchseq(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_fetchseq = True
+
+def printCpseq(option, opt_str, value, parser):
+ objects.ExecutionTrace.print_cpseq = True
+
+def dumpOnExit(option, opt_str, value, parser):
+ objects.Trace.dump_on_exit = True
+
+def debugBreak(option, opt_str, value, parser):
+ objects.Debug.break_cycles = value
+
+def statsTextFile(option, opt_str, value, parser):
+ objects.Statistics.text_file = value
+
+# Standard optparse options. Need to be explicitly included by the
+# user script when it calls optparse.OptionParser().
+standardOptions = [
+ optparse.make_option("--outdir", type="string", default="."),
+ optparse.make_option("--traceflags", type="string", action="callback",
+ callback=setTraceFlags),
+ optparse.make_option("--tracestart", type="int", action="callback",
+ callback=setTraceStart),
+ optparse.make_option("--tracefile", type="string", action="callback",
+ callback=setTraceFile),
+ optparse.make_option("--nopcsymbol",
+ action="callback", callback=noPCSymbol,
+ help="Disable PC symbols in trace output"),
+ optparse.make_option("--noprintcycle",
+ action="callback", callback=noPrintCycle,
+ help="Don't print cycle numbers in trace output"),
+ optparse.make_option("--noprintopclass",
+ action="callback", callback=noPrintOpclass,
+ help="Don't print op class type in trace output"),
+ optparse.make_option("--noprintthread",
+ action="callback", callback=noPrintThread,
+ help="Don't print thread number in trace output"),
+ optparse.make_option("--noprinteffaddr",
+ action="callback", callback=noPrintEA,
+ help="Don't print effective address in trace output"),
+ optparse.make_option("--noprintdata",
+ action="callback", callback=noPrintData,
+ help="Don't print result data in trace output"),
+ optparse.make_option("--printfetchseq",
+ action="callback", callback=printFetchseq,
+ help="Print fetch sequence numbers in trace output"),
+ optparse.make_option("--printcpseq",
+ action="callback", callback=printCpseq,
+ help="Print correct path sequence numbers in trace output"),
+ optparse.make_option("--dumponexit",
+ action="callback", callback=dumpOnExit,
+ help="Dump trace buffer on exit"),
+ optparse.make_option("--debugbreak", type="int", metavar="CYCLE",
+ action="callback", callback=debugBreak,
+ help="Cycle to create a breakpoint"),
+ optparse.make_option("--statsfile", type="string", action="callback",
+ callback=statsTextFile, metavar="FILE",
+ help="Sets the output file for the statistics")
+ ]
# make a SmartDict out of the build options for our local use
import smartdict
build_env = smartdict.SmartDict()
-build_env.update(__main__.m5_build_env)
+build_env.update(defines.m5_build_env)
# make a SmartDict out of the OS environment too
env = smartdict.SmartDict()
env.update(os.environ)
-# import the main m5 config code
-from config import *
-# import the built-in object definitions
-from objects import *
+# Function to provide to C++ so it can look up instances based on paths
+def resolveSimObject(name):
+ obj = config.instanceDict[name]
+ return obj.getCCObject()
+
+# The final hook to generate .ini files. Called from the user script
+# once the config is built.
+def instantiate(root):
+ config.ticks_per_sec = float(root.clock.frequency)
+ # ugly temporary hack to get output to config.ini
+ sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w')
+ root.print_ini()
+ sys.stdout.close() # close config.ini
+ sys.stdout = sys.__stdout__ # restore to original
+ cc_main.loadIniFile(resolveSimObject) # load config.ini into C++
+ root.createCCObject()
+ root.connectPorts()
+ cc_main.finalInit()
+ noDot = True # temporary until we fix dot
+ if not noDot:
+ dot = pydot.Dot()
+ instance.outputDot(dot)
+ dot.orientation = "portrait"
+ dot.size = "8.5,11"
+ dot.ranksep="equally"
+ dot.rank="samerank"
+ dot.write("config.dot")
+ dot.write_ps("config.ps")
+
+# Export curTick to user script.
+def curTick():
+ return cc_main.cvar.curTick
+
+# register our C++ exit callback function with Python
+atexit.register(cc_main.doExitCleanup)
+
+# This import allows user scripts to reference 'm5.objects.Foo' after
+# just doing an 'import m5' (without an 'import m5.objects'). May not
+# matter since most scripts will probably 'from m5.objects import *'.
+import objects
+
+def doQuiesce(root):
+ quiesce = cc_main.createCountedQuiesce()
+ unready_objects = root.startQuiesce(quiesce, True)
+ # If we've got some objects that can't quiesce immediately, then simulate
+ if unready_objects > 0:
+ quiesce.setCount(unready_objects)
+ simulate()
+ cc_main.cleanupCountedQuiesce(quiesce)
+
+def resume(root):
+ root.resume()
+
+def checkpoint(root):
+ if not isinstance(root, objects.Root):
+ raise TypeError, "Object is not a root object. Checkpoint must be called on a root object."
+ doQuiesce(root)
+ print "Writing checkpoint"
+ cc_main.serializeAll()
+ resume(root)
+
+def restoreCheckpoint(root):
+ print "Restoring from checkpoint"
+ cc_main.unserializeAll()
+
+def changeToAtomic(system):
+ if not isinstance(system, objects.Root) and not isinstance(system, System):
+ raise TypeError, "Object is not a root or system object. Checkpoint must be "
+ "called on a root object."
+ doQuiesce(system)
+ print "Changing memory mode to atomic"
+ system.changeTiming(cc_main.SimObject.Atomic)
+ resume(system)
+
+def changeToTiming(system):
+ if not isinstance(system, objects.Root) and not isinstance(system, System):
+ raise TypeError, "Object is not a root or system object. Checkpoint must be "
+ "called on a root object."
+ doQuiesce(system)
+ print "Changing memory mode to timing"
+ system.changeTiming(cc_main.SimObject.Timing)
+ resume(system)
+
+def switchCpus(cpuList):
+ if not isinstance(cpuList, list):
+ raise RuntimeError, "Must pass a list to this function"
+ for i in cpuList:
+ if not isinstance(i, tuple):
+ raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
+
+ [old_cpus, new_cpus] = zip(*cpuList)
+
+ for cpu in old_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU", cpu
+ for cpu in new_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU", cpu
+ # Quiesce all of the individual CPUs
+ quiesce = cc_main.createCountedQuiesce()
+ unready_cpus = 0
+ for old_cpu in old_cpus:
+ unready_cpus += old_cpu.startQuiesce(quiesce, False)
+ # If we've got some objects that can't quiesce immediately, then simulate
+ if unready_cpus > 0:
+ quiesce.setCount(unready_cpus)
+ simulate()
+ cc_main.cleanupCountedQuiesce(quiesce)
+ # Now all of the CPUs are ready to be switched out
+ for old_cpu in old_cpus:
+ old_cpu._ccObject.switchOut()
+ index = 0
+ print "Switching CPUs"
+ for new_cpu in new_cpus:
+ new_cpu.takeOverFrom(old_cpus[index])
+ new_cpu._ccObject.resume()
+ index += 1
diff --git a/src/python/m5/config.py b/src/python/m5/config.py
index 1e25e0d09..6f2873d40 100644
--- a/src/python/m5/config.py
+++ b/src/python/m5/config.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2004-2005 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
@@ -23,12 +23,14 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
-from __future__ import generators
-import os, re, sys, types, inspect
+import os, re, sys, types, inspect, copy
import m5
-panic = m5.panic
+from m5 import panic, cc_main
from convert import *
from multidict import multidict
@@ -82,60 +84,24 @@ class Singleton(type):
#
# Once a set of Python objects have been instantiated in a hierarchy,
# calling 'instantiate(obj)' (where obj is the root of the hierarchy)
-# will generate a .ini file. See simple-4cpu.py for an example
-# (corresponding to m5-test/simple-4cpu.ini).
+# will generate a .ini file.
#
#####################################################################
-#####################################################################
-#
-# ConfigNode/SimObject classes
-#
-# The Python class hierarchy rooted by ConfigNode (which is the base
-# class of SimObject, which in turn is the base class of all other M5
-# SimObject classes) has special attribute behavior. In general, an
-# object in this hierarchy has three categories of attribute-like
-# things:
-#
-# 1. Regular Python methods and variables. These must start with an
-# underscore to be treated normally.
-#
-# 2. SimObject parameters. These values are stored as normal Python
-# attributes, but all assignments to these attributes are checked
-# against the pre-defined set of parameters stored in the class's
-# _params dictionary. Assignments to attributes that do not
-# correspond to predefined parameters, or that are not of the correct
-# type, incur runtime errors.
+# dict to look up SimObjects based on path
+instanceDict = {}
+
+#############################
#
-# 3. Hierarchy children. The child nodes of a ConfigNode are stored
-# in the node's _children dictionary, but can be accessed using the
-# Python attribute dot-notation (just as they are printed out by the
-# simulator). Children cannot be created using attribute assigment;
-# they must be added by specifying the parent node in the child's
-# constructor or using the '+=' operator.
-
-# The SimObject parameters are the most complex, for a few reasons.
-# First, both parameter descriptions and parameter values are
-# inherited. Thus parameter description lookup must go up the
-# inheritance chain like normal attribute lookup, but this behavior
-# must be explicitly coded since the lookup occurs in each class's
-# _params attribute. Second, because parameter values can be set
-# on SimObject classes (to implement default values), the parameter
-# checking behavior must be enforced on class attribute assignments as
-# well as instance attribute assignments. Finally, because we allow
-# class specialization via inheritance (e.g., see the L1Cache class in
-# the simple-4cpu.py example), we must do parameter checking even on
-# class instantiation. To provide all these features, we use a
-# metaclass to define most of the SimObject parameter behavior for
-# this class hierarchy.
+# Utility methods
#
-#####################################################################
+#############################
def isSimObject(value):
return isinstance(value, SimObject)
-def isSimObjSequence(value):
- if not isinstance(value, (list, tuple)):
+def isSimObjectSequence(value):
+ if not isinstance(value, (list, tuple)) or len(value) == 0:
return False
for val in value:
@@ -144,48 +110,76 @@ def isSimObjSequence(value):
return True
+def isSimObjectOrSequence(value):
+ return isSimObject(value) or isSimObjectSequence(value)
+
def isNullPointer(value):
return isinstance(value, NullSimObject)
-# The metaclass for ConfigNode (and thus for everything that derives
-# from ConfigNode, including SimObject). This class controls how new
-# classes that derive from ConfigNode are instantiated, and provides
-# inherited class behavior (just like a class controls how instances
-# of that class are instantiated, and provides inherited instance
-# behavior).
+# Apply method to object.
+# applyMethod(obj, 'meth', <args>) is equivalent to obj.meth(<args>)
+def applyMethod(obj, meth, *args, **kwargs):
+ return getattr(obj, meth)(*args, **kwargs)
+
+# If the first argument is an (non-sequence) object, apply the named
+# method with the given arguments. If the first argument is a
+# sequence, apply the method to each element of the sequence (a la
+# 'map').
+def applyOrMap(objOrSeq, meth, *args, **kwargs):
+ if not isinstance(objOrSeq, (list, tuple)):
+ return applyMethod(objOrSeq, meth, *args, **kwargs)
+ else:
+ return [applyMethod(o, meth, *args, **kwargs) for o in objOrSeq]
+
+
+# The metaclass for SimObject. This class controls how new classes
+# that derive from SimObject are instantiated, and provides inherited
+# class behavior (just like a class controls how instances of that
+# class are instantiated, and provides inherited instance behavior).
class MetaSimObject(type):
# Attributes that can be set only at initialization time
init_keywords = { 'abstract' : types.BooleanType,
'type' : types.StringType }
# Attributes that can be set any time
- keywords = { 'check' : types.FunctionType,
- 'children' : types.ListType }
+ keywords = { 'check' : types.FunctionType }
# __new__ is called before __init__, and is where the statements
# in the body of the class definition get loaded into the class's
- # __dict__. We intercept this to filter out parameter assignments
+ # __dict__. We intercept this to filter out parameter & port assignments
# and only allow "private" attributes to be passed to the base
# __new__ (starting with underscore).
def __new__(mcls, name, bases, dict):
- # Copy "private" attributes (including special methods such as __new__)
- # to the official dict. Everything else goes in _init_dict to be
+ # Copy "private" attributes, functions, and classes to the
+ # official dict. Everything else goes in _init_dict to be
# filtered in __init__.
cls_dict = {}
+ value_dict = {}
for key,val in dict.items():
- if key.startswith('_'):
+ if key.startswith('_') or isinstance(val, (types.FunctionType,
+ types.TypeType)):
cls_dict[key] = val
- del dict[key]
- cls_dict['_init_dict'] = dict
+ else:
+ # must be a param/port setting
+ value_dict[key] = val
+ cls_dict['_value_dict'] = value_dict
return super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
- # initialization
+ # subclass initialization
def __init__(cls, name, bases, dict):
+ # calls type.__init__()... I think that's a no-op, but leave
+ # it here just in case it's not.
super(MetaSimObject, cls).__init__(name, bases, dict)
# initialize required attributes
- cls._params = multidict()
- cls._values = multidict()
- cls._anon_subclass_counter = 0
+
+ # class-only attributes
+ cls._params = multidict() # param descriptions
+ cls._ports = multidict() # port descriptions
+
+ # class or instance attributes
+ cls._values = multidict() # param values
+ cls._port_map = multidict() # port bindings
+ cls._instantiated = False # really instantiated, cloned, or subclassed
# We don't support multiple inheritance. If you want to, you
# must fix multidict to deal with it properly.
@@ -194,35 +188,34 @@ class MetaSimObject(type):
base = bases[0]
+ # Set up general inheritance via multidicts. A subclass will
+ # inherit all its settings from the base class. The only time
+ # 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._params.parent = base._params
+ cls._ports.parent = base._ports
cls._values.parent = base._values
-
- # If your parent has a value in it that's a config node, clone
- # it. Do this now so if we update any of the values'
- # attributes we are updating the clone and not the original.
- for key,val in base._values.iteritems():
-
- # don't clone if (1) we're about to overwrite it with
- # a local setting or (2) we've already cloned a copy
- # from an earlier (more derived) base
- if cls._init_dict.has_key(key) or cls._values.has_key(key):
- continue
-
- if isSimObject(val):
- cls._values[key] = val()
- elif isSimObjSequence(val) and len(val):
- cls._values[key] = [ v() for v in val ]
-
- # now process remaining _init_dict items
- for key,val in cls._init_dict.items():
- if isinstance(val, (types.FunctionType, types.TypeType)):
- type.__setattr__(cls, key, val)
-
+ cls._port_map.parent = base._port_map
+ # mark base as having been subclassed
+ base._instantiated = True
+
+ # Now process the _value_dict items. They could be defining
+ # new (or overriding existing) parameters or ports, setting
+ # class keywords (e.g., 'abstract'), or setting parameter
+ # values or port bindings. The first 3 can only be set when
+ # the class is defined, so we handle them here. The others
+ # can be set later too, so just emulate that by calling
+ # setattr().
+ for key,val in cls._value_dict.items():
# param descriptions
- elif isinstance(val, ParamDesc):
+ if isinstance(val, ParamDesc):
cls._new_param(key, val)
+ # port objects
+ elif isinstance(val, Port):
+ cls._ports[key] = val
+
# init-time-only keywords
elif cls.init_keywords.has_key(key):
cls._set_keyword(key, val, cls.init_keywords[key])
@@ -256,10 +249,19 @@ class MetaSimObject(type):
cls._set_keyword(attr, value, cls.keywords[attr])
return
- # must be SimObject param
+ if cls._ports.has_key(attr):
+ self._ports[attr].connect(self, attr, value)
+ return
+
+ if isSimObjectOrSequence(value) and cls._instantiated:
+ raise RuntimeError, \
+ "cannot set SimObject parameter '%s' after\n" \
+ " class %s has been instantiated or subclassed" \
+ % (attr, cls.__name__)
+
+ # check for param
param = cls._params.get(attr, None)
if param:
- # It's ok: set attribute by delegating to 'object' class.
try:
cls._values[attr] = param.convert(value)
except Exception, e:
@@ -267,12 +269,12 @@ class MetaSimObject(type):
(e, cls.__name__, attr, value)
e.args = (msg, )
raise
- # I would love to get rid of this
- elif isSimObject(value) or isSimObjSequence(value):
- cls._values[attr] = value
+ elif isSimObjectOrSequence(value):
+ # if RHS is a SimObject, it's an implicit child assignment
+ cls._values[attr] = value
else:
raise AttributeError, \
- "Class %s has no parameter %s" % (cls.__name__, attr)
+ "Class %s has no parameter \'%s\'" % (cls.__name__, attr)
def __getattr__(cls, attr):
if cls._values.has_key(attr):
@@ -281,7 +283,7 @@ class MetaSimObject(type):
raise AttributeError, \
"object '%s' has no attribute '%s'" % (cls.__name__, attr)
-# The ConfigNode class is the root of the special hierarchy. Most of
+# The SimObject class is the root of the special hierarchy. Most of
# the code in this class deals with the configuration hierarchy itself
# (parent/child node relationships).
class SimObject(object):
@@ -289,29 +291,79 @@ class SimObject(object):
# get this metaclass.
__metaclass__ = MetaSimObject
- def __init__(self, _value_parent = None, **kwargs):
+ # Initialize new instance. For objects with SimObject-valued
+ # children, we need to recursively clone the classes represented
+ # by those param values as well in a consistent "deep copy"-style
+ # fashion. That is, we want to make sure that each instance is
+ # cloned only once, and that if there are multiple references to
+ # the same original object, we end up with the corresponding
+ # cloned references all pointing to the same cloned instance.
+ def __init__(self, **kwargs):
+ ancestor = kwargs.get('_ancestor')
+ memo_dict = kwargs.get('_memo')
+ if memo_dict is None:
+ # prepare to memoize any recursively instantiated objects
+ memo_dict = {}
+ elif ancestor:
+ # memoize me now to avoid problems with recursive calls
+ memo_dict[ancestor] = self
+
+ if not ancestor:
+ ancestor = self.__class__
+ ancestor._instantiated = True
+
+ # initialize required attributes
+ self._parent = None
self._children = {}
- if _value_parent and type(_value_parent) != type(self):
- # this was called as a type conversion rather than a clone
- raise TypeError, "Cannot convert %s to %s" % \
- (_value_parent.__class__.__name__, self.__class__.__name__)
- if not _value_parent:
- _value_parent = self.__class__
- # clone values
- self._values = multidict(_value_parent._values)
- for key,val in _value_parent._values.iteritems():
+ self._ccObject = None # pointer to C++ object
+ self._instantiated = False # really "cloned"
+
+ # Inherit parameter values from class using multidict so
+ # individual value settings can be overridden.
+ self._values = multidict(ancestor._values)
+ # clone SimObject-valued parameters
+ for key,val in ancestor._values.iteritems():
if isSimObject(val):
- setattr(self, key, val())
- elif isSimObjSequence(val) and len(val):
- setattr(self, key, [ v() for v in val ])
+ setattr(self, key, val(_memo=memo_dict))
+ elif isSimObjectSequence(val) and len(val):
+ setattr(self, key, [ v(_memo=memo_dict) for v in val ])
+ # clone port references. no need to use a multidict here
+ # since we will be creating new references for all ports.
+ self._port_map = {}
+ for key,val in ancestor._port_map.iteritems():
+ self._port_map[key] = applyOrMap(val, 'clone', memo_dict)
# apply attribute assignments from keyword args, if any
for key,val in kwargs.iteritems():
setattr(self, key, val)
+ # "Clone" the current instance by creating another instance of
+ # this instance's class, but that inherits its parameter values
+ # and port mappings from the current instance. If we're in a
+ # "deep copy" recursive clone, check the _memo dict to see if
+ # we've already cloned this instance.
def __call__(self, **kwargs):
- return self.__class__(_value_parent = self, **kwargs)
+ memo_dict = kwargs.get('_memo')
+ if memo_dict is None:
+ # no memo_dict: must be top-level clone operation.
+ # this is only allowed at the root of a hierarchy
+ if self._parent:
+ raise RuntimeError, "attempt to clone object %s " \
+ "not at the root of a tree (parent = %s)" \
+ % (self, self._parent)
+ # create a new dict and use that.
+ memo_dict = {}
+ kwargs['_memo'] = memo_dict
+ elif memo_dict.has_key(self):
+ # clone already done & memoized
+ return memo_dict[self]
+ return self.__class__(_ancestor = self, **kwargs)
def __getattr__(self, attr):
+ if self._ports.has_key(attr):
+ # return reference that can be assigned to another port
+ # via __setattr__
+ return self._ports[attr].makeRef(self, attr)
+
if self._values.has_key(attr):
return self._values[attr]
@@ -326,10 +378,19 @@ class SimObject(object):
object.__setattr__(self, attr, value)
return
+ if self._ports.has_key(attr):
+ # set up port connection
+ self._ports[attr].connect(self, attr, value)
+ return
+
+ if isSimObjectOrSequence(value) and self._instantiated:
+ raise RuntimeError, \
+ "cannot set SimObject parameter '%s' after\n" \
+ " instance been cloned %s" % (attr, `self`)
+
# must be SimObject param
param = self._params.get(attr, None)
if param:
- # It's ok: set attribute by delegating to 'object' class.
try:
value = param.convert(value)
except Exception, e:
@@ -337,8 +398,7 @@ class SimObject(object):
(e, self.__class__.__name__, attr, value)
e.args = (msg, )
raise
- # I would love to get rid of this
- elif isSimObject(value) or isSimObjSequence(value):
+ elif isSimObjectOrSequence(value):
pass
else:
raise AttributeError, "Class %s has no parameter %s" \
@@ -349,7 +409,7 @@ class SimObject(object):
if isSimObject(value):
value.set_path(self, attr)
- elif isSimObjSequence(value):
+ elif isSimObjectSequence(value):
value = SimObjVector(value)
[v.set_path(self, "%s%d" % (attr, i)) for i,v in enumerate(value)]
@@ -376,13 +436,13 @@ class SimObject(object):
self._children[name] = value
def set_path(self, parent, name):
- if not hasattr(self, '_parent'):
+ if not self._parent:
self._parent = parent
self._name = name
parent.add_child(name, self)
def path(self):
- if not hasattr(self, '_parent'):
+ if not self._parent:
return 'root'
ppath = self._parent.path()
if ppath == 'root':
@@ -423,6 +483,8 @@ class SimObject(object):
def print_ini(self):
print '[' + self.path() + ']' # .ini section header
+ instanceDict[self.path()] = self
+
if hasattr(self, 'type') and not isinstance(self, ParamContext):
print 'type=%s' % self.type
@@ -454,6 +516,60 @@ class SimObject(object):
for child in child_names:
self._children[child].print_ini()
+ # Call C++ to create C++ object corresponding to this object and
+ # (recursively) all its children
+ def createCCObject(self):
+ self.getCCObject() # force creation
+ for child in self._children.itervalues():
+ child.createCCObject()
+
+ # Get C++ object corresponding to this object, calling C++ if
+ # necessary to construct it. Does *not* recursively create
+ # children.
+ def getCCObject(self):
+ if not self._ccObject:
+ self._ccObject = -1 # flag to catch cycles in recursion
+ self._ccObject = cc_main.createSimObject(self.path())
+ elif self._ccObject == -1:
+ raise RuntimeError, "%s: recursive call to getCCObject()" \
+ % self.path()
+ return self._ccObject
+
+ # Create C++ port connections corresponding to the connections in
+ # _port_map (& recursively for all children)
+ def connectPorts(self):
+ for portRef in self._port_map.itervalues():
+ applyOrMap(portRef, 'ccConnect')
+ for child in self._children.itervalues():
+ child.connectPorts()
+
+ def startQuiesce(self, quiesce_event, recursive):
+ count = 0
+ # ParamContexts don't serialize
+ if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+ if self._ccObject.quiesce(quiesce_event):
+ count = 1
+ if recursive:
+ for child in self._children.itervalues():
+ count += child.startQuiesce(quiesce_event, True)
+ return count
+
+ def resume(self):
+ if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+ self._ccObject.resume()
+ for child in self._children.itervalues():
+ child.resume()
+
+ def changeTiming(self, mode):
+ if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+ self._ccObject.setMemoryMode(mode)
+ for child in self._children.itervalues():
+ child.changeTiming(mode)
+
+ def takeOverFrom(self, old_cpu):
+ cpu_ptr = cc_main.convertToBaseCPUPtr(old_cpu._ccObject)
+ self._ccObject.takeOverFrom(cpu_ptr)
+
# generate output file for 'dot' to display as a pretty graph.
# this code is currently broken.
def outputDot(self, dot):
@@ -544,9 +660,9 @@ class BaseProxy(object):
if self._search_up:
while not done:
- try: obj = obj._parent
- except: break
-
+ obj = obj._parent
+ if not obj:
+ break
result, done = self.find(obj)
if not done:
@@ -662,16 +778,16 @@ Self = ProxyFactory(search_self = True, search_up = False)
#
# Parameter description classes
#
-# The _params dictionary in each class maps parameter names to
-# either a Param or a VectorParam object. These objects contain the
+# The _params dictionary in each class maps parameter names to either
+# a Param or a VectorParam object. These objects contain the
# parameter description string, the parameter type, and the default
-# value (loaded from the PARAM section of the .odesc files). The
-# _convert() method on these objects is used to force whatever value
-# is assigned to the parameter to the appropriate type.
+# value (if any). The convert() method on these objects is used to
+# force whatever value is assigned to the parameter to the appropriate
+# type.
#
# Note that the default values are loaded into the class's attribute
# space when the parameter dictionary is initialized (in
-# MetaConfigNode._setparams()); after that point they aren't used.
+# MetaSimObject._new_param()); after that point they aren't used.
#
#####################################################################
@@ -725,7 +841,7 @@ class ParamDesc(object):
def __getattr__(self, attr):
if attr == 'ptype':
try:
- ptype = eval(self.ptype_str, m5.__dict__)
+ ptype = eval(self.ptype_str, m5.objects.__dict__)
if not isinstance(ptype, type):
panic("Param qualifier is not a type: %s" % self.ptype)
self.ptype = ptype
@@ -772,7 +888,7 @@ class VectorParamDesc(ParamDesc):
if isinstance(value, (list, tuple)):
# list: coerce each element into new list
tmp_list = [ ParamDesc.convert(self, v) for v in value ]
- if isSimObjSequence(tmp_list):
+ if isSimObjectSequence(tmp_list):
return SimObjVector(tmp_list)
else:
return VectorParamValue(tmp_list)
@@ -794,7 +910,7 @@ class ParamFactory(object):
# E.g., Param.Int(5, "number of widgets")
def __call__(self, *args, **kwargs):
- caller_frame = inspect.stack()[1][0]
+ caller_frame = inspect.currentframe().f_back
ptype = None
try:
ptype = eval(self.ptype_str,
@@ -1066,7 +1182,10 @@ class EthernetAddr(ParamValue):
def __str__(self):
if self.value == NextEthernetAddr:
- return self.addr
+ if hasattr(self, 'addr'):
+ return self.addr
+ else:
+ return "NextEthernetAddr (unresolved)"
else:
return self.value
@@ -1285,24 +1404,108 @@ MaxAddr = Addr.max
MaxTick = Tick.max
AllMemory = AddrRange(0, MaxAddr)
+
+#####################################################################
+#
+# Port objects
+#
+# Ports are used to interconnect objects in the memory system.
+#
#####################################################################
-# The final hook to generate .ini files. Called from configuration
-# script once config is built.
-def instantiate(root):
- global ticks_per_sec
- ticks_per_sec = float(root.clock.frequency)
- root.print_ini()
- noDot = True # temporary until we fix dot
- if not noDot:
- dot = pydot.Dot()
- instance.outputDot(dot)
- dot.orientation = "portrait"
- dot.size = "8.5,11"
- dot.ranksep="equally"
- dot.rank="samerank"
- dot.write("config.dot")
- dot.write_ps("config.ps")
+# Port reference: encapsulates a reference to a particular port on a
+# particular SimObject.
+class PortRef(object):
+ def __init__(self, simobj, name, isVec):
+ assert(isSimObject(simobj))
+ self.simobj = simobj
+ self.name = name
+ self.index = -1
+ self.isVec = isVec # is this a vector port?
+ self.peer = None # not associated with another port yet
+ self.ccConnected = False # C++ port connection done?
+
+ # Set peer port reference. Called via __setattr__ as a result of
+ # a port assignment, e.g., "obj1.port1 = obj2.port2".
+ def setPeer(self, other):
+ if self.isVec:
+ curMap = self.simobj._port_map.get(self.name, [])
+ self.index = len(curMap)
+ curMap.append(other)
+ else:
+ curMap = self.simobj._port_map.get(self.name)
+ if curMap and not self.isVec:
+ print "warning: overwriting port", self.simobj, self.name
+ curMap = other
+ self.simobj._port_map[self.name] = curMap
+ self.peer = other
+
+ def clone(self, memo):
+ newRef = copy.copy(self)
+ assert(isSimObject(newRef.simobj))
+ newRef.simobj = newRef.simobj(_memo=memo)
+ # Tricky: if I'm the *second* PortRef in the pair to be
+ # cloned, then my peer is still in the middle of its clone
+ # method, and thus hasn't returned to its owner's
+ # SimObject.__init__ to get installed in _port_map. As a
+ # result I have no way of finding the *new* peer object. So I
+ # mark myself as "waiting" for my peer, and I let the *first*
+ # PortRef clone call set up both peer pointers after I return.
+ newPeer = newRef.simobj._port_map.get(self.name)
+ if newPeer:
+ if self.isVec:
+ assert(self.index != -1)
+ newPeer = newPeer[self.index]
+ # other guy is all set up except for his peer pointer
+ assert(newPeer.peer == -1) # peer must be waiting for handshake
+ newPeer.peer = newRef
+ newRef.peer = newPeer
+ else:
+ # other guy is in clone; just wait for him to do the work
+ newRef.peer = -1 # mark as waiting for handshake
+ return newRef
+
+ # Call C++ to create corresponding port connection between C++ objects
+ def ccConnect(self):
+ if self.ccConnected: # already done this
+ return
+ peer = self.peer
+ cc_main.connectPorts(self.simobj.getCCObject(), self.name, self.index,
+ peer.simobj.getCCObject(), peer.name, peer.index)
+ self.ccConnected = True
+ peer.ccConnected = True
+
+# Port description object. Like a ParamDesc object, this represents a
+# logical port in the SimObject class, not a particular port on a
+# SimObject instance. The latter are represented by PortRef objects.
+class Port(object):
+ def __init__(self, desc):
+ self.desc = desc
+ self.isVec = False
+
+ # Generate a PortRef for this port on the given SimObject with the
+ # given name
+ def makeRef(self, simobj, name):
+ return PortRef(simobj, name, self.isVec)
+
+ # Connect an instance of this port (on the given SimObject with
+ # the given name) with the port described by the supplied PortRef
+ def connect(self, simobj, name, ref):
+ if not isinstance(ref, PortRef):
+ raise TypeError, \
+ "assigning non-port reference port '%s'" % name
+ myRef = self.makeRef(simobj, name)
+ myRef.setPeer(ref)
+ ref.setPeer(myRef)
+
+# VectorPort description object. Like Port, but represents a vector
+# of connections (e.g., as on a Bus).
+class VectorPort(Port):
+ def __init__(self, desc):
+ Port.__init__(self, desc)
+ self.isVec = True
+
+#####################################################################
# __all__ defines the list of symbols that get exported when
# 'from config import *' is invoked. Try to keep this reasonably
@@ -1319,5 +1522,6 @@ __all__ = ['SimObject', 'ParamContext', 'Param', 'VectorParam',
'NetworkBandwidth', 'MemoryBandwidth',
'Range', 'AddrRange', 'MaxAddr', 'MaxTick', 'AllMemory',
'Null', 'NULL',
- 'NextEthernetAddr', 'instantiate']
+ 'NextEthernetAddr',
+ 'Port', 'VectorPort']
diff --git a/src/python/m5/convert.py b/src/python/m5/convert.py
index 73181e985..580a579bc 100644
--- a/src/python/m5/convert.py
+++ b/src/python/m5/convert.py
@@ -23,6 +23,8 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
# metric prefixes
exa = 1.0e18
diff --git a/src/python/m5/multidict.py b/src/python/m5/multidict.py
index fd40ebbbd..34fc3139b 100644
--- a/src/python/m5/multidict.py
+++ b/src/python/m5/multidict.py
@@ -23,13 +23,15 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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__ = [ 'multidict' ]
class multidict(object):
__nodefault = object()
def __init__(self, parent = {}, **kwargs):
- self.dict = dict(**kwargs)
+ self.local = dict(**kwargs)
self.parent = parent
self.deleted = {}
@@ -40,11 +42,11 @@ class multidict(object):
return `dict(self.items())`
def __contains__(self, key):
- return self.dict.has_key(key) or self.parent.has_key(key)
+ return self.local.has_key(key) or self.parent.has_key(key)
def __delitem__(self, key):
try:
- del self.dict[key]
+ del self.local[key]
except KeyError, e:
if key in self.parent:
self.deleted[key] = True
@@ -53,11 +55,11 @@ class multidict(object):
def __setitem__(self, key, value):
self.deleted.pop(key, False)
- self.dict[key] = value
+ self.local[key] = value
def __getitem__(self, key):
try:
- return self.dict[key]
+ return self.local[key]
except KeyError, e:
if not self.deleted.get(key, False) and key in self.parent:
return self.parent[key]
@@ -65,15 +67,15 @@ class multidict(object):
raise KeyError, e
def __len__(self):
- return len(self.dict) + len(self.parent)
+ return len(self.local) + len(self.parent)
def next(self):
- for key,value in self.dict.items():
+ for key,value in self.local.items():
yield key,value
if self.parent:
for key,value in self.parent.next():
- if key not in self.dict and key not in self.deleted:
+ if key not in self.local and key not in self.deleted:
yield key,value
def has_key(self, key):
@@ -114,22 +116,22 @@ class multidict(object):
return self[key]
except KeyError:
self.deleted.pop(key, False)
- self.dict[key] = default
+ self.local[key] = default
return default
def _dump(self):
print 'multidict dump'
node = self
while isinstance(node, multidict):
- print ' ', node.dict
+ print ' ', node.local
node = node.parent
def _dumpkey(self, key):
values = []
node = self
while isinstance(node, multidict):
- if key in node.dict:
- values.append(node.dict[key])
+ if key in node.local:
+ values.append(node.local[key])
node = node.parent
print key, values
diff --git a/src/python/m5/objects/AlphaConsole.py b/src/python/m5/objects/AlphaConsole.py
index 68e6089ab..329b8c5bd 100644
--- a/src/python/m5/objects/AlphaConsole.py
+++ b/src/python/m5/objects/AlphaConsole.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Device import BasicPioDevice
class AlphaConsole(BasicPioDevice):
diff --git a/src/python/m5/objects/AlphaTLB.py b/src/python/m5/objects/AlphaTLB.py
index 5edf8e13d..11c1792ee 100644
--- a/src/python/m5/objects/AlphaTLB.py
+++ b/src/python/m5/objects/AlphaTLB.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class AlphaTLB(SimObject):
type = 'AlphaTLB'
abstract = True
diff --git a/src/python/m5/objects/BadDevice.py b/src/python/m5/objects/BadDevice.py
index 9cb9a8f03..186b733fa 100644
--- a/src/python/m5/objects/BadDevice.py
+++ b/src/python/m5/objects/BadDevice.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Device import BasicPioDevice
class BadDevice(BasicPioDevice):
diff --git a/src/python/m5/objects/BaseCPU.py b/src/python/m5/objects/BaseCPU.py
index 49cb2a8f3..2e78578df 100644
--- a/src/python/m5/objects/BaseCPU.py
+++ b/src/python/m5/objects/BaseCPU.py
@@ -1,4 +1,6 @@
-from m5 import *
+from m5 import build_env
+from m5.config import *
+
class BaseCPU(SimObject):
type = 'BaseCPU'
abstract = True
diff --git a/src/python/m5/objects/BaseCache.py b/src/python/m5/objects/BaseCache.py
index 79d21572a..497b2b038 100644
--- a/src/python/m5/objects/BaseCache.py
+++ b/src/python/m5/objects/BaseCache.py
@@ -1,29 +1,26 @@
-from m5 import *
-from BaseMem import BaseMem
+from m5.config import *
+from MemObject import MemObject
class Prefetch(Enum): vals = ['none', 'tagged', 'stride', 'ghb']
-class BaseCache(BaseMem):
+class BaseCache(MemObject):
type = 'BaseCache'
adaptive_compression = Param.Bool(False,
"Use an adaptive compression scheme")
assoc = Param.Int("associativity")
block_size = Param.Int("block size in bytes")
+ latency = Param.Int("Latency")
compressed_bus = Param.Bool(False,
"This cache connects to a compressed memory")
compression_latency = Param.Latency('0ns',
"Latency in cycles of compression algorithm")
do_copy = Param.Bool(False, "perform fast copies in the cache")
hash_delay = Param.Int(1, "time in cycles of hash access")
- in_bus = Param.Bus(NULL, "incoming bus object")
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")
- mem_trace = Param.MemTraceWriter(NULL,
- "memory trace writer to record accesses")
mshrs = Param.Int("number of MSHRs (max outstanding requests)")
- out_bus = Param.Bus("outgoing bus object")
prioritizeRequests = Param.Bool(False,
"always service demand misses first")
protocol = Param.CoherenceProtocol(NULL, "coherence protocol to use")
@@ -63,3 +60,6 @@ class BaseCache(BaseMem):
"Use the CPU ID to seperate calculations of prefetches")
prefetch_data_accesses_only = Param.Bool(False,
"Only prefetch on data not on instruction accesses")
+ hit_latency = Param.Int(1,"Hit Latency of the cache")
+ cpu_side = Port("Port on side closer to CPU")
+ mem_side = Port("Port on side closer to MEM")
diff --git a/src/python/m5/objects/Bridge.py b/src/python/m5/objects/Bridge.py
index ada715ce9..c9e673afb 100644
--- a/src/python/m5/objects/Bridge.py
+++ b/src/python/m5/objects/Bridge.py
@@ -1,8 +1,10 @@
-from m5 import *
+from m5.config import *
from MemObject import MemObject
class Bridge(MemObject):
type = 'Bridge'
+ side_a = Port('Side A port')
+ side_b = Port('Side B port')
queue_size_a = Param.Int(16, "The number of requests to buffer")
queue_size_b = Param.Int(16, "The number of requests to buffer")
delay = Param.Latency('0ns', "The latency of this bridge")
diff --git a/src/python/m5/objects/Bus.py b/src/python/m5/objects/Bus.py
index 8c5397281..019e15034 100644
--- a/src/python/m5/objects/Bus.py
+++ b/src/python/m5/objects/Bus.py
@@ -1,6 +1,7 @@
-from m5 import *
+from m5.config import *
from MemObject import MemObject
class Bus(MemObject):
type = 'Bus'
+ port = VectorPort("vector port for connecting devices")
bus_id = Param.Int(0, "blah")
diff --git a/src/python/m5/objects/CoherenceProtocol.py b/src/python/m5/objects/CoherenceProtocol.py
index 7013000d6..64b6cbacf 100644
--- a/src/python/m5/objects/CoherenceProtocol.py
+++ b/src/python/m5/objects/CoherenceProtocol.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class Coherence(Enum): vals = ['uni', 'msi', 'mesi', 'mosi', 'moesi']
class CoherenceProtocol(SimObject):
diff --git a/src/python/m5/objects/Device.py b/src/python/m5/objects/Device.py
index 2a71bbc65..222f750da 100644
--- a/src/python/m5/objects/Device.py
+++ b/src/python/m5/objects/Device.py
@@ -1,9 +1,10 @@
-from m5 import *
+from m5.config import *
from MemObject import MemObject
class PioDevice(MemObject):
type = 'PioDevice'
abstract = True
+ pio = Port("Programmed I/O port")
platform = Param.Platform(Parent.any, "Platform this device is part of")
system = Param.System(Parent.any, "System this device is part of")
@@ -16,3 +17,4 @@ class BasicPioDevice(PioDevice):
class DmaDevice(PioDevice):
type = 'DmaDevice'
abstract = True
+ dma = Port("DMA port")
diff --git a/src/python/m5/objects/DiskImage.py b/src/python/m5/objects/DiskImage.py
index 0d55e9329..70d8b2e45 100644
--- a/src/python/m5/objects/DiskImage.py
+++ b/src/python/m5/objects/DiskImage.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class DiskImage(SimObject):
type = 'DiskImage'
abstract = True
diff --git a/src/python/m5/objects/Ethernet.py b/src/python/m5/objects/Ethernet.py
index 4286c71c8..418670592 100644
--- a/src/python/m5/objects/Ethernet.py
+++ b/src/python/m5/objects/Ethernet.py
@@ -1,4 +1,5 @@
-from m5 import *
+from m5 import build_env
+from m5.config import *
from Device import DmaDevice
from Pci import PciDevice
diff --git a/src/python/m5/objects/FUPool.py b/src/python/m5/objects/FUPool.py
new file mode 100644
index 000000000..cbf1089cf
--- /dev/null
+++ b/src/python/m5/objects/FUPool.py
@@ -0,0 +1,5 @@
+from m5.config import *
+
+class FUPool(SimObject):
+ type = 'FUPool'
+ FUList = VectorParam.FUDesc("list of FU's for this pool")
diff --git a/src/python/m5/objects/FuncUnit.py b/src/python/m5/objects/FuncUnit.py
new file mode 100644
index 000000000..f61590ae9
--- /dev/null
+++ b/src/python/m5/objects/FuncUnit.py
@@ -0,0 +1,17 @@
+from m5.config import *
+
+class OpType(Enum):
+ vals = ['(null)', 'IntAlu', 'IntMult', 'IntDiv', 'FloatAdd',
+ 'FloatCmp', 'FloatCvt', 'FloatMult', 'FloatDiv', 'FloatSqrt',
+ 'MemRead', 'MemWrite', 'IprAccess', 'InstPrefetch']
+
+class OpDesc(SimObject):
+ type = 'OpDesc'
+ issueLat = Param.Int(1, "cycles until another can be issued")
+ opClass = Param.OpType("type of operation")
+ opLat = Param.Int(1, "cycles until result is available")
+
+class FUDesc(SimObject):
+ type = 'FUDesc'
+ count = Param.Int("number of these FU's available")
+ opList = VectorParam.OpDesc("operation classes for this FU type")
diff --git a/src/python/m5/objects/Ide.py b/src/python/m5/objects/Ide.py
index 2403e6d36..9ee578177 100644
--- a/src/python/m5/objects/Ide.py
+++ b/src/python/m5/objects/Ide.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Pci import PciDevice
class IdeID(Enum): vals = ['master', 'slave']
diff --git a/src/python/m5/objects/IntrControl.py b/src/python/m5/objects/IntrControl.py
index 66c82c182..514c3fc62 100644
--- a/src/python/m5/objects/IntrControl.py
+++ b/src/python/m5/objects/IntrControl.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class IntrControl(SimObject):
type = 'IntrControl'
cpu = Param.BaseCPU(Parent.any, "the cpu")
diff --git a/src/python/m5/objects/MemObject.py b/src/python/m5/objects/MemObject.py
index 4d68243e6..d957dae17 100644
--- a/src/python/m5/objects/MemObject.py
+++ b/src/python/m5/objects/MemObject.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class MemObject(SimObject):
type = 'MemObject'
diff --git a/src/python/m5/objects/MemTest.py b/src/python/m5/objects/MemTest.py
index 34299faf0..9916d7cb4 100644
--- a/src/python/m5/objects/MemTest.py
+++ b/src/python/m5/objects/MemTest.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class MemTest(SimObject):
type = 'MemTest'
cache = Param.BaseCache("L1 cache")
diff --git a/src/python/m5/objects/O3CPU.py b/src/python/m5/objects/O3CPU.py
new file mode 100644
index 000000000..4ecfa8fbd
--- /dev/null
+++ b/src/python/m5/objects/O3CPU.py
@@ -0,0 +1,98 @@
+from m5 import build_env
+from m5.config import *
+from BaseCPU import BaseCPU
+
+class DerivO3CPU(BaseCPU):
+ type = 'DerivO3CPU'
+ activity = Param.Unsigned("Initial count")
+ numThreads = Param.Unsigned("number of HW thread contexts")
+
+ checker = Param.BaseCPU(NULL, "checker")
+
+ cachePorts = Param.Unsigned("Cache Ports")
+
+ decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
+ renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
+ iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch "
+ "delay")
+ commitToFetchDelay = Param.Unsigned("Commit to fetch delay")
+ fetchWidth = Param.Unsigned("Fetch width")
+
+ renameToDecodeDelay = Param.Unsigned("Rename to decode delay")
+ iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode "
+ "delay")
+ commitToDecodeDelay = Param.Unsigned("Commit to decode delay")
+ fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay")
+ decodeWidth = Param.Unsigned("Decode width")
+
+ iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename "
+ "delay")
+ commitToRenameDelay = Param.Unsigned("Commit to rename delay")
+ decodeToRenameDelay = Param.Unsigned("Decode to rename delay")
+ renameWidth = Param.Unsigned("Rename width")
+
+ commitToIEWDelay = Param.Unsigned("Commit to "
+ "Issue/Execute/Writeback delay")
+ renameToIEWDelay = Param.Unsigned("Rename to "
+ "Issue/Execute/Writeback delay")
+ issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal "
+ "to the IEW stage)")
+ issueWidth = Param.Unsigned("Issue width")
+ executeWidth = Param.Unsigned("Execute width")
+ executeIntWidth = Param.Unsigned("Integer execute width")
+ executeFloatWidth = Param.Unsigned("Floating point execute width")
+ executeBranchWidth = Param.Unsigned("Branch execute width")
+ executeMemoryWidth = Param.Unsigned("Memory execute width")
+ fuPool = Param.FUPool(NULL, "Functional Unit pool")
+
+ iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit "
+ "delay")
+ renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay")
+ commitWidth = Param.Unsigned("Commit width")
+ squashWidth = Param.Unsigned("Squash width")
+ trapLatency = Param.Tick("Trap latency")
+ fetchTrapLatency = Param.Tick("Fetch trap latency")
+
+ predType = Param.String("Branch predictor type ('local', 'tournament')")
+ localPredictorSize = Param.Unsigned("Size of local predictor")
+ localCtrBits = Param.Unsigned("Bits per counter")
+ localHistoryTableSize = Param.Unsigned("Size of local history table")
+ localHistoryBits = Param.Unsigned("Bits for the local history")
+ globalPredictorSize = Param.Unsigned("Size of global predictor")
+ globalCtrBits = Param.Unsigned("Bits per counter")
+ globalHistoryBits = Param.Unsigned("Bits of history")
+ choicePredictorSize = Param.Unsigned("Size of choice predictor")
+ choiceCtrBits = Param.Unsigned("Bits of choice counters")
+
+ BTBEntries = Param.Unsigned("Number of BTB entries")
+ BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits")
+
+ RASSize = Param.Unsigned("RAS size")
+
+ LQEntries = Param.Unsigned("Number of load queue entries")
+ SQEntries = Param.Unsigned("Number of store queue entries")
+ LFSTSize = Param.Unsigned("Last fetched store table size")
+ SSITSize = Param.Unsigned("Store set ID table size")
+
+ numRobs = Param.Unsigned("Number of Reorder Buffers");
+
+ numPhysIntRegs = Param.Unsigned("Number of physical integer registers")
+ numPhysFloatRegs = Param.Unsigned("Number of physical floating point "
+ "registers")
+ numIQEntries = Param.Unsigned("Number of instruction queue entries")
+ numROBEntries = Param.Unsigned("Number of reorder buffer entries")
+
+ instShiftAmt = Param.Unsigned("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("SMT Number of Fetching Threads")
+ smtFetchPolicy = Param.String("SMT Fetch policy")
+ smtLSQPolicy = Param.String("SMT LSQ Sharing Policy")
+ smtLSQThreshold = Param.String("SMT LSQ Threshold Sharing Parameter")
+ smtIQPolicy = Param.String("SMT IQ Sharing Policy")
+ smtIQThreshold = Param.String("SMT IQ Threshold Sharing Parameter")
+ smtROBPolicy = Param.String("SMT ROB Sharing Policy")
+ smtROBThreshold = Param.String("SMT ROB Threshold Sharing Parameter")
+ smtCommitPolicy = Param.String("SMT Commit Policy")
diff --git a/src/python/m5/objects/OzoneCPU.py b/src/python/m5/objects/OzoneCPU.py
new file mode 100644
index 000000000..8aff89203
--- /dev/null
+++ b/src/python/m5/objects/OzoneCPU.py
@@ -0,0 +1,88 @@
+from m5 import build_env
+from m5.config import *
+from BaseCPU import BaseCPU
+
+class DerivOzoneCPU(BaseCPU):
+ type = 'DerivOzoneCPU'
+
+ numThreads = Param.Unsigned("number of HW thread contexts")
+
+ checker = Param.BaseCPU("Checker CPU")
+
+ width = Param.Unsigned("Width")
+ frontEndWidth = Param.Unsigned("Front end width")
+ backEndWidth = Param.Unsigned("Back end width")
+ backEndSquashLatency = Param.Unsigned("Back end squash latency")
+ backEndLatency = Param.Unsigned("Back end latency")
+ maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size")
+ maxOutstandingMemOps = Param.Unsigned("Maximum number of outstanding memory operations")
+ decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
+ renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
+ iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch "
+ "delay")
+ commitToFetchDelay = Param.Unsigned("Commit to fetch delay")
+ fetchWidth = Param.Unsigned("Fetch width")
+
+ renameToDecodeDelay = Param.Unsigned("Rename to decode delay")
+ iewToDecodeDelay = Param.Unsigned("Issue/Execute/Writeback to decode "
+ "delay")
+ commitToDecodeDelay = Param.Unsigned("Commit to decode delay")
+ fetchToDecodeDelay = Param.Unsigned("Fetch to decode delay")
+ decodeWidth = Param.Unsigned("Decode width")
+
+ iewToRenameDelay = Param.Unsigned("Issue/Execute/Writeback to rename "
+ "delay")
+ commitToRenameDelay = Param.Unsigned("Commit to rename delay")
+ decodeToRenameDelay = Param.Unsigned("Decode to rename delay")
+ renameWidth = Param.Unsigned("Rename width")
+
+ commitToIEWDelay = Param.Unsigned("Commit to "
+ "Issue/Execute/Writeback delay")
+ renameToIEWDelay = Param.Unsigned("Rename to "
+ "Issue/Execute/Writeback delay")
+ issueToExecuteDelay = Param.Unsigned("Issue to execute delay (internal "
+ "to the IEW stage)")
+ issueWidth = Param.Unsigned("Issue width")
+ executeWidth = Param.Unsigned("Execute width")
+ executeIntWidth = Param.Unsigned("Integer execute width")
+ executeFloatWidth = Param.Unsigned("Floating point execute width")
+ executeBranchWidth = Param.Unsigned("Branch execute width")
+ executeMemoryWidth = Param.Unsigned("Memory execute width")
+
+ iewToCommitDelay = Param.Unsigned("Issue/Execute/Writeback to commit "
+ "delay")
+ renameToROBDelay = Param.Unsigned("Rename to reorder buffer delay")
+ commitWidth = Param.Unsigned("Commit width")
+ squashWidth = Param.Unsigned("Squash width")
+
+ predType = Param.String("Type of branch predictor ('local', 'tournament')")
+ localPredictorSize = Param.Unsigned("Size of local predictor")
+ localCtrBits = Param.Unsigned("Bits per counter")
+ localHistoryTableSize = Param.Unsigned("Size of local history table")
+ localHistoryBits = Param.Unsigned("Bits for the local history")
+ globalPredictorSize = Param.Unsigned("Size of global predictor")
+ globalCtrBits = Param.Unsigned("Bits per counter")
+ globalHistoryBits = Param.Unsigned("Bits of history")
+ choicePredictorSize = Param.Unsigned("Size of choice predictor")
+ choiceCtrBits = Param.Unsigned("Bits of choice counters")
+
+ BTBEntries = Param.Unsigned("Number of BTB entries")
+ BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits")
+
+ RASSize = Param.Unsigned("RAS size")
+
+ LQEntries = Param.Unsigned("Number of load queue entries")
+ SQEntries = Param.Unsigned("Number of store queue entries")
+ LFSTSize = Param.Unsigned("Last fetched store table size")
+ SSITSize = Param.Unsigned("Store set ID table size")
+
+ numPhysIntRegs = Param.Unsigned("Number of physical integer registers")
+ numPhysFloatRegs = Param.Unsigned("Number of physical floating point "
+ "registers")
+ numIQEntries = Param.Unsigned("Number of instruction queue entries")
+ numROBEntries = Param.Unsigned("Number of reorder buffer entries")
+
+ instShiftAmt = Param.Unsigned("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")
diff --git a/src/python/m5/objects/Pci.py b/src/python/m5/objects/Pci.py
index 85cefcd44..9e1e91b13 100644
--- a/src/python/m5/objects/Pci.py
+++ b/src/python/m5/objects/Pci.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Device import BasicPioDevice, DmaDevice
class PciConfigData(SimObject):
diff --git a/src/python/m5/objects/PhysicalMemory.py b/src/python/m5/objects/PhysicalMemory.py
index c59910093..9cc7510a2 100644
--- a/src/python/m5/objects/PhysicalMemory.py
+++ b/src/python/m5/objects/PhysicalMemory.py
@@ -1,8 +1,9 @@
-from m5 import *
+from m5.config import *
from MemObject import *
class PhysicalMemory(MemObject):
type = 'PhysicalMemory'
+ port = Port("the access port")
range = Param.AddrRange("Device Address")
file = Param.String('', "memory mapped file")
latency = Param.Latency(Parent.clock, "latency of an access")
diff --git a/src/python/m5/objects/Platform.py b/src/python/m5/objects/Platform.py
index 4da0ffab4..89fee9991 100644
--- a/src/python/m5/objects/Platform.py
+++ b/src/python/m5/objects/Platform.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class Platform(SimObject):
type = 'Platform'
abstract = True
diff --git a/src/python/m5/objects/Process.py b/src/python/m5/objects/Process.py
index 60b00229e..0091d8654 100644
--- a/src/python/m5/objects/Process.py
+++ b/src/python/m5/objects/Process.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class Process(SimObject):
type = 'Process'
abstract = True
diff --git a/src/python/m5/objects/Repl.py b/src/python/m5/objects/Repl.py
index afd256082..8e9f1094f 100644
--- a/src/python/m5/objects/Repl.py
+++ b/src/python/m5/objects/Repl.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class Repl(SimObject):
type = 'Repl'
abstract = True
diff --git a/src/python/m5/objects/Root.py b/src/python/m5/objects/Root.py
index 205a93c76..373475a7a 100644
--- a/src/python/m5/objects/Root.py
+++ b/src/python/m5/objects/Root.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Serialize import Serialize
from Statistics import Statistics
from Trace import Trace
diff --git a/src/python/m5/objects/SimConsole.py b/src/python/m5/objects/SimConsole.py
index df3061908..9e1452c6d 100644
--- a/src/python/m5/objects/SimConsole.py
+++ b/src/python/m5/objects/SimConsole.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class ConsoleListener(SimObject):
type = 'ConsoleListener'
port = Param.TcpPort(3456, "listen port")
diff --git a/src/python/m5/objects/SimpleDisk.py b/src/python/m5/objects/SimpleDisk.py
index e34155ace..44ef709af 100644
--- a/src/python/m5/objects/SimpleDisk.py
+++ b/src/python/m5/objects/SimpleDisk.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
class SimpleDisk(SimObject):
type = 'SimpleDisk'
disk = Param.DiskImage("Disk Image")
diff --git a/src/python/m5/objects/AlphaFullCPU.py b/src/python/m5/objects/SimpleOzoneCPU.py
index 48989d057..5d968cab0 100644
--- a/src/python/m5/objects/AlphaFullCPU.py
+++ b/src/python/m5/objects/SimpleOzoneCPU.py
@@ -1,14 +1,21 @@
-from m5 import *
+from m5 import build_env
+from m5.config import *
from BaseCPU import BaseCPU
-class DerivAlphaFullCPU(BaseCPU):
- type = 'DerivAlphaFullCPU'
+class SimpleOzoneCPU(BaseCPU):
+ type = 'SimpleOzoneCPU'
numThreads = Param.Unsigned("number of HW thread contexts")
if not build_env['FULL_SYSTEM']:
mem = Param.FunctionalMemory(NULL, "memory")
+ width = Param.Unsigned("Width")
+ frontEndWidth = Param.Unsigned("Front end width")
+ backEndWidth = Param.Unsigned("Back end width")
+ backEndSquashLatency = Param.Unsigned("Back end squash latency")
+ backEndLatency = Param.Unsigned("Back end latency")
+ maxInstBufferSize = Param.Unsigned("Maximum instruction buffer size")
decodeToFetchDelay = Param.Unsigned("Decode to fetch delay")
renameToFetchDelay = Param.Unsigned("Rename to fetch delay")
iewToFetchDelay = Param.Unsigned("Issue/Execute/Writeback to fetch "
@@ -48,15 +55,15 @@ class DerivAlphaFullCPU(BaseCPU):
commitWidth = Param.Unsigned("Commit width")
squashWidth = Param.Unsigned("Squash width")
- local_predictor_size = Param.Unsigned("Size of local predictor")
- local_ctr_bits = Param.Unsigned("Bits per counter")
- local_history_table_size = Param.Unsigned("Size of local history table")
- local_history_bits = Param.Unsigned("Bits for the local history")
- global_predictor_size = Param.Unsigned("Size of global predictor")
- global_ctr_bits = Param.Unsigned("Bits per counter")
- global_history_bits = Param.Unsigned("Bits of history")
- choice_predictor_size = Param.Unsigned("Size of choice predictor")
- choice_ctr_bits = Param.Unsigned("Bits of choice counters")
+ localPredictorSize = Param.Unsigned("Size of local predictor")
+ localCtrBits = Param.Unsigned("Bits per counter")
+ localHistoryTableSize = Param.Unsigned("Size of local history table")
+ localHistoryBits = Param.Unsigned("Bits for the local history")
+ globalPredictorSize = Param.Unsigned("Size of global predictor")
+ globalCtrBits = Param.Unsigned("Bits per counter")
+ globalHistoryBits = Param.Unsigned("Bits of history")
+ choicePredictorSize = Param.Unsigned("Size of choice predictor")
+ choiceCtrBits = Param.Unsigned("Bits of choice counters")
BTBEntries = Param.Unsigned("Number of BTB entries")
BTBTagSize = Param.Unsigned("Size of the BTB tags, in bits")
diff --git a/src/python/m5/objects/System.py b/src/python/m5/objects/System.py
index 622b5a870..9a1e1d690 100644
--- a/src/python/m5/objects/System.py
+++ b/src/python/m5/objects/System.py
@@ -1,4 +1,5 @@
-from m5 import *
+from m5 import build_env
+from m5.config import *
class System(SimObject):
type = 'System'
@@ -7,8 +8,6 @@ class System(SimObject):
boot_cpu_frequency = Param.Frequency(Self.cpu[0].clock.frequency,
"boot processor frequency")
init_param = Param.UInt64(0, "numerical value to pass into simulator")
- bin = Param.Bool(False, "is this system binned")
- binned_fns = VectorParam.String([], "functions broken down and binned")
boot_osflags = Param.String("a", "boot flags to pass to the kernel")
kernel = Param.String("file that contains the kernel code")
readfile = Param.String("", "file to read startup script from")
diff --git a/src/python/m5/objects/Tsunami.py b/src/python/m5/objects/Tsunami.py
index 27ea0bce8..4613571d8 100644
--- a/src/python/m5/objects/Tsunami.py
+++ b/src/python/m5/objects/Tsunami.py
@@ -1,4 +1,4 @@
-from m5 import *
+from m5.config import *
from Device import BasicPioDevice
from Platform import Platform
diff --git a/src/python/m5/objects/Uart.py b/src/python/m5/objects/Uart.py
index 54754aeb9..8e1fd1a37 100644
--- a/src/python/m5/objects/Uart.py
+++ b/src/python/m5/objects/Uart.py
@@ -1,4 +1,5 @@
-from m5 import *
+from m5 import build_env
+from m5.config import *
from Device import BasicPioDevice
class Uart(BasicPioDevice):
diff --git a/src/python/m5/smartdict.py b/src/python/m5/smartdict.py
index cd38d7326..d85dbd517 100644
--- a/src/python/m5/smartdict.py
+++ b/src/python/m5/smartdict.py
@@ -23,6 +23,8 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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
# The SmartDict class fixes a couple of issues with using the content
# of os.environ or similar dicts of strings as Python variables:
diff --git a/src/sim/async.hh b/src/sim/async.hh
index e0190a133..50ae73040 100644
--- a/src/sim/async.hh
+++ b/src/sim/async.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __ASYNC_HH__
diff --git a/src/sim/builder.cc b/src/sim/builder.cc
index 7dc118985..9074cc899 100644
--- a/src/sim/builder.cc
+++ b/src/sim/builder.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <assert.h>
@@ -31,17 +33,14 @@
#include "base/inifile.hh"
#include "base/misc.hh"
#include "sim/builder.hh"
-#include "sim/configfile.hh"
-#include "sim/config_node.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
#include "sim/root.hh"
using namespace std;
-SimObjectBuilder::SimObjectBuilder(ConfigNode *_configNode)
- : ParamContext(_configNode->getPath(), NoAutoInit),
- configNode(_configNode)
+SimObjectBuilder::SimObjectBuilder(const std::string &_iniSection)
+ : ParamContext(_iniSection, NoAutoInit)
{
}
@@ -76,8 +75,7 @@ SimObjectBuilder::parseParams(IniFile &iniFile)
void
SimObjectBuilder::printErrorProlog(ostream &os)
{
- ccprintf(os, "Error creating object '%s' of type '%s':\n",
- iniSection, configNode->getType());
+ ccprintf(os, "Error creating object '%s':\n", iniSection);
}
@@ -110,9 +108,13 @@ SimObjectClass::SimObjectClass(const string &className, CreateFunc createFunc)
//
//
SimObject *
-SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
+SimObjectClass::createObject(IniFile &configDB, const std::string &iniSection)
{
- const string &type = configNode->getType();
+ string type;
+ if (!configDB.find(iniSection, "type", type)) {
+ // no C++ type associated with this object
+ return NULL;
+ }
// look up className to get appropriate createFunc
if (classMap->find(type) == classMap->end())
@@ -123,7 +125,7 @@ SimObjectClass::createObject(IniFile &configDB, ConfigNode *configNode)
// call createFunc with config hierarchy node to get object
// builder instance (context with parameters for object creation)
- SimObjectBuilder *objectBuilder = (*createFunc)(configNode);
+ SimObjectBuilder *objectBuilder = (*createFunc)(iniSection);
assert(objectBuilder != NULL);
@@ -164,7 +166,7 @@ SimObjectClass::describeAllClasses(ostream &os)
os << "[" << className << "]\n";
// create dummy object builder just to instantiate parameters
- SimObjectBuilder *objectBuilder = (*createFunc)(NULL);
+ SimObjectBuilder *objectBuilder = (*createFunc)("");
// now get the object builder to describe ite params
objectBuilder->describeParams(os);
diff --git a/src/sim/builder.hh b/src/sim/builder.hh
index b32e00e76..2997fe5c3 100644
--- a/src/sim/builder.hh
+++ b/src/sim/builder.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __BUILDER_HH__
@@ -53,14 +55,8 @@ class SimObject;
//
class SimObjectBuilder : public ParamContext
{
- private:
- // The corresponding node in the configuration hierarchy.
- // (optional: may be null if the created object is not in the
- // hierarchy)
- ConfigNode *configNode;
-
public:
- SimObjectBuilder(ConfigNode *_configNode);
+ SimObjectBuilder(const std::string &_iniSection);
virtual ~SimObjectBuilder();
@@ -75,9 +71,6 @@ class SimObjectBuilder : public ParamContext
// configuration hierarchy node label and position)
virtual const std::string &getInstanceName() { return iniSection; }
- // return the configuration hierarchy node for this context.
- virtual ConfigNode *getConfigNode() { return configNode; }
-
// Create the actual SimObject corresponding to the parameter
// values in this context. This function is overridden in derived
// classes to call a specific constructor for a particular
@@ -123,7 +116,7 @@ class SimObjectClass
// for the object (specified by the second string argument), and
// an optional config hierarchy node (specified by the third
// argument). A pointer to the new SimObjectBuilder is returned.
- typedef SimObjectBuilder *(*CreateFunc)(ConfigNode *configNode);
+ typedef SimObjectBuilder *(*CreateFunc)(const std::string &iniSection);
static std::map<std::string,CreateFunc> *classMap;
@@ -135,7 +128,8 @@ class SimObjectClass
// create SimObject given name of class and pointer to
// configuration hierarchy node
- static SimObject *createObject(IniFile &configDB, ConfigNode *configNode);
+ static SimObject *createObject(IniFile &configDB,
+ const std::string &iniSection);
// print descriptions of all parameters registered with all
// SimObject classes
@@ -154,15 +148,15 @@ class OBJ_CLASS##Builder : public SimObjectBuilder \
#define END_DECLARE_SIM_OBJECT_PARAMS(OBJ_CLASS) \
\
- OBJ_CLASS##Builder(ConfigNode *configNode); \
+ OBJ_CLASS##Builder(const std::string &iniSection); \
virtual ~OBJ_CLASS##Builder() {} \
\
OBJ_CLASS *create(); \
};
#define BEGIN_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
-OBJ_CLASS##Builder::OBJ_CLASS##Builder(ConfigNode *configNode) \
- : SimObjectBuilder(configNode),
+ OBJ_CLASS##Builder::OBJ_CLASS##Builder(const std::string &iSec) \
+ : SimObjectBuilder(iSec),
#define END_INIT_SIM_OBJECT_PARAMS(OBJ_CLASS) \
@@ -174,9 +168,9 @@ OBJ_CLASS *OBJ_CLASS##Builder::create()
#define REGISTER_SIM_OBJECT(CLASS_NAME, OBJ_CLASS) \
SimObjectBuilder * \
-new##OBJ_CLASS##Builder(ConfigNode *configNode) \
+new##OBJ_CLASS##Builder(const std::string &iniSection) \
{ \
- return new OBJ_CLASS##Builder(configNode); \
+ return new OBJ_CLASS##Builder(iniSection); \
} \
\
SimObjectClass the##OBJ_CLASS##Class(CLASS_NAME, \
diff --git a/src/sim/byteswap.hh b/src/sim/byteswap.hh
index a8c5da9d7..f1f244150 100644
--- a/src/sim/byteswap.hh
+++ b/src/sim/byteswap.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Nathan Binkert
*/
//The purpose of this file is to provide endainness conversion utility
@@ -33,6 +36,7 @@
#ifndef __SIM_BYTE_SWAP_HH__
#define __SIM_BYTE_SWAP_HH__
+#include "base/misc.hh"
#include "sim/host.hh"
// This lets us figure out what the byte order of the host system is
@@ -46,6 +50,10 @@
#include <machine/endian.h>
#endif
+#if defined(__APPLE__)
+#include <libkern/OSByteOrder.h>
+#endif
+
//These functions actually perform the swapping for parameters
//of various bit lengths
static inline uint64_t
@@ -53,6 +61,8 @@ swap_byte64(uint64_t x)
{
#if defined(linux)
return bswap_64(x);
+#elif defined(__APPLE__)
+ return OSSwapInt64(x);
#else
return (uint64_t)((((uint64_t)(x) & 0xff) << 56) |
((uint64_t)(x) & 0xff00ULL) << 40 |
@@ -70,6 +80,8 @@ swap_byte32(uint32_t x)
{
#if defined(linux)
return bswap_32(x);
+#elif defined(__APPLE__)
+ return OSSwapInt32(x);
#else
return (uint32_t)(((uint32_t)(x) & 0xff) << 24 |
((uint32_t)(x) & 0xff00) << 8 | ((uint32_t)(x) & 0xff0000) >> 8 |
@@ -82,31 +94,31 @@ swap_byte16(uint16_t x)
{
#if defined(linux)
return bswap_16(x);
+#elif defined(__APPLE__)
+ return OSSwapInt16(x);
#else
return (uint16_t)(((uint16_t)(x) & 0xff) << 8 |
((uint16_t)(x) & 0xff00) >> 8);
#endif
}
-//This lets the compiler figure out how to call the swap_byte functions above
-//for different data types.
-static inline uint64_t swap_byte(uint64_t x) {return swap_byte64(x);}
-static inline int64_t swap_byte(int64_t x) {return swap_byte64((uint64_t)x);}
-static inline uint32_t swap_byte(uint32_t x) {return swap_byte32(x);}
-static inline int32_t swap_byte(int32_t x) {return swap_byte32((uint32_t)x);}
-//This is to prevent the following two functions from compiling on
-//64bit machines. It won't detect everything, so it should be changed.
-#ifndef __x86_64__
-static inline long swap_byte(long x) {return swap_byte32((long)x);}
-static inline unsigned long swap_byte(unsigned long x)
- { return swap_byte32((unsigned long)x);}
-#endif
-static inline uint16_t swap_byte(uint16_t x) {return swap_byte32(x);}
-static inline int16_t swap_byte(int16_t x) {return swap_byte16((uint16_t)x);}
-static inline uint8_t swap_byte(uint8_t x) {return x;}
-static inline int8_t swap_byte(int8_t x) {return x;}
-static inline double swap_byte(double x) {return swap_byte64((uint64_t)x);}
-static inline float swap_byte(float x) {return swap_byte32((uint32_t)x);}
+// This function lets the compiler figure out how to call the
+// swap_byte functions above for different data types. Since the
+// sizeof() values are known at compiel time, it should inline to a
+// direct call to the right swap_byteNN() function.
+template <typename T>
+static inline T swap_byte(T x) {
+ if (sizeof(T) == 8)
+ return swap_byte64((uint64_t)x);
+ else if (sizeof(T) == 4)
+ return swap_byte32((uint32_t)x);
+ else if (sizeof(T) == 2)
+ return swap_byte16((uint16_t)x);
+ else if (sizeof(T) == 1)
+ return x;
+ else
+ panic("Can't byte-swap values larger than 64 bits");
+}
//The conversion functions with fixed endianness on both ends don't need to
//be in a namespace
diff --git a/src/sim/debug.cc b/src/sim/debug.cc
index 09e5346a8..be9566836 100644
--- a/src/sim/debug.cc
+++ b/src/sim/debug.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <sys/types.h>
@@ -124,12 +127,12 @@ DebugContext::checkParams()
// handy function to schedule DebugBreakEvent on main event queue
// (callable from debugger)
//
-extern "C" void sched_break_cycle(Tick when)
+void sched_break_cycle(Tick when)
{
new DebugBreakEvent(&mainEventQueue, when);
}
-extern "C" void eventq_dump()
+void eventq_dump()
{
mainEventQueue.dump();
}
diff --git a/src/sim/debug.hh b/src/sim/debug.hh
index 75b261d80..79792234b 100644
--- a/src/sim/debug.hh
+++ b/src/sim/debug.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __DEBUG_HH__
diff --git a/src/sim/eventq.cc b/src/sim/eventq.cc
index 4bfd6face..6ae838897 100644
--- a/src/sim/eventq.cc
+++ b/src/sim/eventq.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Steve Raasch
*/
#include <assert.h>
@@ -98,7 +102,7 @@ EventQueue::remove(Event *event)
prev->next = curr->next;
}
-void
+Event *
EventQueue::serviceOne()
{
Event *event = head;
@@ -106,13 +110,20 @@ EventQueue::serviceOne()
head = event->next;
// handle action
- if (!event->squashed())
+ if (!event->squashed()) {
event->process();
- else
+ if (event->isExitEvent()) {
+ assert(!event->getFlags(Event::AutoDelete)); // would be silly
+ return event;
+ }
+ } else {
event->clearFlags(Event::Squashed);
+ }
if (event->getFlags(Event::AutoDelete) && !event->scheduled())
delete event;
+
+ return NULL;
}
diff --git a/src/sim/eventq.hh b/src/sim/eventq.hh
index 5fc73bb53..430473df3 100644
--- a/src/sim/eventq.hh
+++ b/src/sim/eventq.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
@@ -87,7 +90,8 @@ class Event : public Serializable, public FastAlloc
Squashed = 0x1,
Scheduled = 0x2,
AutoDelete = 0x4,
- AutoSerialize = 0x8
+ AutoSerialize = 0x8,
+ IsExitEvent = 0x10
};
bool getFlags(Flags f) const { return (_flags & f) == f; }
@@ -211,6 +215,9 @@ class Event : public Serializable, public FastAlloc
/// Check whether the event is squashed
bool squashed() { return getFlags(Squashed); }
+ /// See if this is a SimExitEvent (without resorting to RTTI)
+ bool isExitEvent() { return getFlags(IsExitEvent); }
+
/// Get the time that the event is scheduled
Tick when() const { return _when; }
@@ -295,7 +302,7 @@ class EventQueue : public Serializable
void reschedule(Event *ev);
Tick nextTick() { return head->when(); }
- void serviceOne();
+ 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,
diff --git a/src/sim/faults.cc b/src/sim/faults.cc
index cb095f852..650b728f7 100644
--- a/src/sim/faults.cc
+++ b/src/sim/faults.cc
@@ -24,29 +24,32 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Gabe Black
*/
#include "base/misc.hh"
#include "sim/faults.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#if !FULL_SYSTEM
-void FaultBase::invoke(ExecContext * xc)
+void FaultBase::invoke(ThreadContext * tc)
{
- fatal("fault (%s) detected @ PC 0x%08p", name(), xc->readPC());
+ fatal("fault (%s) detected @ PC 0x%08p", name(), tc->readPC());
}
#else
-void FaultBase::invoke(ExecContext * xc)
+void FaultBase::invoke(ThreadContext * tc)
{
- DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), xc->readPC());
- xc->getCpuPtr()->recordEvent(csprintf("Fault %s", name()));
+ DPRINTF(Fault, "Fault %s at PC: %#x\n", name(), tc->readPC());
+ tc->getCpuPtr()->recordEvent(csprintf("Fault %s", name()));
- assert(!xc->misspeculating());
+ assert(!tc->misspeculating());
}
#endif
-void UnimpFault::invoke(ExecContext * xc)
+void UnimpFault::invoke(ThreadContext * tc)
{
panic("Unimpfault: %s\n", panicStr.c_str());
}
diff --git a/src/sim/faults.hh b/src/sim/faults.hh
index 9b3bc9103..00264d8fc 100644
--- a/src/sim/faults.hh
+++ b/src/sim/faults.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Gabe Black
*/
#ifndef __FAULTS_HH__
@@ -33,7 +36,7 @@
#include "sim/stats.hh"
#include "config/full_system.hh"
-class ExecContext;
+class ThreadContext;
class FaultBase;
typedef RefCountingPtr<FaultBase> Fault;
@@ -51,11 +54,7 @@ class FaultBase : public RefCounted
{
public:
virtual FaultName name() = 0;
-#if FULL_SYSTEM
- virtual void invoke(ExecContext * xc);
-#else
- virtual void invoke(ExecContext * xc);
-#endif
+ virtual void invoke(ThreadContext * tc);
// template<typename T>
// bool isA() {return dynamic_cast<T *>(this);}
virtual bool isMachineCheckFault() {return false;}
@@ -74,7 +73,7 @@ class UnimpFault : public FaultBase
{ }
FaultName name() {return "Unimplemented simulator feature";}
- void invoke(ExecContext * xc);
+ void invoke(ThreadContext * tc);
};
#endif // __FAULTS_HH__
diff --git a/src/sim/host.hh b/src/sim/host.hh
index 48c977331..9c79580b1 100644
--- a/src/sim/host.hh
+++ b/src/sim/host.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/**
@@ -54,6 +56,8 @@ typedef int64_t Counter;
*/
typedef int64_t Tick;
+const Tick MaxTick = (1LL << 62);
+
/**
* Address type
* This will probably be moved somewhere else in the near future.
diff --git a/src/sim/main.cc b/src/sim/main.cc
index aecc171ed..3eb7fa95d 100644
--- a/src/sim/main.cc
+++ b/src/sim/main.cc
@@ -24,24 +24,30 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 Raasch
+ * Nathan Binkert
+ * Steve Reinhardt
*/
///
/// @file sim/main.cc
///
+#include <Python.h> // must be before system headers... see Python docs
+
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <signal.h>
+#include <getopt.h>
#include <list>
#include <string>
#include <vector>
-#include "base/copyright.hh"
-#include "base/embedfile.hh"
+#include "base/callback.hh"
#include "base/inifile.hh"
#include "base/misc.hh"
#include "base/output.hh"
@@ -51,11 +57,12 @@
#include "base/time.hh"
#include "cpu/base.hh"
#include "cpu/smt.hh"
-#include "python/pyconfig.hh"
+#include "mem/mem_object.hh"
+#include "mem/port.hh"
#include "sim/async.hh"
#include "sim/builder.hh"
-#include "sim/configfile.hh"
#include "sim/host.hh"
+#include "sim/serialize.hh"
#include "sim/sim_events.hh"
#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
@@ -119,31 +126,39 @@ showBriefHelp(ostream &out)
ccprintf(out, "Usage:\n");
ccprintf(out,
-"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
-" [--<var>=<val>] <config file>\n"
+"%s [-p <path>] [-i ] [-h] <config file>\n"
"\n"
-" -d set the output directory to <dir>\n"
-" -E set the environment variable <var> to <val> (or 'True')\n"
-" -I add the directory <dir> to python's path\n"
-" -P execute <python> directly in the configuration\n"
-" --var=val set the python variable <var> to '<val>'\n"
-" <configfile> config file name (ends in .py)\n\n",
+" -p, --path <path> prepends <path> to PYTHONPATH instead of using\n"
+" built-in zip archive. Useful when developing/debugging\n"
+" changes to built-in Python libraries, as the new Python\n"
+" can be tested without building a new m5 binary.\n\n"
+" -i, --interactive forces entry into interactive mode after the supplied\n"
+" script is executed (just like the -i option to the\n"
+" Python interpreter).\n\n"
+" -h Prints this help\n\n"
+" <configfile> config file name which ends in .py. (Normally you can\n"
+" run <configfile> --help to get help on that config files\n"
+" parameters.\n\n",
prog);
- ccprintf(out, "%s -X\n -X extract embedded files\n\n", prog);
- ccprintf(out, "%s -h\n -h print short help\n\n", prog);
}
+const char *briefCopyright =
+"Copyright (c) 2001-2006\n"
+"The Regents of The University of Michigan\n"
+"All Rights Reserved\n";
+
/// Print welcome message.
void
sayHello(ostream &out)
{
- extern const char *compileDate; // from date.cc
+ extern const char *compileDate; // from date.cc
ccprintf(out, "M5 Simulator System\n");
// display copyright
ccprintf(out, "%s\n", briefCopyright);
- ccprintf(out, "M5 compiled on %d\n", compileDate);
+ ccprintf(out, "M5 compiled %d\n", compileDate);
+ ccprintf(out, "M5 started %s\n", Time::start);
char *host = getenv("HOSTNAME");
if (!host)
@@ -151,66 +166,19 @@ sayHello(ostream &out)
if (host)
ccprintf(out, "M5 executing on %s\n", host);
-
- ccprintf(out, "M5 simulation started %s\n", Time::start);
-}
-
-///
-/// Echo the command line for posterity in such a way that it can be
-/// used to rerun the same simulation (given the same .ini files).
-///
-void
-echoCommandLine(int argc, char **argv, ostream &out)
-{
- out << "command line: " << argv[0];
- for (int i = 1; i < argc; i++) {
- string arg(argv[i]);
-
- out << ' ';
-
- // If the arg contains spaces, we need to quote it.
- // The rest of this is overkill to make it look purty.
-
- // print dashes first outside quotes
- int non_dash_pos = arg.find_first_not_of("-");
- out << arg.substr(0, non_dash_pos); // print dashes
- string body = arg.substr(non_dash_pos); // the rest
-
- // if it's an assignment, handle the lhs & rhs separately
- int eq_pos = body.find("=");
- if (eq_pos == string::npos) {
- out << quote(body);
- }
- else {
- string lhs(body.substr(0, eq_pos));
- string rhs(body.substr(eq_pos + 1));
-
- out << quote(lhs) << "=" << quote(rhs);
- }
- }
- out << endl << endl;
}
-char *
-getOptionString(int &index, int argc, char **argv)
-{
- char *option = argv[index] + 2;
- if (*option != '\0')
- return option;
-
- // We didn't find an argument, it must be in the next variable.
- if (++index >= argc)
- panic("option string for option '%s' not found", argv[index - 1]);
- return argv[index];
-}
+extern "C" { void init_cc_main(); }
int
main(int argc, char **argv)
{
- // Save off program name
+ // Saze off program name
myProgName = argv[0];
+ sayHello(cerr);
+
signal(SIGFPE, SIG_IGN); // may occur on misspeculated paths
signal(SIGTRAP, SIG_IGN);
signal(SIGUSR1, dumpStatsHandler); // dump intermediate stats
@@ -218,181 +186,309 @@ main(int argc, char **argv)
signal(SIGINT, exitNowHandler); // dump final stats and exit
signal(SIGABRT, abortHandler);
- bool configfile_found = false;
- PythonConfig pyconfig;
- string outdir;
+ Py_SetProgramName(argv[0]);
+
+ // default path to m5 python code is the currently executing
+ // file... Python ZipImporter will find embedded zip archive
+ char *pythonpath = argv[0];
+
+ bool interactive = false;
+ bool show_help = false;
+ bool getopt_done = false;
+ int opt_index = 0;
+
+ static struct option long_options[] = {
+ {"python", 1, 0, 'p'},
+ {"interactive", 0, 0, 'i'},
+ {"help", 0, 0, 'h'},
+ {0,0,0,0}
+ };
+
+ do {
+ switch (getopt_long(argc, argv, "+p:ih", long_options, &opt_index)) {
+ // -p <path> prepends <path> to PYTHONPATH instead of
+ // using built-in zip archive. Useful when
+ // developing/debugging changes to built-in Python
+ // libraries, as the new Python can be tested without
+ // building a new m5 binary.
+ case 'p':
+ pythonpath = optarg;
+ break;
+
+ // -i forces entry into interactive mode after the
+ // supplied script is executed (just like the -i option to
+ // the Python interpreter).
+ case 'i':
+ interactive = true;
+ break;
+
+ case 'h':
+ show_help = true;
+ break;
+ case -1:
+ getopt_done = true;
+ break;
+
+ default:
+ fatal("Unrecognized option %c\n", optopt);
+ }
+ } while (!getopt_done);
- if (argc < 2) {
+ if (show_help) {
showBriefHelp(cerr);
exit(1);
}
- sayHello(cerr);
+ // Fix up argc & argv to hide arguments we just processed.
+ // getopt() sets optind to the index of the first non-processed
+ // argv element.
+ argc -= optind;
+ argv += optind;
- // Parse command-line options.
- // Since most of the complex options are handled through the
- // config database, we don't mess with getopts, and just parse
- // manually.
- for (int i = 1; i < argc; ++i) {
- char *arg_str = argv[i];
-
- // if arg starts with '--', parse as a special python option
- // of the format --<python var>=<string value>, if the arg
- // starts with '-', it should be a simulator option with a
- // format similar to getopt. In any other case, treat the
- // option as a configuration file name and load it.
- if (arg_str[0] == '-' && arg_str[1] == '-') {
- string str = &arg_str[2];
- string var, val;
-
- if (!split_first(str, var, val, '='))
- panic("Could not parse configuration argument '%s'\n"
- "Expecting --<variable>=<value>\n", arg_str);
-
- pyconfig.setVariable(var, val);
- } else if (arg_str[0] == '-') {
- char *option;
- string var, val;
-
- // switch on second char
- switch (arg_str[1]) {
- case 'd':
- outdir = getOptionString(i, argc, argv);
- break;
-
- case 'h':
- showBriefHelp(cerr);
- exit(1);
-
- case 'E':
- option = getOptionString(i, argc, argv);
- if (!split_first(option, var, val, '='))
- val = "True";
-
- if (setenv(var.c_str(), val.c_str(), true) == -1)
- panic("setenv: %s\n", strerror(errno));
- break;
-
- case 'I':
- option = getOptionString(i, argc, argv);
- pyconfig.addPath(option);
- break;
-
- case 'P':
- option = getOptionString(i, argc, argv);
- pyconfig.writeLine(option);
- break;
-
- case 'X': {
- list<EmbedFile> lst;
- EmbedMap::all(lst);
- list<EmbedFile>::iterator i = lst.begin();
- list<EmbedFile>::iterator end = lst.end();
-
- while (i != end) {
- cprintf("Embedded File: %s\n", i->name);
- cout.write(i->data, i->length);
- ++i;
- }
-
- return 0;
- }
-
- default:
- showBriefHelp(cerr);
- panic("invalid argument '%s'\n", arg_str);
- }
- } else {
- string file(arg_str);
- string base, ext;
+ // Set up PYTHONPATH to make sure the m5 module is found
+ string newpath(pythonpath);
+
+ char *oldpath = getenv("PYTHONPATH");
+ if (oldpath != NULL) {
+ newpath += ":";
+ newpath += oldpath;
+ }
- if (!split_last(file, base, ext, '.') || ext != "py")
- panic("Config file '%s' must end in '.py'\n", file);
+ if (setenv("PYTHONPATH", newpath.c_str(), true) == -1)
+ fatal("setenv: %s\n", strerror(errno));
- pyconfig.load(file);
- configfile_found = true;
+ // initialize embedded Python interpreter
+ Py_Initialize();
+ PySys_SetArgv(argc, argv);
+
+ // initialize SWIG 'cc_main' module
+ init_cc_main();
+
+ if (argc > 0) {
+ // extra arg(s): first is script file, remaining ones are args
+ // to script file
+ char *filename = argv[0];
+ FILE *fp = fopen(filename, "r");
+ if (!fp) {
+ fatal("cannot open file '%s'\n", filename);
}
+
+ PyRun_AnyFile(fp, filename);
+ } else {
+ // no script file argument... force interactive prompt
+ interactive = true;
}
- if (outdir.empty()) {
- char *env = getenv("OUTPUT_DIR");
- outdir = env ? env : ".";
+ if (interactive) {
+ // The following code to import readline was copied from Python
+ // 2.4.3's Modules/main.c.
+ // Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
+ // Python Software Foundation; All Rights Reserved
+ // We should only enable this if we're actually using an
+ // interactive prompt.
+ PyObject *v;
+ v = PyImport_ImportModule("readline");
+ if (v == NULL)
+ PyErr_Clear();
+ else
+ Py_DECREF(v);
+
+ PyRun_InteractiveLoop(stdin, "stdin");
}
- simout.setDirectory(outdir);
+ // clean up Python intepreter.
+ Py_Finalize();
+}
- char *env = getenv("CONFIG_OUTPUT");
- if (!env)
- env = "config.out";
- configStream = simout.find(env);
- if (!configfile_found)
- panic("no configuration file specified!");
+void
+setOutputDir(const string &dir)
+{
+ simout.setDirectory(dir);
+}
+
+
+IniFile inifile;
+
+SimObject *
+createSimObject(const string &name)
+{
+ return SimObjectClass::createObject(inifile, name);
+}
+
+
+/**
+ * Pointer to the Python function that maps names to SimObjects.
+ */
+PyObject *resolveFunc = NULL;
+
+/**
+ * Convert a pointer to the Python object that SWIG wraps around a C++
+ * SimObject pointer back to the actual C++ pointer. See main.i.
+ */
+extern "C" SimObject *convertSwigSimObjectPtr(PyObject *);
+
+
+SimObject *
+resolveSimObject(const string &name)
+{
+ PyObject *pyPtr = PyEval_CallFunction(resolveFunc, "(s)", name.c_str());
+ if (pyPtr == NULL) {
+ PyErr_Print();
+ panic("resolveSimObject: failure on call to Python for %s", name);
+ }
+
+ SimObject *simObj = convertSwigSimObjectPtr(pyPtr);
+ if (simObj == NULL)
+ panic("resolveSimObject: failure on pointer conversion for %s", name);
+
+ return simObj;
+}
+
+
+/**
+ * Load config.ini into C++ database. Exported to Python via SWIG;
+ * invoked from m5.instantiate().
+ */
+void
+loadIniFile(PyObject *_resolveFunc)
+{
+ resolveFunc = _resolveFunc;
+ configStream = simout.find("config.out");
// The configuration database is now complete; start processing it.
- IniFile inifile;
- if (!pyconfig.output(inifile))
- panic("Error processing python code");
+ inifile.load("config.ini");
// Initialize statistics database
Stats::InitSimStats();
+}
- // Now process the configuration hierarchy and create the SimObjects.
- ConfigHierarchy configHierarchy(inifile);
- configHierarchy.build();
- configHierarchy.createSimObjects();
+/**
+ * Look up a MemObject port. Helper function for connectPorts().
+ */
+Port *
+lookupPort(SimObject *so, const std::string &name, int i)
+{
+ MemObject *mo = dynamic_cast<MemObject *>(so);
+ if (mo == NULL) {
+ warn("error casting SimObject %s to MemObject", so->name());
+ return NULL;
+ }
+
+ Port *p = mo->getPort(name, i);
+ if (p == NULL)
+ warn("error looking up port %s on object %s", name, so->name());
+ return p;
+}
+
+
+/**
+ * Connect the described MemObject ports. Called from Python via SWIG.
+ */
+int
+connectPorts(SimObject *o1, const std::string &name1, int i1,
+ SimObject *o2, const std::string &name2, int i2)
+{
+ Port *p1 = lookupPort(o1, name1, i1);
+ Port *p2 = lookupPort(o2, name2, i2);
+
+ if (p1 == NULL || p2 == NULL) {
+ warn("connectPorts: port lookup error");
+ return 0;
+ }
+
+ p1->setPeer(p2);
+ p2->setPeer(p1);
+
+ return 1;
+}
+
+/**
+ * Do final initialization steps after object construction but before
+ * start of simulation.
+ */
+void
+finalInit()
+{
// Parse and check all non-config-hierarchy parameters.
ParamContext::parseAllContexts(inifile);
ParamContext::checkAllContexts();
- // Print hello message to stats file if it's actually a file. If
- // it's not (i.e. it's cout or cerr) then we already did it above.
- if (simout.isFile(*outputStream))
- sayHello(*outputStream);
-
- // Echo command line and all parameter settings to stats file as well.
- echoCommandLine(argc, argv, *outputStream);
+ // Echo all parameter settings to stats file as well.
ParamContext::showAllContexts(*configStream);
- // Any objects that can't connect themselves until after construction should
- // do so now
- SimObject::connectAll();
-
// Do a second pass to finish initializing the sim objects
SimObject::initAll();
// Restore checkpointed state, if any.
+#if 0
configHierarchy.unserializeSimObjects();
-
- // Done processing the configuration database.
- // Check for unreferenced entries.
- if (inifile.printUnreferenced())
- panic("unreferenced sections/entries in the intermediate ini file");
+#endif
SimObject::regAllStats();
- // uncomment the following to get PC-based execution-time profile
-#ifdef DO_PROFILE
- init_profile((char *)&_init, (char *)&_fini);
-#endif
-
// Check to make sure that the stats package is properly initialized
Stats::check();
// Reset to put the stats in a consistent state.
Stats::reset();
- warn("Entering event queue. Starting simulation...\n");
SimStartup();
- while (!mainEventQueue.empty()) {
+}
+
+
+/** Simulate for num_cycles additional cycles. If num_cycles is -1
+ * (the default), do not limit simulation; some other event must
+ * terminate the loop. Exported to Python via SWIG.
+ * @return The SimLoopExitEvent that caused the loop to exit.
+ */
+SimLoopExitEvent *
+simulate(Tick num_cycles = -1)
+{
+ warn("Entering event queue @ %d. Starting simulation...\n", curTick);
+
+ // Fix up num_cycles. Special default value -1 means simulate
+ // "forever"... schedule event at MaxTick just to be safe.
+ // Otherwise it's a delta for additional cycles to simulate past
+ // curTick, and thus must be non-negative.
+ if (num_cycles == -1)
+ num_cycles = MaxTick;
+ else if (num_cycles < 0)
+ fatal("simulate: num_cycles must be >= 0 (was %d)\n", num_cycles);
+ else
+ num_cycles = curTick + num_cycles;
+
+ Event *limit_event = new SimLoopExitEvent(num_cycles,
+ "simulate() limit reached");
+
+ while (1) {
+ // there should always be at least one event (the SimLoopExitEvent
+ // we just scheduled) in the queue
+ assert(!mainEventQueue.empty());
assert(curTick <= mainEventQueue.nextTick() &&
"event scheduled in the past");
// forward current cycle to the time of the first event on the
// queue
curTick = mainEventQueue.nextTick();
- mainEventQueue.serviceOne();
+ Event *exit_event = mainEventQueue.serviceOne();
+ if (exit_event != NULL) {
+ // hit some kind of exit event; return to Python
+ // event must be subclass of SimLoopExitEvent...
+ SimLoopExitEvent *se_event = dynamic_cast<SimLoopExitEvent *>(exit_event);
+ if (se_event == NULL)
+ panic("Bogus exit event class!");
+
+ // if we didn't hit limit_event, delete it
+ if (se_event != limit_event) {
+ assert(limit_event->scheduled());
+ limit_event->deschedule();
+ delete limit_event;
+ }
+
+ return se_event;
+ }
if (async_event) {
async_event = false;
@@ -412,7 +508,7 @@ main(int argc, char **argv)
if (async_exit) {
async_exit = false;
- new SimExitEvent("User requested STOP");
+ exitSimLoop("user interrupt received");
}
if (async_io || async_alarm) {
@@ -423,11 +519,78 @@ main(int argc, char **argv)
}
}
- // This should never happen... every conceivable way for the
- // simulation to terminate (hit max cycles/insts, signal,
- // simulated system halts/exits) generates an exit event, so we
- // should never run out of events on the queue.
- exitNow("no events on event loop! All CPUs must be idle.", 1);
+ // not reached... only exit is return on SimLoopExitEvent
+}
+
+Event *
+createCountedQuiesce()
+{
+ return new CountedQuiesceEvent();
+}
+
+void
+cleanupCountedQuiesce(Event *counted_quiesce)
+{
+ CountedQuiesceEvent *event =
+ dynamic_cast<CountedQuiesceEvent *>(counted_quiesce);
+ if (event == NULL) {
+ fatal("Called cleanupCountedQuiesce() on an event that was not "
+ "a CountedQuiesceEvent.");
+ }
+ assert(event->getCount() == 0);
+ delete event;
+}
+
+void
+serializeAll()
+{
+ Serializable::serializeAll();
+}
+
+void
+unserializeAll()
+{
+ Serializable::unserializeAll();
+}
+
+/**
+ * Queue of C++ callbacks to invoke on simulator exit.
+ */
+CallbackQueue exitCallbacks;
+
+/**
+ * Register an exit callback.
+ */
+void
+registerExitCallback(Callback *callback)
+{
+ exitCallbacks.add(callback);
+}
+
+BaseCPU *
+convertToBaseCPUPtr(SimObject *obj)
+{
+ BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj);
+
+ if (ptr == NULL)
+ warn("Casting to BaseCPU pointer failed");
+ return ptr;
+}
+
+/**
+ * Do C++ simulator exit processing. Exported to SWIG to be invoked
+ * when simulator terminates via Python's atexit mechanism.
+ */
+void
+doExitCleanup()
+{
+ exitCallbacks.process();
+ exitCallbacks.clear();
+
+ cout.flush();
+
+ ParamContext::cleanupAllContexts();
- return 0;
+ // print simulation stats
+ Stats::DumpNow();
}
diff --git a/src/sim/param.cc b/src/sim/param.cc
index 8998d7d77..b1c50946b 100644
--- a/src/sim/param.cc
+++ b/src/sim/param.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <algorithm>
@@ -37,8 +39,6 @@
#include "base/range.hh"
#include "base/str.hh"
#include "base/trace.hh"
-#include "sim/config_node.hh"
-#include "sim/configfile.hh"
#include "sim/param.hh"
#include "sim/sim_object.hh"
@@ -519,7 +519,9 @@ parseSimObjectParam(ParamContext *context, const string &s, SimObject *&value)
obj = NULL;
}
else {
- obj = context->resolveSimObject(s);
+ // defined in main.cc
+ extern SimObject *resolveSimObject(const string &);
+ obj = resolveSimObject(s);
if (obj == NULL)
return false;
@@ -694,22 +696,6 @@ ParamContext::printErrorProlog(ostream &os)
}
//
-// Resolve an object name to a SimObject pointer. The object will be
-// created as a side-effect if necessary. If the name contains a
-// colon (e.g., "iq:IQ"), then the object is local (invisible to
-// outside this context). If there is no colon, the name needs to be
-// resolved through the configuration hierarchy (only possible for
-// SimObjectBuilder objects, which return non-NULL for configNode()).
-//
-SimObject *
-ParamContext::resolveSimObject(const string &name)
-{
- ConfigNode *n = getConfigNode();
- return n ? n->resolveSimObject(name) : NULL;
-}
-
-
-//
// static method: call parseParams() on all registered contexts
//
void
diff --git a/src/sim/param.hh b/src/sim/param.hh
index 4a1b8bda1..1bc55c125 100644
--- a/src/sim/param.hh
+++ b/src/sim/param.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#ifndef __SIM_PARAM_HH__
@@ -34,10 +36,10 @@
#include <string>
#include <vector>
-#include "sim/configfile.hh"
#include "sim/startup.hh"
// forward decls
+class IniFile;
class BaseParam;
class SimObject;
@@ -130,18 +132,10 @@ class ParamContext : protected StartupCallback
// print context information for parameter error
virtual void printErrorProlog(std::ostream &);
- // resolve a SimObject name in this context to an object pointer.
- virtual SimObject *resolveSimObject(const std::string &name);
-
// generate the name for this instance of this context (used as a
// prefix to create unique names in resolveSimObject()
virtual const std::string &getInstanceName() { return iniSection; }
- // return the configuration hierarchy node for this context. Bare
- // ParamContext objects have no corresponding node, so the default
- // implementation returns NULL.
- virtual ConfigNode *getConfigNode() { return NULL; }
-
// Parse all parameters registered with all ParamContext objects.
static void parseAllContexts(IniFile &iniFile);
diff --git a/src/sim/process.cc b/src/sim/process.cc
index 1da525093..f989300a3 100644
--- a/src/sim/process.cc
+++ b/src/sim/process.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <unistd.h>
@@ -36,7 +40,7 @@
#include "base/loader/symtab.hh"
#include "base/statistics.hh"
#include "config/full_system.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/page_table.hh"
#include "mem/physical.hh"
#include "mem/translating_port.hh"
@@ -46,6 +50,20 @@
#include "sim/syscall_emul.hh"
#include "sim/system.hh"
+#include "arch/isa_specific.hh"
+#if THE_ISA == ALPHA_ISA
+#include "arch/alpha/linux/process.hh"
+#include "arch/alpha/tru64/process.hh"
+#elif THE_ISA == SPARC_ISA
+#include "arch/sparc/linux/process.hh"
+#include "arch/sparc/solaris/process.hh"
+#elif THE_ISA == MIPS_ISA
+#include "arch/mips/linux/process.hh"
+#else
+#error "THE_ISA not set"
+#endif
+
+
using namespace std;
using namespace TheISA;
@@ -130,11 +148,11 @@ Process::openOutputFile(const string &filename)
int
-Process::registerExecContext(ExecContext *xc)
+Process::registerThreadContext(ThreadContext *tc)
{
// add to list
- int myIndex = execContexts.size();
- execContexts.push_back(xc);
+ int myIndex = threadContexts.size();
+ threadContexts.push_back(tc);
// return CPU number to caller
return myIndex;
@@ -143,14 +161,14 @@ Process::registerExecContext(ExecContext *xc)
void
Process::startup()
{
- if (execContexts.empty())
+ if (threadContexts.empty())
fatal("Process %s is not associated with any CPUs!\n", name());
- // first exec context for this process... initialize & enable
- ExecContext *xc = execContexts[0];
+ // first thread context for this process... initialize & enable
+ ThreadContext *tc = threadContexts[0];
// mark this context as active so it will start ticking.
- xc->activate(0);
+ tc->activate(0);
Port *mem_port;
mem_port = system->physmem->getPort("functional");
@@ -160,14 +178,14 @@ Process::startup()
}
void
-Process::replaceExecContext(ExecContext *xc, int xcIndex)
+Process::replaceThreadContext(ThreadContext *tc, int tcIndex)
{
- if (xcIndex >= execContexts.size()) {
- panic("replaceExecContext: bad xcIndex, %d >= %d\n",
- xcIndex, execContexts.size());
+ if (tcIndex >= threadContexts.size()) {
+ panic("replaceThreadContext: bad tcIndex, %d >= %d\n",
+ tcIndex, threadContexts.size());
}
- execContexts[xcIndex] = xc;
+ threadContexts[tcIndex] = tc;
}
// map simulator fd sim_fd to target fd tgt_fd
@@ -308,11 +326,10 @@ LiveProcess::argsInit(int intSize, int pageSize)
// set bottom of stack
stack_min = stack_base - space_needed;
// align it
- stack_min &= ~(intSize-1);
+ stack_min = roundDown(stack_min, pageSize);
stack_size = stack_base - stack_min;
// map memory
- pTable->allocate(roundDown(stack_min, pageSize),
- roundUp(stack_size, pageSize));
+ pTable->allocate(stack_min, roundUp(stack_size, pageSize));
// map out initial stack contents
Addr argv_array_base = stack_min + intSize; // room for argc
@@ -334,20 +351,23 @@ LiveProcess::argsInit(int intSize, int pageSize)
copyStringArray(argv, argv_array_base, arg_data_base, initVirtMem);
copyStringArray(envp, envp_array_base, env_data_base, initVirtMem);
- execContexts[0]->setIntReg(ArgumentReg0, argc);
- execContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
- execContexts[0]->setIntReg(StackPointerReg, stack_min);
+ threadContexts[0]->setIntReg(ArgumentReg0, argc);
+ threadContexts[0]->setIntReg(ArgumentReg1, argv_array_base);
+ threadContexts[0]->setIntReg(StackPointerReg, stack_min);
Addr prog_entry = objFile->entryPoint();
- execContexts[0]->setPC(prog_entry);
- execContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
- execContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+ threadContexts[0]->setPC(prog_entry);
+ threadContexts[0]->setNextPC(prog_entry + sizeof(MachInst));
+
+#if THE_ISA != ALPHA_ISA //e.g. MIPS or Sparc
+ threadContexts[0]->setNextNPC(prog_entry + (2 * sizeof(MachInst)));
+#endif
num_processes++;
}
void
-LiveProcess::syscall(int64_t callnum, ExecContext *xc)
+LiveProcess::syscall(int64_t callnum, ThreadContext *tc)
{
num_syscalls++;
@@ -355,7 +375,135 @@ LiveProcess::syscall(int64_t callnum, ExecContext *xc)
if (desc == NULL)
fatal("Syscall %d out of range", callnum);
- desc->doSyscall(callnum, this, xc);
+ desc->doSyscall(callnum, this, tc);
+}
+
+LiveProcess *
+LiveProcess::create(const std::string &nm, System *system, int stdin_fd,
+ int stdout_fd, int stderr_fd, std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp)
+{
+ LiveProcess *process = NULL;
+
+ ObjectFile *objFile = createObjectFile(executable);
+ if (objFile == NULL) {
+ fatal("Can't load object file %s", executable);
+ }
+
+#if THE_ISA == ALPHA_ISA
+ if (objFile->getArch() != ObjectFile::Alpha)
+ fatal("Object file architecture does not match compiled ISA (Alpha).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Tru64:
+ process = new AlphaTru64Process(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ case ObjectFile::Linux:
+ process = new AlphaLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#elif THE_ISA == SPARC_ISA
+ if (objFile->getArch() != ObjectFile::SPARC)
+ fatal("Object file architecture does not match compiled ISA (SPARC).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new SparcLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+
+ case ObjectFile::Solaris:
+ process = new SparcSolarisProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#elif THE_ISA == MIPS_ISA
+ if (objFile->getArch() != ObjectFile::Mips)
+ fatal("Object file architecture does not match compiled ISA (MIPS).");
+ switch (objFile->getOpSys()) {
+ case ObjectFile::Linux:
+ process = new MipsLinuxProcess(nm, objFile, system,
+ stdin_fd, stdout_fd, stderr_fd,
+ argv, envp);
+ break;
+
+ default:
+ fatal("Unknown/unsupported operating system.");
+ }
+#else
+#error "THE_ISA not set"
+#endif
+
+
+ if (process == NULL)
+ fatal("Unknown error creating process object.");
+ return process;
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+ VectorParam<string> cmd;
+ Param<string> executable;
+ Param<string> input;
+ Param<string> output;
+ VectorParam<string> env;
+ SimObjectParam<System *> system;
+
+END_DECLARE_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+ INIT_PARAM(cmd, "command line (executable plus arguments)"),
+ INIT_PARAM(executable, "executable (overrides cmd[0] if set)"),
+ INIT_PARAM(input, "filename for stdin (dflt: use sim stdin)"),
+ INIT_PARAM(output, "filename for stdout/stderr (dflt: use sim stdout)"),
+ INIT_PARAM(env, "environment settings"),
+ INIT_PARAM(system, "system")
+
+END_INIT_SIM_OBJECT_PARAMS(LiveProcess)
+
+
+CREATE_SIM_OBJECT(LiveProcess)
+{
+ string in = input;
+ string out = output;
+
+ // initialize file descriptors to default: same as simulator
+ int stdin_fd, stdout_fd, stderr_fd;
+
+ if (in == "stdin" || in == "cin")
+ stdin_fd = STDIN_FILENO;
+ else
+ stdin_fd = Process::openInputFile(input);
+
+ if (out == "stdout" || out == "cout")
+ stdout_fd = STDOUT_FILENO;
+ else if (out == "stderr" || out == "cerr")
+ stdout_fd = STDERR_FILENO;
+ else
+ stdout_fd = Process::openOutputFile(out);
+
+ stderr_fd = (stdout_fd != STDOUT_FILENO) ? stdout_fd : STDERR_FILENO;
+
+ return LiveProcess::create(getInstanceName(), system,
+ stdin_fd, stdout_fd, stderr_fd,
+ (string)executable == "" ? cmd[0] : executable,
+ cmd, env);
}
-DEFINE_SIM_OBJECT_CLASS_NAME("LiveProcess", LiveProcess);
+
+REGISTER_SIM_OBJECT("LiveProcess", LiveProcess)
diff --git a/src/sim/process.hh b/src/sim/process.hh
index 807bf330f..763deb100 100644
--- a/src/sim/process.hh
+++ b/src/sim/process.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __PROCESS_HH__
@@ -43,8 +46,7 @@
#include "base/statistics.hh"
#include "sim/sim_object.hh"
-class CPUExecContext;
-class ExecContext;
+class ThreadContext;
class SyscallDesc;
class PageTable;
class TranslatingPort;
@@ -62,24 +64,24 @@ class Process : public SimObject
/// running on.
System *system;
- // have we initialized an execution context from this process? If
+ // have we initialized a thread context from this process? If
// yes, subsequent contexts are assumed to be for dynamically
// created threads and are not initialized.
bool initialContextLoaded;
- // execution contexts associated with this process
- std::vector<ExecContext *> execContexts;
+ // thread contexts associated with this process
+ std::vector<ThreadContext *> threadContexts;
// number of CPUs (esxec contexts, really) assigned to this process.
- unsigned int numCpus() { return execContexts.size(); }
+ unsigned int numCpus() { return threadContexts.size(); }
// record of blocked context
struct WaitRec
{
Addr waitChan;
- ExecContext *waitingContext;
+ ThreadContext *waitingContext;
- WaitRec(Addr chan, ExecContext *ctx)
+ WaitRec(Addr chan, ThreadContext *ctx)
: waitChan(chan), waitingContext(ctx)
{ }
};
@@ -140,12 +142,12 @@ class Process : public SimObject
// override of virtual SimObject method: register statistics
virtual void regStats();
- // register an execution context for this process.
- // returns xc's cpu number (index into execContexts[])
- int registerExecContext(ExecContext *xc);
+ // register a thread context for this process.
+ // returns tc's cpu number (index into threadContexts[])
+ int registerThreadContext(ThreadContext *tc);
- void replaceExecContext(ExecContext *xc, int xcIndex);
+ void replaceThreadContext(ThreadContext *tc, int tcIndex);
// map simulator fd sim_fd to target fd tgt_fd
void dup_fd(int sim_fd, int tgt_fd);
@@ -159,7 +161,7 @@ class Process : public SimObject
// look up simulator fd for given target fd
int sim_fd(int tgt_fd);
- virtual void syscall(int64_t callnum, ExecContext *xc) = 0;
+ virtual void syscall(int64_t callnum, ThreadContext *tc) = 0;
};
//
@@ -181,9 +183,19 @@ class LiveProcess : public Process
virtual void argsInit(int intSize, int pageSize);
public:
- virtual void syscall(int64_t callnum, ExecContext *xc);
+ virtual void syscall(int64_t callnum, ThreadContext *tc);
virtual SyscallDesc* getDesc(int callnum) = 0;
+
+ // this function is used to create the LiveProcess object, since
+ // we can't tell which subclass of LiveProcess to use until we
+ // open and look at the object file.
+ static LiveProcess *create(const std::string &nm,
+ System *_system,
+ int stdin_fd, int stdout_fd, int stderr_fd,
+ std::string executable,
+ std::vector<std::string> &argv,
+ std::vector<std::string> &envp);
};
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
index 7897b5c8b..b2854e491 100644
--- a/src/sim/pseudo_inst.cc
+++ b/src/sim/pseudo_inst.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <errno.h>
@@ -36,7 +38,8 @@
#include "arch/vtophys.hh"
#include "cpu/base.hh"
#include "cpu/sampler/sampler.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/quiesce_event.hh"
#include "kern/kernel_stats.hh"
#include "sim/param.hh"
#include "sim/serialize.hh"
@@ -61,89 +64,94 @@ namespace AlphaPseudo
bool doQuiesce;
void
- arm(ExecContext *xc)
+ arm(ThreadContext *tc)
{
- xc->getCpuPtr()->kernelStats->arm();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->arm();
}
void
- quiesce(ExecContext *xc)
+ quiesce(ThreadContext *tc)
{
if (!doQuiesce)
return;
- xc->suspend();
- xc->getCpuPtr()->kernelStats->quiesce();
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
}
void
- quiesceNs(ExecContext *xc, uint64_t ns)
+ quiesceNs(ThreadContext *tc, uint64_t ns)
{
if (!doQuiesce || ns == 0)
return;
- Event *quiesceEvent = xc->getQuiesceEvent();
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
if (quiesceEvent->scheduled())
quiesceEvent->reschedule(curTick + Clock::Int::ns * ns);
else
quiesceEvent->schedule(curTick + Clock::Int::ns * ns);
- xc->suspend();
- xc->getCpuPtr()->kernelStats->quiesce();
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
}
void
- quiesceCycles(ExecContext *xc, uint64_t cycles)
+ quiesceCycles(ThreadContext *tc, uint64_t cycles)
{
if (!doQuiesce || cycles == 0)
return;
- Event *quiesceEvent = xc->getQuiesceEvent();
+ EndQuiesceEvent *quiesceEvent = tc->getQuiesceEvent();
if (quiesceEvent->scheduled())
quiesceEvent->reschedule(curTick +
- xc->getCpuPtr()->cycles(cycles));
+ tc->getCpuPtr()->cycles(cycles));
else
quiesceEvent->schedule(curTick +
- xc->getCpuPtr()->cycles(cycles));
+ tc->getCpuPtr()->cycles(cycles));
- xc->suspend();
- xc->getCpuPtr()->kernelStats->quiesce();
+ tc->suspend();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->quiesce();
}
uint64_t
- quiesceTime(ExecContext *xc)
+ quiesceTime(ThreadContext *tc)
{
- return (xc->readLastActivate() - xc->readLastSuspend()) / Clock::Int::ns;
+ return (tc->readLastActivate() - tc->readLastSuspend()) / Clock::Int::ns;
}
void
- ivlb(ExecContext *xc)
+ ivlb(ThreadContext *tc)
{
- xc->getCpuPtr()->kernelStats->ivlb();
+ if (tc->getKernelStats())
+ tc->getKernelStats()->ivlb();
}
void
- ivle(ExecContext *xc)
+ ivle(ThreadContext *tc)
{
}
void
- m5exit_old(ExecContext *xc)
+ m5exit_old(ThreadContext *tc)
{
- SimExit(curTick, "m5_exit_old instruction encountered");
+ exitSimLoop(curTick, "m5_exit_old instruction encountered");
}
void
- m5exit(ExecContext *xc, Tick delay)
+ m5exit(ThreadContext *tc, Tick delay)
{
Tick when = curTick + delay * Clock::Int::ns;
- SimExit(when, "m5_exit instruction encountered");
+ exitSimLoop(when, "m5_exit instruction encountered");
}
void
- resetstats(ExecContext *xc, Tick delay, Tick period)
+ resetstats(ThreadContext *tc, Tick delay, Tick period)
{
if (!doStatisticsInsts)
return;
@@ -157,7 +165,7 @@ namespace AlphaPseudo
}
void
- dumpstats(ExecContext *xc, Tick delay, Tick period)
+ dumpstats(ThreadContext *tc, Tick delay, Tick period)
{
if (!doStatisticsInsts)
return;
@@ -171,19 +179,19 @@ namespace AlphaPseudo
}
void
- addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr)
+ addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr)
{
char symb[100];
- CopyStringOut(xc, symb, symbolAddr, 100);
+ CopyStringOut(tc, symb, symbolAddr, 100);
std::string symbol(symb);
DPRINTF(Loader, "Loaded symbol: %s @ %#llx\n", symbol, addr);
- xc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
+ tc->getSystemPtr()->kernelSymtab->insert(addr,symbol);
}
void
- dumpresetstats(ExecContext *xc, Tick delay, Tick period)
+ dumpresetstats(ThreadContext *tc, Tick delay, Tick period)
{
if (!doStatisticsInsts)
return;
@@ -197,22 +205,16 @@ namespace AlphaPseudo
}
void
- m5checkpoint(ExecContext *xc, Tick delay, Tick period)
+ m5checkpoint(ThreadContext *tc, Tick delay, Tick period)
{
if (!doCheckpointInsts)
return;
-
-
- Tick when = curTick + delay * Clock::Int::ns;
- Tick repeat = period * Clock::Int::ns;
-
- Checkpoint::setup(when, repeat);
}
uint64_t
- readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset)
+ readfile(ThreadContext *tc, Addr vaddr, uint64_t len, uint64_t offset)
{
- const string &file = xc->getCpuPtr()->system->params()->readfile;
+ const string &file = tc->getCpuPtr()->system->params()->readfile;
if (file.empty()) {
return ULL(0);
}
@@ -239,7 +241,7 @@ namespace AlphaPseudo
}
close(fd);
- CopyIn(xc, vaddr, buf, result);
+ CopyIn(tc, vaddr, buf, result);
delete [] buf;
return result;
}
@@ -271,12 +273,12 @@ namespace AlphaPseudo
doCheckpointInsts = __checkpoint;
}
- void debugbreak(ExecContext *xc)
+ void debugbreak(ThreadContext *tc)
{
debug_break();
}
- void switchcpu(ExecContext *xc)
+ void switchcpu(ThreadContext *tc)
{
if (SampCPU)
SampCPU->switchCPUs();
diff --git a/src/sim/pseudo_inst.hh b/src/sim/pseudo_inst.hh
index 4dd427c99..5e5b7d95f 100644
--- a/src/sim/pseudo_inst.hh
+++ b/src/sim/pseudo_inst.hh
@@ -24,9 +24,11 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
-class ExecContext;
+class ThreadContext;
//We need the "Tick" data type from here
#include "sim/host.hh"
@@ -42,21 +44,21 @@ namespace AlphaPseudo
extern bool doCheckpointInsts;
extern bool doQuiesce;
- void arm(ExecContext *xc);
- void quiesce(ExecContext *xc);
- void quiesceNs(ExecContext *xc, uint64_t ns);
- void quiesceCycles(ExecContext *xc, uint64_t cycles);
- uint64_t quiesceTime(ExecContext *xc);
- void ivlb(ExecContext *xc);
- void ivle(ExecContext *xc);
- void m5exit(ExecContext *xc, Tick delay);
- void m5exit_old(ExecContext *xc);
- void resetstats(ExecContext *xc, Tick delay, Tick period);
- void dumpstats(ExecContext *xc, Tick delay, Tick period);
- void dumpresetstats(ExecContext *xc, Tick delay, Tick period);
- void m5checkpoint(ExecContext *xc, Tick delay, Tick period);
- uint64_t readfile(ExecContext *xc, Addr vaddr, uint64_t len, uint64_t offset);
- void debugbreak(ExecContext *xc);
- void switchcpu(ExecContext *xc);
- void addsymbol(ExecContext *xc, Addr addr, Addr symbolAddr);
+ 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 ivlb(ThreadContext *tc);
+ void ivle(ThreadContext *tc);
+ void m5exit(ThreadContext *tc, Tick delay);
+ void m5exit_old(ThreadContext *tc);
+ 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);
}
diff --git a/src/sim/root.cc b/src/sim/root.cc
index 6348ec104..ec5e2f7e2 100644
--- a/src/sim/root.cc
+++ b/src/sim/root.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <cstring>
@@ -37,6 +40,7 @@
#include "sim/builder.hh"
#include "sim/host.hh"
#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
#include "sim/sim_object.hh"
#include "sim/root.hh"
@@ -96,7 +100,7 @@ void
Root::startup()
{
if (max_tick != 0)
- new SimExitEvent(curTick + max_tick, "reached maximum cycle count");
+ exitSimLoop(curTick + max_tick, "reached maximum cycle count");
if (progress_interval != 0)
new ProgressEvent(&mainEventQueue, progress_interval);
diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc
index c4ef124bb..7450d7b7e 100644
--- a/src/sim/serialize.cc
+++ b/src/sim/serialize.cc
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Erik Hallnor
+ * Steve Reinhardt
*/
#include <sys/time.h>
@@ -41,7 +45,6 @@
#include "base/output.hh"
#include "base/str.hh"
#include "base/trace.hh"
-#include "sim/config_node.hh"
#include "sim/eventq.hh"
#include "sim/param.hh"
#include "sim/serialize.hh"
@@ -241,56 +244,41 @@ Serializable::serializeAll()
globals.serialize(outstream);
SimObject::serializeAll(outstream);
-
- assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount);
- Serializable::ckptPrevCount++;
- if (ckptMaxCount && ++ckptCount >= ckptMaxCount)
- SimExit(curTick + 1, "Maximum number of checkpoints dropped");
-
}
-
void
-Serializable::unserializeGlobals(Checkpoint *cp)
+Serializable::unserializeAll()
{
- globals.unserialize(cp);
-}
-
-
-class SerializeEvent : public Event
-{
- protected:
- Tick repeat;
-
- public:
- SerializeEvent(Tick _when, Tick _repeat);
- virtual void process();
- virtual void serialize(std::ostream &os)
- {
- panic("Cannot serialize the SerializeEvent");
- }
+ string dir = Checkpoint::dir();
+ string cpt_file = dir + Checkpoint::baseFilename;
+ string section = "";
-};
+ DPRINTFR(Config, "Loading checkpoint dir '%s'\n",
+ dir);
+ Checkpoint *cp = new Checkpoint(dir, section);
+ unserializeGlobals(cp);
-SerializeEvent::SerializeEvent(Tick _when, Tick _repeat)
- : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat)
-{
- setFlags(AutoDelete);
- schedule(_when);
+ SimObject::unserializeAll(cp);
}
void
-SerializeEvent::process()
+Serializable::unserializeGlobals(Checkpoint *cp)
{
- Serializable::serializeAll();
- if (repeat)
- schedule(curTick + repeat);
+ globals.unserialize(cp);
}
const char *Checkpoint::baseFilename = "m5.cpt";
static string checkpointDirBase;
+void
+setCheckpointDir(const std::string &name)
+{
+ checkpointDirBase = name;
+ if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
+ checkpointDirBase += "/";
+}
+
string
Checkpoint::dir()
{
@@ -301,75 +289,11 @@ Checkpoint::dir()
}
void
-Checkpoint::setup(Tick when, Tick period)
-{
- new SerializeEvent(when, period);
-}
-
-class SerializeParamContext : public ParamContext
-{
- private:
- SerializeEvent *event;
-
- public:
- SerializeParamContext(const string &section);
- ~SerializeParamContext();
- void checkParams();
-};
-
-SerializeParamContext serialParams("serialize");
-
-Param<string> serialize_dir(&serialParams, "dir",
- "dir to stick checkpoint in "
- "(sprintf format with cycle #)");
-
-Param<Counter> serialize_cycle(&serialParams,
- "cycle",
- "cycle to serialize",
- 0);
-
-Param<Counter> serialize_period(&serialParams,
- "period",
- "period to repeat serializations",
- 0);
-
-Param<int> serialize_count(&serialParams, "count",
- "maximum number of checkpoints to drop");
-
-SerializeParamContext::SerializeParamContext(const string &section)
- : ParamContext(section), event(NULL)
-{ }
-
-SerializeParamContext::~SerializeParamContext()
-{
-}
-
-void
-SerializeParamContext::checkParams()
-{
- checkpointDirBase = simout.resolve(serialize_dir);
-
- // guarantee that directory ends with a '/'
- if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
- checkpointDirBase += "/";
-
- if (serialize_cycle > 0)
- Checkpoint::setup(serialize_cycle, serialize_period);
-
- Serializable::ckptMaxCount = serialize_count;
-}
-
-void
debug_serialize()
{
Serializable::serializeAll();
}
-void
-debug_serialize(Tick when)
-{
- new SerializeEvent(when, 0);
-}
////////////////////////////////////////////////////////////////////////
//
@@ -439,9 +363,8 @@ Serializable::create(Checkpoint *cp, const std::string &section)
}
-Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path,
- const ConfigNode *_configNode)
- : db(new IniFile), basePath(path), configNode(_configNode), cptDir(cpt_dir)
+Checkpoint::Checkpoint(const std::string &cpt_dir, const std::string &path)
+ : db(new IniFile), basePath(path), cptDir(cpt_dir)
{
string filename = cpt_dir + "/" + Checkpoint::baseFilename;
if (!db->load(filename)) {
@@ -467,9 +390,6 @@ Checkpoint::findObj(const std::string &section, const std::string &entry,
if (!db->find(section, entry, path))
return false;
- if ((value = configNode->resolveSimObject(path)) != NULL)
- return true;
-
if ((value = objMap[path]) != NULL)
return true;
diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh
index d8f5f8fc5..a80dc99e4 100644
--- a/src/sim/serialize.hh
+++ b/src/sim/serialize.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Erik Hallnor
+ * Steve Reinhardt
*/
/* @file
@@ -39,8 +43,8 @@
#include <map>
#include "sim/host.hh"
-#include "sim/configfile.hh"
+class IniFile;
class Serializable;
class Checkpoint;
@@ -123,6 +127,7 @@ class Serializable
static int ckptMaxCount;
static int ckptPrevCount;
static void serializeAll();
+ static void unserializeAll();
static void unserializeGlobals(Checkpoint *cp);
};
@@ -174,7 +179,7 @@ class SerializableClass
// an optional config hierarchy node (specified by the third
// argument). A pointer to the new SerializableBuilder is returned.
typedef Serializable *(*CreateFunc)(Checkpoint *cp,
- const std::string &section);
+ const std::string &section);
static std::map<std::string,CreateFunc> *classMap;
@@ -188,7 +193,7 @@ class SerializableClass
// create Serializable given name of class and pointer to
// configuration hierarchy node
static Serializable *createObject(Checkpoint *cp,
- const std::string &section);
+ const std::string &section);
};
//
@@ -200,18 +205,19 @@ class SerializableClass
SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \
OBJ_CLASS::createForUnserialize);
+void
+setCheckpointName(const std::string &name);
+
class Checkpoint
{
private:
IniFile *db;
const std::string basePath;
- const ConfigNode *configNode;
std::map<std::string, Serializable*> objMap;
public:
- Checkpoint(const std::string &cpt_dir, const std::string &path,
- const ConfigNode *_configNode);
+ Checkpoint(const std::string &cpt_dir, const std::string &path);
const std::string cptDir;
@@ -235,9 +241,6 @@ class Checkpoint
// Filename for base checkpoint file within directory.
static const char *baseFilename;
-
- // Set up a checkpoint creation event or series of events.
- static void setup(Tick when, Tick period = 0);
};
#endif // __SERIALIZE_HH__
diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc
index c2bdca9df..97f7ae03c 100644
--- a/src/sim/sim_events.cc
+++ b/src/sim/sim_events.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <string>
@@ -43,26 +45,45 @@ using namespace std;
// handle termination event
//
void
-SimExitEvent::process()
+SimLoopExitEvent::process()
{
- // This event does not autodelete because exitNow may be called,
- // and the function will never be allowed to finish.
- if (theQueue() == &mainEventQueue) {
- string _cause = cause;
- int _code = code;
- delete this;
- exitNow(_cause, _code);
- } else {
- new SimExitEvent(cause, code);
+ // 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) {
+ exitSimLoop(cause, code);
delete this;
}
+
+ // otherwise do nothing... the IsExitEvent flag takes care of
+ // exiting the simulation loop and returning this object to Python
}
const char *
-SimExitEvent::description()
+SimLoopExitEvent::description()
+{
+ return "simulation loop exit";
+}
+
+void
+exitSimLoop(Tick when, const std::string &message, int exit_code)
+{
+ new SimLoopExitEvent(when, message, exit_code);
+}
+
+void
+exitSimLoop(const std::string &message, int exit_code)
+{
+ exitSimLoop(curTick, message, exit_code);
+}
+
+void
+CountedQuiesceEvent::process()
{
- return "simulation termination";
+ if (--count == 0) {
+ exitSimLoop("Finished quiesce");
+ }
}
//
@@ -88,7 +109,7 @@ void
CountedExitEvent::process()
{
if (--downCounter == 0) {
- new SimExitEvent(cause, 0);
+ exitSimLoop(cause, 0);
}
}
@@ -117,7 +138,7 @@ CheckSwapEvent::process()
if (swap < 100) {
cerr << "\a\aAborting Simulation! Inadequate swap space!\n\n";
- new SimExitEvent("Lack of swap space");
+ exitSimLoop("Lack of swap space");
}
schedule(curTick + interval);
diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh
index c93914457..50368f258 100644
--- a/src/sim/sim_events.hh
+++ b/src/sim/sim_events.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SIM_SIM_EVENTS_HH__
@@ -34,7 +36,7 @@
//
// Event to terminate simulation at a particular cycle/instruction
//
-class SimExitEvent : public Event
+class SimLoopExitEvent : public Event
{
private:
// string explaining why we're terminating
@@ -42,30 +44,45 @@ class SimExitEvent : public Event
int code;
public:
- SimExitEvent(const std::string &_cause, int c = 0)
- : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
- code(c)
- { schedule(curTick); }
+ // Default constructor. Only really used for derived classes.
+ SimLoopExitEvent()
+ : Event(&mainEventQueue, Sim_Exit_Pri)
+ { }
- SimExitEvent(Tick _when, const std::string &_cause, int c = 0)
+ SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0)
: Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause),
code(c)
- { schedule(_when); }
+ { setFlags(IsExitEvent); schedule(_when); }
- SimExitEvent(EventQueue *q, const std::string &_cause, int c = 0)
+ SimLoopExitEvent(EventQueue *q,
+ Tick _when, const std::string &_cause, int c = 0)
: Event(q, Sim_Exit_Pri), cause(_cause), code(c)
- { schedule(curTick); }
+ { setFlags(IsExitEvent); schedule(_when); }
- SimExitEvent(EventQueue *q, Tick _when, const std::string &_cause,
- int c = 0)
- : Event(q, Sim_Exit_Pri), cause(_cause), code(c)
- { schedule(_when); }
+ std::string getCause() { return cause; }
+ int getCode() { return code; }
void process(); // process event
virtual const char *description();
};
+class CountedQuiesceEvent : public SimLoopExitEvent
+{
+ private:
+ // Count down to quiescing
+ int count;
+ public:
+ CountedQuiesceEvent()
+ : count(0)
+ { }
+ void process();
+
+ void setCount(int _count) { count = _count; }
+
+ int getCount() { return count; }
+};
+
//
// Event class to terminate simulation after 'n' related events have
// occurred using a shared counter: used to terminate when *all*
diff --git a/src/sim/sim_exit.hh b/src/sim/sim_exit.hh
index f14256933..545bf4ae0 100644
--- a/src/sim/sim_exit.hh
+++ b/src/sim/sim_exit.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ * Steve Reinhardt
*/
#ifndef __SIM_EXIT_HH__
@@ -33,12 +36,23 @@
#include "sim/host.hh"
+// forward declaration
class Callback;
+/// Register a callback to be called when Python exits. Defined in
+/// sim/main.cc.
void registerExitCallback(Callback *);
-void exitNow(const std::string &cause, int exit_code);
-void exitNow(const char *cause, int exit_code);
-void SimExit(Tick when, const char *message);
+/// 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.
+void exitSimLoop(Tick when, const std::string &message, 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.
+void exitSimLoop(const std::string &cause, int exit_code = 0);
#endif // __SIM_EXIT_HH__
diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc
index 17d58ba4f..551555b25 100644
--- a/src/sim/sim_object.cc
+++ b/src/sim/sim_object.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <assert.h>
@@ -35,7 +38,6 @@
#include "base/trace.hh"
#include "base/stats/events.hh"
#include "base/serializer.hh"
-#include "sim/configfile.hh"
#include "sim/host.hh"
#include "sim/sim_object.hh"
#include "sim/stats.hh"
@@ -71,6 +73,7 @@ SimObject::SimObject(Params *p)
doRecordEvent = !Stats::event_ignore.match(name());
simObjectList.push_back(this);
+ state = Atomic;
}
//
@@ -86,6 +89,7 @@ SimObject::SimObject(const string &_name)
doRecordEvent = !Stats::event_ignore.match(name());
simObjectList.push_back(this);
+ state = Atomic;
}
void
@@ -217,6 +221,24 @@ SimObject::serializeAll(ostream &os)
}
}
+void
+SimObject::unserializeAll(Checkpoint *cp)
+{
+ SimObjectList::reverse_iterator ri = simObjectList.rbegin();
+ SimObjectList::reverse_iterator rend = simObjectList.rend();
+
+ for (; ri != rend; ++ri) {
+ SimObject *obj = *ri;
+ DPRINTFR(Config, "Unserializing '%s'\n",
+ obj->name());
+ if(cp->sectionExists(obj->name()))
+ obj->unserialize(cp, obj->name());
+ else
+ warn("Not unserializing '%s': no section found in checkpoint.\n",
+ obj->name());
+ }
+}
+
#ifdef DEBUG
//
// static function: flag which objects should have the debugger break
@@ -234,7 +256,6 @@ SimObject::debugObjectBreak(const string &objs)
}
}
-extern "C"
void
debugObjectBreak(const char *objs)
{
@@ -249,10 +270,50 @@ SimObject::recordEvent(const std::string &stat)
Stats::recordEvent(stat);
}
+bool
+SimObject::quiesce(Event *quiesce_event)
+{
+ if (state != QuiescedAtomic && state != Atomic) {
+ panic("Must implement your own quiesce function if it is to be used "
+ "in timing mode!");
+ }
+ state = QuiescedAtomic;
+ return false;
+}
+
+void
+SimObject::resume()
+{
+ if (state == QuiescedAtomic) {
+ state = Atomic;
+ } else if (state == QuiescedTiming) {
+ state = Timing;
+ }
+}
+
+void
+SimObject::setMemoryMode(State new_mode)
+{
+ assert(new_mode == Timing || new_mode == Atomic);
+ if (state == QuiescedAtomic && new_mode == Timing) {
+ state = QuiescedTiming;
+ } else if (state == QuiescedTiming && new_mode == Atomic) {
+ state = QuiescedAtomic;
+ } else {
+ state = new_mode;
+ }
+}
+
+void
+SimObject::switchOut()
+{
+ panic("Unimplemented!");
+}
+
void
-SimObject::drain(Serializer *serializer)
+SimObject::takeOverFrom(BaseCPU *cpu)
{
- serializer->signalDrained();
+ panic("Unimplemented!");
}
DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject)
diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh
index 76aba7ea1..e0b21782f 100644
--- a/src/sim/sim_object.hh
+++ b/src/sim/sim_object.hh
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
/* @file
@@ -41,7 +44,8 @@
#include "sim/serialize.hh"
#include "sim/startup.hh"
-class Serializer;
+class BaseCPU;
+class Event;
/*
* Abstract superclass for simulation objects. Represents things that
@@ -55,15 +59,26 @@ class SimObject : public Serializable, protected StartupCallback
std::string name;
};
+ enum State {
+ Atomic,
+ Timing,
+ Quiescing,
+ QuiescedAtomic,
+ QuiescedTiming
+ };
+
protected:
Params *_params;
+ State state;
+
+ void changeState(State new_state) { state = new_state; }
public:
const Params *params() const { return _params; }
- private:
- friend class Serializer;
+ State getState() { return state; }
+ private:
typedef std::vector<SimObject *> SimObjectList;
// list of all instantiated simulation objects
@@ -97,13 +112,16 @@ class SimObject : public Serializable, protected StartupCallback
// static: call nameOut() & serialize() on all SimObjects
static void serializeAll(std::ostream &);
+ static void unserializeAll(Checkpoint *cp);
// Methods to drain objects in order to take checkpoints
// Or switch from timing -> atomic memory model
- virtual void drain(Serializer *serializer);
- virtual void resume() { return;} ;
- virtual void serializationComplete()
- { assert(0 && "Unimplemented"); };
+ // Quiesce returns true if the SimObject cannot quiesce immediately.
+ virtual bool quiesce(Event *quiesce_event);
+ virtual void resume();
+ virtual void setMemoryMode(State new_mode);
+ virtual void switchOut();
+ virtual void takeOverFrom(BaseCPU *cpu);
#ifdef DEBUG
public:
diff --git a/src/sim/startup.cc b/src/sim/startup.cc
index 683e6c746..838352107 100644
--- a/src/sim/startup.cc
+++ b/src/sim/startup.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
*/
#include <list>
diff --git a/src/sim/startup.hh b/src/sim/startup.hh
index 3c9b654f1..cfc4450f4 100644
--- a/src/sim/startup.hh
+++ b/src/sim/startup.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SIM_STARTUP_HH__
diff --git a/src/sim/stat_control.cc b/src/sim/stat_control.cc
index 85c405b7f..041830ab7 100644
--- a/src/sim/stat_control.cc
+++ b/src/sim/stat_control.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 will contain default statistics for the simulator that
@@ -219,8 +221,7 @@ SetupEvent(int flags, Tick when, Tick repeat)
/* namespace Stats */ }
-extern "C" void
-debugDumpStats()
+void debugDumpStats()
{
Stats::DumpNow();
}
diff --git a/src/sim/stat_control.hh b/src/sim/stat_control.hh
index a22ce76af..fb369f640 100644
--- a/src/sim/stat_control.hh
+++ b/src/sim/stat_control.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SIM_STAT_CONTROL_HH__
diff --git a/src/sim/stats.hh b/src/sim/stats.hh
index 8e97d041f..97251283d 100644
--- a/src/sim/stats.hh
+++ b/src/sim/stats.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __SIM_STATS_HH__
diff --git a/src/sim/syscall_emul.cc b/src/sim/syscall_emul.cc
index ed0da628e..e72890612 100644
--- a/src/sim/syscall_emul.cc
+++ b/src/sim/syscall_emul.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Ali Saidi
*/
#include <fcntl.h>
@@ -35,37 +38,37 @@
#include "sim/syscall_emul.hh"
#include "base/chunk_generator.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "cpu/base.hh"
#include "mem/page_table.hh"
#include "sim/process.hh"
-#include "sim/sim_events.hh"
+#include "sim/sim_exit.hh"
using namespace std;
using namespace TheISA;
void
-SyscallDesc::doSyscall(int callnum, Process *process, ExecContext *xc)
+SyscallDesc::doSyscall(int callnum, Process *process, ThreadContext *tc)
{
DPRINTFR(SyscallVerbose, "%d: %s: syscall %s called w/arguments %d,%d,%d,%d\n",
- curTick,xc->getCpuPtr()->name(), name,
- xc->getSyscallArg(0),xc->getSyscallArg(1),
- xc->getSyscallArg(2),xc->getSyscallArg(3));
+ curTick,tc->getCpuPtr()->name(), name,
+ tc->getSyscallArg(0),tc->getSyscallArg(1),
+ tc->getSyscallArg(2),tc->getSyscallArg(3));
- SyscallReturn retval = (*funcPtr)(this, callnum, process, xc);
+ SyscallReturn retval = (*funcPtr)(this, callnum, process, tc);
DPRINTFR(SyscallVerbose, "%d: %s: syscall %s returns %d\n",
- curTick,xc->getCpuPtr()->name(), name, retval.value());
+ curTick,tc->getCpuPtr()->name(), name, retval.value());
if (!(flags & SyscallDesc::SuppressReturnValue))
- xc->setSyscallReturn(retval);
+ tc->setSyscallReturn(retval);
}
SyscallReturn
unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
fatal("syscall %s (#%d) unimplemented.", desc->name, callnum);
@@ -75,10 +78,10 @@ unimplementedFunc(SyscallDesc *desc, int callnum, Process *process,
SyscallReturn
ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
warn("ignoring syscall %s(%d, %d, ...)", desc->name,
- xc->getSyscallArg(0), xc->getSyscallArg(1));
+ tc->getSyscallArg(0), tc->getSyscallArg(1));
return 0;
}
@@ -86,28 +89,30 @@ ignoreFunc(SyscallDesc *desc, int callnum, Process *process,
SyscallReturn
exitFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- new SimExitEvent("target called exit()", xc->getSyscallArg(0) & 0xff);
+ if (tc->exit()) {
+ exitSimLoop("target called exit()", tc->getSyscallArg(0) & 0xff);
+ }
return 1;
}
SyscallReturn
-getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+getpagesizeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
return (int)VMPageSize;
}
SyscallReturn
-obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+obreakFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
Addr junk;
// change brk addr to first arg
- Addr new_brk = xc->getSyscallArg(0);
+ Addr new_brk = tc->getSyscallArg(0);
if (new_brk != 0) {
for (ChunkGenerator gen(p->brk_point, new_brk - p->brk_point,
VMPageSize); !gen.done(); gen.next()) {
@@ -123,9 +128,9 @@ obreakFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
SyscallReturn
-closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+closeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- int target_fd = xc->getSyscallArg(0);
+ int target_fd = tc->getSyscallArg(0);
int status = close(p->sim_fd(target_fd));
if (status >= 0)
p->free_fd(target_fd);
@@ -134,28 +139,28 @@ closeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
SyscallReturn
-readFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+readFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- int fd = p->sim_fd(xc->getSyscallArg(0));
- int nbytes = xc->getSyscallArg(2);
- BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
int bytes_read = read(fd, bufArg.bufferPtr(), nbytes);
if (bytes_read != -1)
- bufArg.copyOut(xc->getMemPort());
+ bufArg.copyOut(tc->getMemPort());
return bytes_read;
}
SyscallReturn
-writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+writeFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- int fd = p->sim_fd(xc->getSyscallArg(0));
- int nbytes = xc->getSyscallArg(2);
- BufferArg bufArg(xc->getSyscallArg(1), nbytes);
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ int nbytes = tc->getSyscallArg(2);
+ BufferArg bufArg(tc->getSyscallArg(1), nbytes);
- bufArg.copyIn(xc->getMemPort());
+ bufArg.copyIn(tc->getMemPort());
int bytes_written = write(fd, bufArg.bufferPtr(), nbytes);
@@ -166,11 +171,11 @@ writeFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
SyscallReturn
-lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+lseekFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- int fd = p->sim_fd(xc->getSyscallArg(0));
- uint64_t offs = xc->getSyscallArg(1);
- int whence = xc->getSyscallArg(2);
+ int fd = p->sim_fd(tc->getSyscallArg(0));
+ uint64_t offs = tc->getSyscallArg(1);
+ int whence = tc->getSyscallArg(2);
off_t result = lseek(fd, offs, whence);
@@ -179,7 +184,7 @@ lseekFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
SyscallReturn
-munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+munmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
// given that we don't really implement mmap, munmap is really easy
return 0;
@@ -189,24 +194,24 @@ munmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
const char *hostname = "m5.eecs.umich.edu";
SyscallReturn
-gethostnameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+gethostnameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- int name_len = xc->getSyscallArg(1);
- BufferArg name(xc->getSyscallArg(0), name_len);
+ int name_len = tc->getSyscallArg(1);
+ BufferArg name(tc->getSyscallArg(0), name_len);
strncpy((char *)name.bufferPtr(), hostname, name_len);
- name.copyOut(xc->getMemPort());
+ name.copyOut(tc->getMemPort());
return 0;
}
SyscallReturn
-unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+unlinkFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return (TheISA::IntReg)-EFAULT;
int result = unlink(path.c_str());
@@ -214,16 +219,16 @@ unlinkFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
SyscallReturn
-renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+renameFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
string old_name;
- if (!xc->getMemPort()->tryReadString(old_name, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(old_name, tc->getSyscallArg(0)))
return -EFAULT;
string new_name;
- if (!xc->getMemPort()->tryReadString(new_name, xc->getSyscallArg(1)))
+ if (!tc->getMemPort()->tryReadString(new_name, tc->getSyscallArg(1)))
return -EFAULT;
int64_t result = rename(old_name.c_str(), new_name.c_str());
@@ -231,45 +236,45 @@ renameFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
SyscallReturn
-truncateFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+truncateFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
- off_t length = xc->getSyscallArg(1);
+ off_t length = tc->getSyscallArg(1);
int result = truncate(path.c_str(), length);
return (result == -1) ? -errno : result;
}
SyscallReturn
-ftruncateFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc)
+ftruncateFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
{
- int fd = process->sim_fd(xc->getSyscallArg(0));
+ int fd = process->sim_fd(tc->getSyscallArg(0));
if (fd < 0)
return -EBADF;
- off_t length = xc->getSyscallArg(1);
+ off_t length = tc->getSyscallArg(1);
int result = ftruncate(fd, length);
return (result == -1) ? -errno : result;
}
SyscallReturn
-chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+chownFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
/* XXX endianess */
- uint32_t owner = xc->getSyscallArg(1);
+ uint32_t owner = tc->getSyscallArg(1);
uid_t hostOwner = owner;
- uint32_t group = xc->getSyscallArg(2);
+ uint32_t group = tc->getSyscallArg(2);
gid_t hostGroup = group;
int result = chown(path.c_str(), hostOwner, hostGroup);
@@ -277,17 +282,17 @@ chownFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
}
SyscallReturn
-fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc)
+fchownFunc(SyscallDesc *desc, int num, Process *process, ThreadContext *tc)
{
- int fd = process->sim_fd(xc->getSyscallArg(0));
+ int fd = process->sim_fd(tc->getSyscallArg(0));
if (fd < 0)
return -EBADF;
/* XXX endianess */
- uint32_t owner = xc->getSyscallArg(1);
+ uint32_t owner = tc->getSyscallArg(1);
uid_t hostOwner = owner;
- uint32_t group = xc->getSyscallArg(2);
+ uint32_t group = tc->getSyscallArg(2);
gid_t hostGroup = group;
int result = fchown(fd, hostOwner, hostGroup);
@@ -297,14 +302,14 @@ fchownFunc(SyscallDesc *desc, int num, Process *process, ExecContext *xc)
SyscallReturn
fcntlFunc(SyscallDesc *desc, int num, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = xc->getSyscallArg(0);
+ int fd = tc->getSyscallArg(0);
if (fd < 0 || process->sim_fd(fd) < 0)
return -EBADF;
- int cmd = xc->getSyscallArg(1);
+ int cmd = tc->getSyscallArg(1);
switch (cmd) {
case 0: // F_DUPFD
// if we really wanted to support this, we'd need to do it
@@ -338,8 +343,37 @@ fcntlFunc(SyscallDesc *desc, int num, Process *process,
}
SyscallReturn
+fcntl64Func(SyscallDesc *desc, int num, Process *process,
+ ThreadContext *tc)
+{
+ int fd = tc->getSyscallArg(0);
+
+ if (fd < 0 || process->sim_fd(fd) < 0)
+ return -EBADF;
+
+ int cmd = tc->getSyscallArg(1);
+ switch (cmd) {
+ case 33: //F_GETLK64
+ warn("fcntl64(%d, F_GETLK64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ case 34: // F_SETLK64
+ case 35: // F_SETLKW64
+ warn("fcntl64(%d, F_SETLK(W)64) not supported, error returned\n", fd);
+ return -EMFILE;
+
+ default:
+ // not sure if this is totally valid, but we'll pass it through
+ // to the underlying OS
+ warn("fcntl64(%d, %d) passed through to host\n", fd, cmd);
+ return fcntl(process->sim_fd(fd), cmd);
+ // return 0;
+ }
+}
+
+SyscallReturn
pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
int fds[2], sim_fds[2];
int pipe_retval = pipe(fds);
@@ -354,99 +388,99 @@ pipePseudoFunc(SyscallDesc *desc, int callnum, Process *process,
// Alpha Linux convention for pipe() is that fd[0] is returned as
// the return value of the function, and fd[1] is returned in r20.
- xc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
+ tc->setIntReg(SyscallPseudoReturnReg, sim_fds[1]);
return sim_fds[0];
}
SyscallReturn
getpidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// Make up a PID. There's no interprocess communication in
// fake_syscall mode, so there's no way for a process to know it's
// not getting a unique value.
- xc->setIntReg(SyscallPseudoReturnReg, 99);
+ tc->setIntReg(SyscallPseudoReturnReg, 99);
return 100;
}
SyscallReturn
getuidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// Make up a UID and EUID... it shouldn't matter, and we want the
// simulation to be deterministic.
// EUID goes in r20.
- xc->setIntReg(SyscallPseudoReturnReg, 100); //EUID
+ tc->setIntReg(SyscallPseudoReturnReg, 100); //EUID
return 100; // UID
}
SyscallReturn
getgidPseudoFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// Get current group ID. EGID goes in r20.
- xc->setIntReg(SyscallPseudoReturnReg, 100); //EGID
+ tc->setIntReg(SyscallPseudoReturnReg, 100); //EGID
return 100;
}
SyscallReturn
setuidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// can't fathom why a benchmark would call this.
- warn("Ignoring call to setuid(%d)\n", xc->getSyscallArg(0));
+ warn("Ignoring call to setuid(%d)\n", tc->getSyscallArg(0));
return 0;
}
SyscallReturn
getpidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
// Make up a PID. There's no interprocess communication in
// fake_syscall mode, so there's no way for a process to know it's
// not getting a unique value.
- xc->setIntReg(SyscallPseudoReturnReg, 99); //PID
+ tc->setIntReg(SyscallPseudoReturnReg, 99); //PID
return 100;
}
SyscallReturn
getppidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 99;
}
SyscallReturn
getuidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 100; // UID
}
SyscallReturn
geteuidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 100; // UID
}
SyscallReturn
getgidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 100;
}
SyscallReturn
getegidFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
return 100;
}
diff --git a/src/sim/syscall_emul.hh b/src/sim/syscall_emul.hh
index 00f016410..a3990e2fd 100644
--- a/src/sim/syscall_emul.hh
+++ b/src/sim/syscall_emul.hh
@@ -24,13 +24,17 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Kevin Lim
+ * Korey Sewell
*/
#ifndef __SIM_SYSCALL_EMUL_HH__
#define __SIM_SYSCALL_EMUL_HH__
-#define BSD_HOST (defined(__APPLE__) || defined(__OpenBSD__) || \
- defined(__FreeBSD__))
+#define NO_STAT64 (defined(__APPLE__) || defined(__OpenBSD__) || \
+ defined(__FreeBSD__) || defined(__CYGWIN__))
///
/// @file syscall_emul.hh
@@ -51,7 +55,7 @@
#include "base/misc.hh"
#include "base/trace.hh"
#include "cpu/base.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/translating_port.hh"
#include "mem/page_table.hh"
#include "sim/process.hh"
@@ -65,7 +69,7 @@ class SyscallDesc {
/// Typedef for target syscall handler functions.
typedef SyscallReturn (*FuncPtr)(SyscallDesc *, int num,
- Process *, ExecContext *);
+ Process *, ThreadContext *);
const char *name; //!< Syscall name (e.g., "open").
FuncPtr funcPtr; //!< Pointer to emulation function.
@@ -75,7 +79,7 @@ class SyscallDesc {
enum Flags {
/// Don't set return regs according to funcPtr return value.
/// Used for syscalls with non-standard return conventions
- /// that explicitly set the ExecContext regs (e.g.,
+ /// that explicitly set the ThreadContext regs (e.g.,
/// sigreturn).
SuppressReturnValue = 1
};
@@ -87,7 +91,7 @@ class SyscallDesc {
}
/// Emulate the syscall. Public interface for calling through funcPtr.
- void doSyscall(int callnum, Process *proc, ExecContext *xc);
+ void doSyscall(int callnum, Process *proc, ThreadContext *tc);
};
@@ -169,129 +173,133 @@ class TypedBufferArg : public BaseBufferArg
/// Handler for unimplemented syscalls that we haven't thought about.
SyscallReturn unimplementedFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Handler for unimplemented syscalls that we never intend to
/// implement (signal handling, etc.) and should not affect the correct
/// behavior of the program. Print a warning only if the appropriate
/// trace flag is enabled. Return success to the target program.
SyscallReturn ignoreFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target exit() handler: terminate simulation.
SyscallReturn exitFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getpagesize() handler.
SyscallReturn getpagesizeFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target obreak() handler: set brk address.
SyscallReturn obreakFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target close() handler.
SyscallReturn closeFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target read() handler.
SyscallReturn readFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target write() handler.
SyscallReturn writeFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target lseek() handler.
SyscallReturn lseekFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target munmap() handler.
SyscallReturn munmapFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target gethostname() handler.
SyscallReturn gethostnameFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target unlink() handler.
SyscallReturn unlinkFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target rename() handler.
SyscallReturn renameFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target truncate() handler.
SyscallReturn truncateFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target ftruncate() handler.
SyscallReturn ftruncateFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target chown() handler.
SyscallReturn chownFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target fchown() handler.
SyscallReturn fchownFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target fnctl() handler.
SyscallReturn fcntlFunc(SyscallDesc *desc, int num,
- Process *process, ExecContext *xc);
+ Process *process, ThreadContext *tc);
+
+/// Target fcntl64() handler.
+SyscallReturn fcntl64Func(SyscallDesc *desc, int num,
+ Process *process, ThreadContext *tc);
/// Target setuid() handler.
SyscallReturn setuidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getpid() handler.
SyscallReturn getpidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getuid() handler.
SyscallReturn getuidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getgid() handler.
SyscallReturn getgidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getppid() handler.
SyscallReturn getppidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target geteuid() handler.
SyscallReturn geteuidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getegid() handler.
SyscallReturn getegidFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Pseudo Funcs - These functions use a different return convension,
/// returning a second value in a register other than the normal return register
SyscallReturn pipePseudoFunc(SyscallDesc *desc, int num,
- Process *process, ExecContext *xc);
+ Process *process, ThreadContext *tc);
/// Target getpidPseudo() handler.
SyscallReturn getpidPseudoFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getuidPseudo() handler.
SyscallReturn getuidPseudoFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// Target getgidPseudo() handler.
SyscallReturn getgidPseudoFunc(SyscallDesc *desc, int num,
- Process *p, ExecContext *xc);
+ Process *p, ThreadContext *tc);
/// This struct is used to build an target-OS-dependent table that
@@ -335,10 +343,10 @@ getElapsedTime(T1 &sec, T2 &usec)
template <class OS>
SyscallReturn
ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = xc->getSyscallArg(0);
- unsigned req = xc->getSyscallArg(1);
+ int fd = tc->getSyscallArg(0);
+ unsigned req = tc->getSyscallArg(1);
DPRINTF(SyscallVerbose, "ioctl(%d, 0x%x, ...)\n", fd, req);
@@ -360,7 +368,7 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
default:
fatal("Unsupported ioctl call: ioctl(%d, 0x%x, ...) @ 0x%llx\n",
- fd, req, xc->readPC());
+ fd, req, tc->readPC());
}
}
@@ -368,11 +376,11 @@ ioctlFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
openFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
if (path == "/dev/sysdev0") {
@@ -382,8 +390,8 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
return -ENOENT;
}
- int tgtFlags = xc->getSyscallArg(1);
- int mode = xc->getSyscallArg(2);
+ int tgtFlags = tc->getSyscallArg(1);
+ int mode = tc->getSyscallArg(2);
int hostFlags = 0;
// translate open flags
@@ -415,14 +423,14 @@ openFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
chmodFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
- uint32_t mode = xc->getSyscallArg(1);
+ uint32_t mode = tc->getSyscallArg(1);
mode_t hostMode = 0;
// XXX translate mode flags via OS::something???
@@ -441,15 +449,15 @@ chmodFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = xc->getSyscallArg(0);
+ int fd = tc->getSyscallArg(0);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
- uint32_t mode = xc->getSyscallArg(1);
+ uint32_t mode = tc->getSyscallArg(1);
mode_t hostMode = 0;
// XXX translate mode flags via OS::someting???
@@ -468,11 +476,11 @@ fchmodFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
statFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
struct stat hostBuf;
@@ -481,7 +489,7 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -491,15 +499,15 @@ statFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
fstat64Func(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = xc->getSyscallArg(0);
+ int fd = tc->getSyscallArg(0);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
-#if BSD_HOST
+#if NO_STAT64
struct stat hostBuf;
int result = fstat(process->sim_fd(fd), &hostBuf);
#else
@@ -510,7 +518,7 @@ fstat64Func(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStat64Buf(xc->getMemPort(), fd, xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStat64Buf(tc->getMemPort(), fd, tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -520,11 +528,11 @@ fstat64Func(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
lstatFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
struct stat hostBuf;
@@ -533,7 +541,7 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -542,14 +550,14 @@ lstatFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
lstat64Func(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
-#if BSD_HOST
+#if NO_STAT64
struct stat hostBuf;
int result = lstat(path.c_str(), &hostBuf);
#else
@@ -560,7 +568,7 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStat64Buf(xc->getMemPort(), -1, xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStat64Buf(tc->getMemPort(), -1, tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -569,9 +577,9 @@ lstat64Func(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
fstatFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = process->sim_fd(xc->getSyscallArg(0));
+ int fd = process->sim_fd(tc->getSyscallArg(0));
DPRINTF(SyscallVerbose, "fstat(%d, ...)\n", fd);
@@ -584,7 +592,7 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStatBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -594,11 +602,11 @@ fstatFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
statfsFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
struct statfs hostBuf;
@@ -607,7 +615,7 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -617,9 +625,9 @@ statfsFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = process->sim_fd(xc->getSyscallArg(0));
+ int fd = process->sim_fd(tc->getSyscallArg(0));
if (fd < 0)
return -EBADF;
@@ -630,7 +638,7 @@ fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
if (result < 0)
return -errno;
- OS::copyOutStatfsBuf(xc->getMemPort(), xc->getSyscallArg(1), &hostBuf);
+ OS::copyOutStatfsBuf(tc->getMemPort(), tc->getSyscallArg(1), &hostBuf);
return 0;
}
@@ -640,17 +648,17 @@ fstatfsFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
writevFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int fd = xc->getSyscallArg(0);
+ int fd = tc->getSyscallArg(0);
if (fd < 0 || process->sim_fd(fd) < 0) {
// doesn't map to any simulator fd: not a valid target fd
return -EBADF;
}
- TranslatingPort *p = xc->getMemPort();
- uint64_t tiov_base = xc->getSyscallArg(1);
- size_t count = xc->getSyscallArg(2);
+ TranslatingPort *p = tc->getMemPort();
+ uint64_t tiov_base = tc->getSyscallArg(1);
+ size_t count = tc->getSyscallArg(2);
struct iovec hiov[count];
for (int i = 0; i < count; ++i)
{
@@ -692,14 +700,14 @@ writevFunc(SyscallDesc *desc, int callnum, Process *process,
/// anything else.
template <class OS>
SyscallReturn
-mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
+mmapFunc(SyscallDesc *desc, int num, Process *p, ThreadContext *tc)
{
- Addr start = xc->getSyscallArg(0);
- uint64_t length = xc->getSyscallArg(1);
- // int prot = xc->getSyscallArg(2);
- int flags = xc->getSyscallArg(3);
- // int fd = p->sim_fd(xc->getSyscallArg(4));
- // int offset = xc->getSyscallArg(5);
+ 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);
if ((start % TheISA::VMPageSize) != 0 ||
(length % TheISA::VMPageSize) != 0) {
@@ -721,7 +729,7 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
if (!(flags & OS::TGT_MAP_ANONYMOUS)) {
warn("allowing mmap of file @ fd %d. "
- "This will break if not /dev/zero.", xc->getSyscallArg(4));
+ "This will break if not /dev/zero.", tc->getSyscallArg(4));
}
return start;
@@ -731,10 +739,10 @@ mmapFunc(SyscallDesc *desc, int num, Process *p, ExecContext *xc)
template <class OS>
SyscallReturn
getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- unsigned resource = xc->getSyscallArg(0);
- TypedBufferArg<typename OS::rlimit> rlp(xc->getSyscallArg(1));
+ unsigned resource = tc->getSyscallArg(0);
+ TypedBufferArg<typename OS::rlimit> rlp(tc->getSyscallArg(1));
switch (resource) {
case OS::TGT_RLIMIT_STACK:
@@ -751,7 +759,7 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
break;
}
- rlp.copyOut(xc->getMemPort());
+ rlp.copyOut(tc->getMemPort());
return 0;
}
@@ -759,16 +767,16 @@ getrlimitFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- TypedBufferArg<typename OS::timeval> tp(xc->getSyscallArg(0));
+ TypedBufferArg<typename OS::timeval> tp(tc->getSyscallArg(0));
getElapsedTime(tp->tv_sec, tp->tv_usec);
tp->tv_sec += seconds_since_epoch;
tp->tv_sec = htog(tp->tv_sec);
tp->tv_usec = htog(tp->tv_usec);
- tp.copyOut(xc->getMemPort());
+ tp.copyOut(tc->getMemPort());
return 0;
}
@@ -778,15 +786,15 @@ gettimeofdayFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
utimesFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
std::string path;
- if (!xc->getMemPort()->tryReadString(path, xc->getSyscallArg(0)))
+ if (!tc->getMemPort()->tryReadString(path, tc->getSyscallArg(0)))
return -EFAULT;
- TypedBufferArg<typename OS::timeval [2]> tp(xc->getSyscallArg(1));
- tp.copyIn(xc->getMemPort());
+ TypedBufferArg<typename OS::timeval [2]> tp(tc->getSyscallArg(1));
+ tp.copyIn(tc->getMemPort());
struct timeval hostTimeval[2];
for (int i = 0; i < 2; ++i)
@@ -805,10 +813,10 @@ utimesFunc(SyscallDesc *desc, int callnum, Process *process,
template <class OS>
SyscallReturn
getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
- ExecContext *xc)
+ ThreadContext *tc)
{
- int who = xc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
- TypedBufferArg<typename OS::rusage> rup(xc->getSyscallArg(1));
+ int who = tc->getSyscallArg(0); // THREAD, SELF, or CHILDREN
+ TypedBufferArg<typename OS::rusage> rup(tc->getSyscallArg(1));
if (who != OS::TGT_RUSAGE_SELF) {
// don't really handle THREAD or CHILDREN, but just warn and
@@ -838,7 +846,7 @@ getrusageFunc(SyscallDesc *desc, int callnum, Process *process,
rup->ru_nvcsw = 0;
rup->ru_nivcsw = 0;
- rup.copyOut(xc->getMemPort());
+ rup.copyOut(tc->getMemPort());
return 0;
}
diff --git a/src/sim/system.cc b/src/sim/system.cc
index 89f39491e..89e7b8542 100644
--- a/src/sim/system.cc
+++ b/src/sim/system.cc
@@ -1,8 +1,41 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Lisa Hsu
+ * Nathan Binkert
+ * Ali Saidi
+ */
+
#include "arch/isa_traits.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/trace.hh"
-#include "cpu/exec_context.hh"
+#include "cpu/thread_context.hh"
#include "mem/mem_object.hh"
#include "mem/physical.hh"
#include "sim/builder.hh"
@@ -86,8 +119,6 @@ System::System(Params *p)
DPRINTF(Loader, "Kernel end = %#x\n", kernelEnd);
DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
DPRINTF(Loader, "Kernel loaded...\n");
-
- kernelBinning = new Kernel::Binning(this);
#endif // FULL_SYSTEM
// increment the number of running systms
@@ -99,8 +130,6 @@ System::~System()
#if FULL_SYSTEM
delete kernelSymtab;
delete kernel;
-
- delete kernelBinning;
#else
panic("System::fixFuncEventAddr needs to be rewritten "
"to work with syscall emulation");
@@ -115,26 +144,26 @@ int rgdb_wait = -1;
#endif // FULL_SYSTEM
int
-System::registerExecContext(ExecContext *xc, int id)
+System::registerThreadContext(ThreadContext *tc, int id)
{
if (id == -1) {
- for (id = 0; id < execContexts.size(); id++) {
- if (!execContexts[id])
+ for (id = 0; id < threadContexts.size(); id++) {
+ if (!threadContexts[id])
break;
}
}
- if (execContexts.size() <= id)
- execContexts.resize(id + 1);
+ if (threadContexts.size() <= id)
+ threadContexts.resize(id + 1);
- if (execContexts[id])
+ if (threadContexts[id])
panic("Cannot have two CPUs with the same id (%d)\n", id);
- execContexts[id] = xc;
+ threadContexts[id] = tc;
numcpus++;
#if FULL_SYSTEM
- RemoteGDB *rgdb = new RemoteGDB(this, xc);
+ RemoteGDB *rgdb = new RemoteGDB(this, tc);
GDBListener *gdbl = new GDBListener(rgdb, 7000 + id);
gdbl->listen();
/**
@@ -158,21 +187,21 @@ void
System::startup()
{
int i;
- for (i = 0; i < execContexts.size(); i++)
- execContexts[i]->activate(0);
+ for (i = 0; i < threadContexts.size(); i++)
+ threadContexts[i]->activate(0);
}
void
-System::replaceExecContext(ExecContext *xc, int id)
+System::replaceThreadContext(ThreadContext *tc, int id)
{
- if (id >= execContexts.size()) {
- panic("replaceExecContext: bad id, %d >= %d\n",
- id, execContexts.size());
+ if (id >= threadContexts.size()) {
+ panic("replaceThreadContext: bad id, %d >= %d\n",
+ id, threadContexts.size());
}
- execContexts[id] = xc;
+ threadContexts[id] = tc;
#if FULL_SYSTEM
- remoteGDB[id]->replaceExecContext(xc);
+ remoteGDB[id]->replaceThreadContext(tc);
#endif // FULL_SYSTEM
}
@@ -187,19 +216,9 @@ System::new_page()
#endif
void
-System::regStats()
-{
-#if FULL_SYSTEM
- kernelBinning->regStats(name() + ".kern");
-#endif // FULL_SYSTEM
-}
-
-void
System::serialize(ostream &os)
{
#if FULL_SYSTEM
- kernelBinning->serialize(os);
-
kernelSymtab->serialize("kernel_symtab", os);
#endif // FULL_SYSTEM
}
@@ -209,8 +228,6 @@ void
System::unserialize(Checkpoint *cp, const string &section)
{
#if FULL_SYSTEM
- kernelBinning->unserialize(cp, section);
-
kernelSymtab->unserialize("kernel_symtab", cp, section);
#endif // FULL_SYSTEM
}
@@ -226,7 +243,6 @@ System::printSystems()
}
}
-extern "C"
void
printSystems()
{
diff --git a/src/sim/system.hh b/src/sim/system.hh
index 7e21bd587..059dc92dc 100644
--- a/src/sim/system.hh
+++ b/src/sim/system.hh
@@ -24,6 +24,10 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
+ * Lisa Hsu
+ * Nathan Binkert
*/
#ifndef __SYSTEM_HH__
@@ -44,7 +48,7 @@
#endif
class BaseCPU;
-class ExecContext;
+class ThreadContext;
class ObjectFile;
class PhysicalMemory;
@@ -52,7 +56,6 @@ class PhysicalMemory;
class Platform;
class GDBListener;
class RemoteGDB;
-namespace Kernel { class Binning; }
#endif
class System : public SimObject
@@ -61,12 +64,12 @@ class System : public SimObject
PhysicalMemory *physmem;
PCEventQueue pcEventQueue;
- std::vector<ExecContext *> execContexts;
+ std::vector<ThreadContext *> threadContexts;
int numcpus;
int getNumCPUs()
{
- if (numcpus != execContexts.size())
+ if (numcpus != threadContexts.size())
panic("cpu array not fully populated!");
return numcpus;
@@ -96,8 +99,6 @@ class System : public SimObject
/** Entry point in the kernel to start at */
Addr kernelEntry;
- Kernel::Binning *kernelBinning;
-
#else
int page_ptr;
@@ -157,9 +158,6 @@ class System : public SimObject
Tick boot_cpu_frequency;
std::string boot_osflags;
uint64_t init_param;
- bool bin;
- std::vector<std::string> binned_fns;
- bool bin_int;
std::string kernel_path;
std::string readfile;
@@ -204,10 +202,9 @@ class System : public SimObject
#endif // FULL_SYSTEM
- int registerExecContext(ExecContext *xc, int xcIndex);
- void replaceExecContext(ExecContext *xc, int xcIndex);
+ int registerThreadContext(ThreadContext *tc, int tcIndex);
+ void replaceThreadContext(ThreadContext *tc, int tcIndex);
- void regStats();
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
diff --git a/src/sim/vptr.hh b/src/sim/vptr.hh
index cc57e63f0..bcc22f0ca 100644
--- a/src/sim/vptr.hh
+++ b/src/sim/vptr.hh
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 __ARCH_ALPHA_VPTR_HH__
@@ -32,7 +34,7 @@
#include "arch/vtophys.hh"
#include "arch/isa_traits.hh"
-class ExecContext;
+class ThreadContext;
template <class T>
class VPtr
@@ -41,17 +43,17 @@ class VPtr
typedef T Type;
private:
- ExecContext *xc;
+ ThreadContext *tc;
Addr ptr;
public:
- ExecContext *GetXC() const { return xc; }
+ ThreadContext *GetTC() const { return tc; }
Addr GetPointer() const { return ptr; }
public:
- explicit VPtr(ExecContext *_xc, Addr p = 0) : xc(_xc), ptr(p) { }
+ explicit VPtr(ThreadContext *_tc, Addr p = 0) : tc(_tc), ptr(p) { }
template <class U>
- VPtr(const VPtr<U> &vp) : xc(vp.GetXC()), ptr(vp.GetPointer()) {}
+ VPtr(const VPtr<U> &vp) : tc(vp.GetTC()), ptr(vp.GetPointer()) {}
~VPtr() {}
bool operator!() const
@@ -88,7 +90,7 @@ class VPtr
template <class U>
const VPtr<T> &operator=(const VPtr<U> &vp)
{
- xc = vp.GetXC();
+ tc = vp.GetTC();
ptr = vp.GetPointer();
return *this;
@@ -97,7 +99,7 @@ class VPtr
operator T *()
{
panic("Needs to be rewritten\n");
-/* void *addr = vtomem(xc, ptr, sizeof(T));
+/* void *addr = vtomem(tc, ptr, sizeof(T));
return (T *)addr;
*/
}
@@ -105,7 +107,7 @@ class VPtr
T *operator->()
{
panic("Needs to be rewritten\n");
-/* void *addr = vtomem(xc, ptr, sizeof(T));
+/* void *addr = vtomem(tc, ptr, sizeof(T));
return (T *)addr;
*/
}
@@ -113,7 +115,7 @@ class VPtr
T &operator*()
{
panic("Needs to be rewritten\n");
-/* void *addr = vtomem(xc, ptr, sizeof(T));
+/* void *addr = vtomem(tc, ptr, sizeof(T));
return *(T *)addr;
*/
}
diff --git a/src/unittest/bitvectest.cc b/src/unittest/bitvectest.cc
index 1b8c332f5..440a150a3 100644
--- a/src/unittest/bitvectest.cc
+++ b/src/unittest/bitvectest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream.h>
diff --git a/src/unittest/circletest.cc b/src/unittest/circletest.cc
index bb15f8c64..f072cf044 100644
--- a/src/unittest/circletest.cc
+++ b/src/unittest/circletest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <fcntl.h>
diff --git a/src/unittest/cprintftest.cc b/src/unittest/cprintftest.cc
index 361f84028..9c3eb0cd6 100644
--- a/src/unittest/cprintftest.cc
+++ b/src/unittest/cprintftest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/unittest/genini.py b/src/unittest/genini.py
index 2af81fe2b..a969a6ee4 100755
--- a/src/unittest/genini.py
+++ b/src/unittest/genini.py
@@ -24,6 +24,8 @@
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (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 getopt, os, os.path, sys
from os.path import join as joinpath, realpath
diff --git a/src/unittest/initest.cc b/src/unittest/initest.cc
index 0c5ac2343..8f53fce5c 100644
--- a/src/unittest/initest.cc
+++ b/src/unittest/initest.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
#include <iostream>
diff --git a/src/unittest/lru_test.cc b/src/unittest/lru_test.cc
index 2829163de..d10eb1dd0 100644
--- a/src/unittest/lru_test.cc
+++ b/src/unittest/lru_test.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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>
diff --git a/src/unittest/nmtest.cc b/src/unittest/nmtest.cc
index e9c20d19d..b6b74e08d 100644
--- a/src/unittest/nmtest.cc
+++ b/src/unittest/nmtest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/unittest/offtest.cc b/src/unittest/offtest.cc
index d3f035b73..ebfb2515c 100644
--- a/src/unittest/offtest.cc
+++ b/src/unittest/offtest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <sys/types.h>
diff --git a/src/unittest/paramtest.cc b/src/unittest/paramtest.cc
index cb31c49d5..e513ab981 100644
--- a/src/unittest/paramtest.cc
+++ b/src/unittest/paramtest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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
*/
//
diff --git a/src/unittest/rangetest.cc b/src/unittest/rangetest.cc
index 41d438f48..b7a68ab44 100644
--- a/src/unittest/rangetest.cc
+++ b/src/unittest/rangetest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/unittest/sized_test.cc b/src/unittest/sized_test.cc
index 86cd13e5b..f1bf7528f 100644
--- a/src/unittest/sized_test.cc
+++ b/src/unittest/sized_test.cc
@@ -24,6 +24,9 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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>
diff --git a/src/unittest/stattest.cc b/src/unittest/stattest.cc
index b944eff45..4e504fde9 100644
--- a/src/unittest/stattest.cc
+++ b/src/unittest/stattest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iomanip>
@@ -48,10 +50,10 @@ Tick ticksPerSecond = ULL(2000000000);
Scalar<> s1;
Scalar<> s2;
Average<> s3;
-Scalar<MainBin> s4;
-Vector<MainBin> s5;
-Distribution<MainBin> s6;
-Vector<MainBin> s7;
+Scalar<> s4;
+Vector<> s5;
+Distribution<> s6;
+Vector<> s7;
AverageVector<> s8;
StandardDeviation<> s9;
AverageDeviation<> s10;
@@ -70,9 +72,6 @@ Value f5;
Formula f6;
Formula f7;
-MainBin bin1("bin1");
-MainBin bin2("bin2");
-
ostream *outputStream = &cout;
double
@@ -301,8 +300,6 @@ main(int argc, char *argv[])
check();
reset();
- bin1.activate();
-
s16[1][0] = 1;
s16[0][1] = 3;
s16[0][0] = 2;
@@ -493,7 +490,6 @@ main(int argc, char *argv[])
s6.sample(8);
s6.sample(9);
- bin2.activate();
s6.sample(10);
s6.sample(10);
s6.sample(10);
diff --git a/src/unittest/strnumtest.cc b/src/unittest/strnumtest.cc
index a80dd7c36..ea28e35df 100644
--- a/src/unittest/strnumtest.cc
+++ b/src/unittest/strnumtest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream.h>
diff --git a/src/unittest/symtest.cc b/src/unittest/symtest.cc
index 5fba71736..f0142b923 100644
--- a/src/unittest/symtest.cc
+++ b/src/unittest/symtest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream.h>
diff --git a/src/unittest/tokentest.cc b/src/unittest/tokentest.cc
index 7f27d58fe..128346b5b 100644
--- a/src/unittest/tokentest.cc
+++ b/src/unittest/tokentest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 <iostream>
diff --git a/src/unittest/tracetest.cc b/src/unittest/tracetest.cc
index 866b67d9b..b1343aac3 100644
--- a/src/unittest/tracetest.cc
+++ b/src/unittest/tracetest.cc
@@ -24,6 +24,8 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (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 "sim/host.hh"