1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
`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
);
// Este módulo provee capacidad para spin_locks (básicamente mutexes) para
// proteger una sección de código a través de spin lock/unlock.
// Esto básicamente es la implemenntación de las instrucciones de ARM
// ldrex, strexeq, que originalmente no son parte ARMv4, esto implica
// que este quad-core es un frankenstein entre ARMv4 y alguna versión
// posterior que sí implementa esas instrucciones.
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
|