forked from osresearch/risc8
-
Notifications
You must be signed in to change notification settings - Fork 0
/
risc8-regs.v
156 lines (134 loc) · 3.3 KB
/
risc8-regs.v
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
`ifndef _risc8_regfile_v_
`define _risc8_regfile_v_
/*
* The block RAM regfile has a limitation that writes are not available
* until the next clock cycle.
*
* The A register can be a pair of registers, while the B is always one byte.
*/
module risc8_regs(
input clk,
input reset,
// read ports
input [5:0] a,
input [5:0] b,
output [15:0] Ra,
output [7:0] Rb,
// write port
input write,
input write_word,
input [5:0] d,
input [15:0] Rd
);
// duplicate the register file so that we can emulate a
// dual-read port, single-write port block RAM
// 32 8-bit registers == 16 16-bit words
reg [15:0] ram_a[0:15];
reg [15:0] ram_b[0:15];
// there has to be a better way to do this
initial $readmemh("zero.hex", ram_a);
initial $readmemh("zero.hex", ram_b);
wire [4:0] a_word = a[5:1];
wire [4:0] b_word = b[5:1];
wire [4:0] d_word = d[5:1];
reg [1:0] al_src;
reg [1:0] ah_src;
reg [1:0] bl_src;
reg [15:0] Ra_ram;
reg [15:0] Rb_ram;
reg [15:0] Ra;
reg [ 7:0] Rb;
reg [15:0] cache_Rd;
always @(posedge clk) if (!reset) begin
Ra_ram <= ram_a[a_word];
Rb_ram <= ram_b[b_word];
// default source is from the ram read
// with the correct byte selected from the a and b address
al_src <= { 1'b0, a[0] };
ah_src <= { 1'b0, 1'b1 };
bl_src <= { 1'b0, b[0] };
if (write) begin
cache_Rd <= Rd;
if (write_word) begin
// assume aligned write for d
ram_a[d_word][15:0] <= Rd;
ram_b[d_word][15:0] <= Rd;
// check for cache hit
if (a_word == d_word) begin
if (a[0] == 0) begin
// replace both bytes from the cache
al_src <= 2'b10;
ah_src <= 2'b11;
end else
if (a[0] == 1) begin
// replace bottom byte from top byte
al_src <= 2'b11;
end
end
if (b_word == d_word) begin
if (b[0] == 0) begin
// low byte of cache
bl_src <= 2'b10;
end else begin
// high byte of cache
bl_src <= 2'b11;
end
end
end else
if (d[0] == 0) begin
// low byte write
//$display("R[%dL] <= %02x", d_word, Rd[7:0]);
ram_a[d_word][7:0] <= Rd[7:0];
ram_b[d_word][7:0] <= Rd[7:0];
if (a_word == d_word && a[0] == 0) begin
// cache hit on low byte of A
al_src <= 2'b10;
end
if (b == d) begin
// cache hit on low byte of B
bl_src <= 2'b10;
end
end else begin
// high byte write
//$display("R[%dH] <= %02x", d_word, Rd[7:0]);
ram_a[d_word][15:8] <= Rd[7:0];
ram_b[d_word][15:8] <= Rd[7:0];
if (a_word == d_word) begin
if (a[0] == 0) begin
// cache hit on high byte of A
ah_src <= 2'b10;
end else begin
// cache hit on low byte of A
al_src <= 2'b10;
end
end
if (b == d) begin
// cache hit on low byte of D
bl_src <= 2'b10;
end
end
end
end
// satisfy reads from the cache
always @(*) begin
case(al_src)
2'b00: Ra[7:0] = Ra_ram[7:0];
2'b01: Ra[7:0] = Ra_ram[15:8];
2'b10: Ra[7:0] = cache_Rd[7:0];
2'b11: Ra[7:0] = cache_Rd[15:8];
endcase
case(ah_src)
2'b00: Ra[15:8] = Ra_ram[7:0];
2'b01: Ra[15:8] = Ra_ram[15:8];
2'b10: Ra[15:8] = cache_Rd[7:0];
2'b11: Ra[15:8] = cache_Rd[15:8];
endcase
case(bl_src)
2'b00: Rb[7:0] = Rb_ram[7:0];
2'b01: Rb[7:0] = Rb_ram[15:8];
2'b10: Rb[7:0] = cache_Rd[7:0];
2'b11: Rb[7:0] = cache_Rd[15:8];
endcase
end
endmodule
`endif