Using g-cache, we can simulate more complex cache systems. Let us consider the structure described by figure 5.
|
| Figure 5. A More Complex Cache System |
What we want to simulate is a system with separate instruction and data caches at level 1 backed by a level 2 cache. We will connect this memory hierarchy to an x86 processor. The dotted components in the diagram represent elements that are introduced in Simics to complete the simulation. Let us have a look at these components:
In terms of script, this configuration gives us the following:
#
# Transaction staller for memory
#
@staller = pre_conf_object('staller', 'trans-staller')
@staller.stall_time = 200
#
# l2 cache: 512Kb Write-back
#
@l2c = pre_conf_object('l2c', 'g-cache')
@l2c.cpus = conf.cpu0
@l2c.config_line_number = 4096
@l2c.config_line_size = 128
@l2c.config_assoc = 8
@l2c.config_virtual_index = 0
@l2c.config_virtual_tag = 0
@l2c.config_write_back = 1
@l2c.config_write_allocate = 1
@l2c.config_replacement_policy = 'lru'
@l2c.penalty_read = 10
@l2c.penalty_write = 10
@l2c.penalty_read_next = 0
@l2c.penalty_write_next = 0
@l2c.timing_model = staller
#
# instruction cache: 16Kb
#
@ic = pre_conf_object('ic', 'g-cache')
@ic.cpus = conf.cpu0
@ic.config_line_number = 256
@ic.config_line_size = 64
@ic.config_assoc = 2
@ic.config_virtual_index = 0
@ic.config_virtual_tag = 0
@ic.config_replacement_policy = 'lru'
@ic.penalty_read = 3
@ic.penalty_write = 0
@ic.penalty_read_next = 0
@ic.penalty_write_next = 0
@ic.timing_model = l2c
#
# data cache: 16Kb Write-through
#
@dc = pre_conf_object('dc', 'g-cache')
@dc.cpus = conf.cpu0
@dc.config_line_number = 256
@dc.config_line_size = 64
@dc.config_assoc = 4
@dc.config_virtual_index = 0
@dc.config_virtual_tag = 0
@dc.config_replacement_policy = 'lru'
@dc.penalty_read = 3
@dc.penalty_write = 3
@dc.penalty_read_next = 0
@dc.penalty_write_next = 0
@dc.timing_model = l2c
#
# transaction splitter for instruction cache
#
@ts_i = pre_conf_object('ts_i', 'trans-splitter')
@ts_i.cache = ic
@ts_i.timing_model = ic
@ts_i.next_cache_line_size = 64
#
# transaction splitter for data cache
#
@ts_d = pre_conf_object('ts_d', 'trans-splitter')
@ts_d.cache = dc
@ts_d.timing_model = dc
@ts_d.next_cache_line_size = 64
#
# instruction-data splitter
#
@id = pre_conf_object('id', 'id-splitter')
@id.ibranch = ts_i
@id.dbranch = ts_d
@SIM_add_configuration([staller, l2c, ic, dc, ts_i, ts_d, id], None)
Once this is done, we can simply plug the id-splitter to the main memory:
@conf.phys_mem0.timing_model = conf.id
Note the way the penalties have been set: we don't use _next penalties but let the next level report penalties in case they are accessed. In this configuration, a read hit in L1 would take 3 cycles; a read miss that goes to memory would take 3 + 10 + 200 = 213 cycles if no copy-back is performed in the L2 cache. There's no best way to set up the penalties so it's up to you to decide how your model should behave.