summaryrefslogtreecommitdiff
path: root/rtl/cache/routing.sv
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rtl/cache/routing.sv40
1 files changed, 40 insertions, 0 deletions
diff --git a/rtl/cache/routing.sv b/rtl/cache/routing.sv
index c72d9b5..78f1be0 100644
--- a/rtl/cache/routing.sv
+++ b/rtl/cache/routing.sv
@@ -37,6 +37,12 @@ module cache_routing
output line_be mem_byteenable
);
+ /* Módulo para enrutar las operaciones a cache o memoria
+ * Esto porque hay escrituras que definitivamente no pueden quedar en cache
+ * como el caso de periféricos, para los cuales si se guarda "su valor" en
+ * cache y no en memoria se harían lecturas incorrectas
+ */
+
word core_address_line;
logic cached, cache_mem, transition;
addr_io_region io;
@@ -48,29 +54,56 @@ module cache_routing
BYPASS
} state;
+ //Arbitrar el bus del lado de la cache
+
+ /* Se sabe si el address es cache o no evaluando los bits de IO.
+ * Esto es posible porque se cumple lo siguiente:
+ * - La memoria tiene un tamaño que es una potencia de 2
+ * - Sus direcciones inician en 0
+ * Entonces si los bits de IO son distintos de 0, se sabe que no es
+ * una dirección cached
+ */
assign cached = io == 3'b000;
+ // Se afirma si cache quiere hacer un read o write de memoria
assign cache_mem = cache_mem_read || cache_mem_write;
+ // Acá se divide el core_address para analizarse por separado
assign {io, core_tag, core_index, core_offset} = core_address;
assign core_address_line = {io, core_tag, core_index, 4'b0000};
+ // Si está cached se asigna a lectura de cache, sino a lectura de memoria
assign core_readdata_line = cached ? data_rd : mem_readdata;
+ // Se afirma si el core quiere leer/escribir a cache y efectivamente es una
+ // dirección de cache
assign cache_core_read = core_read && cached;
assign cache_core_write = core_write && cached;
+ // Máquina de estados:
+ // IDLE/CACHE/BYPASS
+ // Bypass: el request evita pasar por caché, para que no quede escrito el
+ // el dato. Esto sirve para periféricos, por ejemplo.
+ // Cache: el request sí pasa por caché, esto sucede para todo lo que va
+ // para RAM.
always_comb begin
transition = 0;
core_waitrequest = cache_core_waitrequest;
+ // Desde el punto de vista de cache, mem le hace waitreq a cache
cache_mem_waitrequest = 1;
unique case (state)
IDLE:
+ /* Transition se afirma si cache quiere hacer un read o write de
+ * memoria, o si el address no es cache y el core quiere leer
+ * o escribir a cache
+ */
transition = cache_mem || (!cached && (core_read || core_write));
CACHE:
+ // Cache le hace waitreq a memoria
cache_mem_waitrequest = mem_waitrequest;
BYPASS:
+ // Se le hace waitreq al core si la memoria también lo hace
core_waitrequest = mem_waitrequest;
endcase
end
@@ -83,6 +116,11 @@ module cache_routing
end else unique case (state)
IDLE:
if (transition) begin
+ // Si cache quiere hacer una operación con memoria, se pasa
+ // a CACHE, sino hay que hacer BYPASS. Si la operación
+ // no es directo a memoria, se hace bypasss porque esto
+ // implica que el dato no tiene que quedar cacheado. (Talvez
+ // es algo de un periférico, etc.)
state <= cache_mem ? CACHE : BYPASS;
mem_read <= cache_mem ? cache_mem_read : core_read;
mem_write <= cache_mem ? cache_mem_write : core_write;
@@ -98,6 +136,8 @@ module cache_routing
always_ff @(posedge clk)
if (transition) begin
+ // Si cache no quiere hacer una operación con memoria, se asignan
+ // las señales del core
mem_address <= cache_mem ? cache_mem_address : core_address_line;
mem_writedata <= cache_mem ? cache_mem_writedata : core_writedata_line;
mem_byteenable <= cache_mem ? 16'hffff : core_byteenable_line;