Single Core Cache Controller
This module is the L1 cache controller (CC) allocated in the nu+ core. There is a component that it filters all request to/from LDST: core interface (CI). Regards to this component, it can be possible to decouple a service speed of cache controller and a service speed of LDST units. In fact, the cache controller can manage one request at a time but there are more than one LDST units so they can send more than one request at a time. Core interface receives a request from the LDST unit (all the event concerned to the memory: miss, flush, evict) and store it in one of four queues. Once elaboration of cache controller terminated, it sends a dequeue signal to core interface for delete request in queues.
TODO: magari un disegno di tutti i componenti collegati al CC
In a single core architecture, there is no need for Miss Status Holding Register (MSHR).
Contents
Interface
This section shows the interface of the cache controller to/from all other linked units.
To/from Core interface
Following lines of code define interface to/from core interface:
output logic cc_dequeue_store_request, ~ input logic ci_store_request_valid, input thread_id_t ci_store_request_thread_id, input dcache_address_t ci_store_request_address, input logic ci_store_request_coherent, ~ input logic ci_flush_request_valid, input dcache_address_t ci_flush_request_address, input dcache_line_t ci_flush_request_cache_line, input dcache_store_mask_t ci_flush_request_dirty_mask, input logic ci_flush_request_coherent, ~
In these lines of code there is dequeue signal, depending on kind of request, for load and store operation there are valid, thread ID, address and coherent signals, for flush, replacement and dinv (TODO: chiedere cos'è dinv). All these signals are described link alla pagina del core interface here. TODO: creare la pagina core interface?
To/from LDST
TODO
To/from IO Map
TODO
To/from Memory controller
TODO
To/from Instruction cache
TODO
To/from Thread controller
TODO
Implementation
In this section is described how to is implemented CC.
FSM
The behaviour is implemented by a finite state machine (FSM). There are three states:
- idle
- send request
- wait response
Below is represented the graph of FSM of CC.
The FSM is implemented dividing sequential and combinatorial output.
Sequential part
In the IDLE state, there is a preparation of request. Preparation depends on the type of request. Below there is an example of LOAD request:
if (grants[LOAD]) begin granted_read <= 1'b1; granted_write <= 1'b0; granted_need_snoop <= 1'b1; granted_need_hit_miss <= 1'b0; granted_wakeup <= 1'b1; granted_thread_id <= ci_load_request_thread_id; granted_address <= ci_load_request_address;
There is some information such as thread ID that it sent a request or address of LOAD request. If there is at least one request, then CC move into SEND REQ state.
In the SEND REQ state, there is a logic that allows CC to send a request to the memory. If the request is executable and the memory is available, then CC can send the request by writing the address and kind (READ or WRITE) of request. If kind of request is READ, then CC need to waits for a response, else if kind of request is WRITE, CC computes a DINV request and it comes back in the IDLE state. Else if the request isn't executable, then CC comes back in the IDLE state.
In the WAIT RESP state, CC waits for a response from the memory. If memory response is available, then CC comes back in the IDLE state. If kind of request is INSTR, then CC return to Thread Controller (TC) the contents of memory. Else if kind of request is READ or WRITE, then CC performs a request by below lines of code:
end else if (grants_reg[LOAD] | grants_reg[STORE]) begin cc_update_ldst_valid <= 1'b1; cc_update_ldst_way <= counter_way[granted_address.index]; cc_update_ldst_address <= granted_address; cc_update_ldst_privileges <= dcache_privileges_t'(2'b11); cc_update_ldst_store_value <= m2n_response_data_swap; cc_update_ldst_command <= ways_full ? CC_REPLACEMENT : CC_UPDATE_INFO_DATA;
CC returns to LDST way where a request has to execute, READ and WRITE privileges, data that has to write if kind of request is STORE.
IO, Instruction and Core Interface requests buffering
Every request is stored in a vector (TODO: chiedere se il segnale valid è un id della richiesta; TODO: chiedere meglio questa parte). Regards to this vector, it can be possible to schedule a request. There is a component (described [here]) that allow rounding robin schedule.
TODO: gestione istruzioni "speciali"
Snoop managing
snoop + way TODO: chiedere meglio questa parte
Memory swap
This portion of code is used to transform a vector of data from xxx-endian into xxx-endian (TODO: chiedere a francesco cosa siamo noi e in cosa trasforma). For each vector of date there is a flag ENDSWAP: if it is asserted then is need to transform the format of data.