-
Notifications
You must be signed in to change notification settings - Fork 185
/
im_cached.v
134 lines (113 loc) · 2.89 KB
/
im_cached.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
/*
* im_cached
*
* Read only 4 block direct mapped cache with one
* word (32-bit) blocks.
* Interfaces to the slow instruction memory (im_slow).
*
* On the next clock edge after an address has been asserted,
* data is valid and can be read if hit is high, otherwise
* hit will be low and additional cycles will be needed to
* retrieve the data from (slow) memory.
*/
`ifndef _im_cached
`define _im_cached
`include "im_slow.v"
module im_cached(
input wire clk,
input wire [31:0] addr,
output wire hit,
output wire [31:0] data);
// parameters to im_slow.v and im.v,
// refer to the documentation of those modules
parameter NMEM = 128;
parameter IM_DATA = "im_data.txt";
parameter MEM_SIZE = 128;
parameter ND = 3;
wire rdy;
wire [31:0] mem_data;
im_slow #(.NMEM(NMEM), .IM_DATA(IM_DATA), .ND(ND))
ims1(.clk(clk), .addr(addr), .rdy(rdy), .data(mem_data));
//
// ADDRESS
// 31 4 3 2 1 0
// +------------+-----------+-----+
// | tag | index | X X |
// +------------+-----------+-----+
//
// X X - byte index
//
// tag: 28 bits
// index: 2 bits (4 blocks)
//
// BLOCK
// 60 59 32 31 0
// +---+---------+--------+
// | V | tag | word |
// +---+---------+--------+
//
// decode address
//wire [1:0] byte_idx;
wire [1:0] index;
wire [27:0] addr_tag;
//
//assign byte_idx = addr[1:0];
assign index = addr[3:2];
assign addr_tag = addr[31:4];
reg [60:0] block; // selected block
reg [60:0] block0;
reg [60:0] block1;
reg [60:0] block2;
reg [60:0] block3;
// initialize valid bit to false
initial begin
block0[60] = 1'b0;
block1[60] = 1'b0;
block2[60] = 1'b0;
block3[60] = 1'b0;
end
// select block in cache to read from
always @(*) begin
case (index)
0: block = block0;
1: block = block1;
2: block = block2;
//3: block = block3;
default: block = block3;
endcase
end
// decode block
wire valid;
wire [27:0] block_tag;
//wire [31:0] block_data;
//
assign valid = block[60];
assign block_tag = block[59:32];
//assign block_data = block[31:0];
//
//assign data = block_data;
assign data = (rdy == 1'b1) ? mem_data : block[31:0];
// Update block from memory,
// or hold current value.
//
// Anytime the address has been asserted long
// enough for the memory to become ready (rdy)
// the cache will be updated.
always @(posedge clk) begin
// default
block0 <= block0;
block1 <= block1;
block2 <= block2;
block3 <= block3;
if (index == 2'd0 && rdy)
block0 <= {1'b1, addr_tag, mem_data}; // { valid, tag, data }
if (index == 2'd1 && rdy)
block1 <= {1'b1, addr_tag, mem_data};
if (index == 2'd2 && rdy)
block2 <= {1'b1, addr_tag, mem_data};
if (index == 2'd3 && rdy)
block3 <= {1'b1, addr_tag, mem_data};
end
assign hit = (rdy || (valid && (addr_tag == block_tag))) ? 1'b1 : 1'b0;
endmodule
`endif