summaryrefslogtreecommitdiff
path: root/rtl/cache/monitor.sv
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/cache/monitor.sv')
-rw-r--r--rtl/cache/monitor.sv103
1 files changed, 103 insertions, 0 deletions
diff --git a/rtl/cache/monitor.sv b/rtl/cache/monitor.sv
new file mode 100644
index 0000000..b7f0d15
--- /dev/null
+++ b/rtl/cache/monitor.sv
@@ -0,0 +1,103 @@
+`include "cache/defs.sv"
+
+module cache_monitor
+(
+ input logic clk,
+ rst_n,
+
+ input addr_tag core_tag,
+ input addr_index core_index,
+ input addr_offset core_offset,
+ input logic core_lock,
+ input word core_writedata,
+ output logic[1:0] core_response,
+
+ input line data_rd,
+
+ input logic monitor_acquire,
+ monitor_fail,
+ monitor_release,
+ output line monitor_update,
+ output logic monitor_commit
+);
+
+ line monitor_rd, monitor_wr;
+ word update_3, update_2, update_1, update_0;
+ logic dirty, done, hit, known;
+ addr_tag tag;
+ addr_index index;
+
+ logic[3:0] mask, mask_clear, core_ex_mask;
+
+ assign monitor_commit = !core_lock || (hit && known && done);
+ assign monitor_update = {update_3, update_2, update_1, update_0};
+
+ /* Avalon p. 15:
+ * - 00: OKAY - Successful response for a transaction.
+ * - 10: SLVERR - Error from an endpoint agent. Indicates an unsuccessful transaction.
+ */
+ assign core_response = {monitor_fail, 1'b0};
+
+ assign hit = tag == core_tag && index == core_index;
+ assign done = monitor_rd == data_rd && mask_clear == 4'b0000;
+ assign known = mask[core_offset];
+ assign mask_clear = mask & ~core_ex_mask;
+
+ always_comb begin
+ {update_3, update_2, update_1, update_0} = monitor_wr;
+
+ unique case (core_offset)
+ 2'b00: begin
+ update_0 = core_writedata;
+ core_ex_mask = 4'b0001;
+ end
+
+ 2'b01: begin
+ update_1 = core_writedata;
+ core_ex_mask = 4'b0010;
+ end
+
+ 2'b10: begin
+ update_2 = core_writedata;
+ core_ex_mask = 4'b0100;
+ end
+
+ 2'b11: begin
+ update_3 = core_writedata;
+ core_ex_mask = 4'b1000;
+ end
+ endcase
+ end
+
+ always @(posedge clk or negedge rst_n)
+ if (!rst_n) begin
+ mask <= 4'b0000;
+ dirty <= 0;
+ end else begin
+ if (monitor_acquire) begin
+ mask <= hit && !known && !dirty ? mask | core_ex_mask : core_ex_mask;
+ dirty <= 0;
+ end
+
+ if (monitor_release) begin
+ mask <= hit && known ? mask_clear : 4'b0000;
+ dirty <= hit && known;
+ end
+ end
+
+ always_ff @(posedge clk) begin
+ if (monitor_acquire) begin
+ tag <= core_tag;
+ index <= core_index;
+
+ if (!hit || known || dirty || mask == 4'b0000) begin
+ monitor_rd <= data_rd;
+ monitor_wr <= data_rd;
+ end
+ end
+
+ if (monitor_release)
+ monitor_wr <= monitor_update;
+ end
+
+endmodule