Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Yuchen Wu
ustc_ca2021_lab
Commits
007cb530
Commit
007cb530
authored
May 09, 2021
by
YouGuoliang
Browse files
Add Lab03
parent
6519d3e6
Changes
70
Hide whitespace changes
Inline
Side-by-side
lab3/CacheSrcCode/README.md
0 → 100644
View file @
007cb530
# cache 实验所需的文件
*
main_mem.sv 和 mem.sv 是我们提供的主存代码,cache代码会调用它们
*
cache.sv 是我们提供的直接相连cache的代码。
*
generate_cache_tb.py 是我们提供的,用于生成 cache 测试testbench的python代码
*
cache_tb.sv 是一个由 generate_cache_tb.py 生成的testbench
lab3/CacheSrcCode/cache.sv
0 → 100644
View file @
007cb530
module
cache
#(
parameter
LINE_ADDR_LEN
=
3
,
// line内地址长度,决定了每个line具有2^3个word
parameter
SET_ADDR_LEN
=
3
,
// 组地址长度,决定了一共有2^3=8组
parameter
TAG_ADDR_LEN
=
6
,
// tag长度
parameter
WAY_CNT
=
3
// 组相连度,决定了每组中有多少路line,这里是直接映射型cache,因此该参数没用到
)(
input
clk
,
rst
,
output
miss
,
// 对CPU发出的miss信号
input
[
31
:
0
]
addr
,
// 读写请求地址
input
rd_req
,
// 读请求信号
output
reg
[
31
:
0
]
rd_data
,
// 读出的数据,一次读一个word
input
wr_req
,
// 写请求信号
input
[
31
:
0
]
wr_data
// 要写入的数据,一次写一个word
);
localparam
MEM_ADDR_LEN
=
TAG_ADDR_LEN
+
SET_ADDR_LEN
;
// 计算主存地址长度 MEM_ADDR_LEN,主存大小=2^MEM_ADDR_LEN个line
localparam
UNUSED_ADDR_LEN
=
32
-
TAG_ADDR_LEN
-
SET_ADDR_LEN
-
LINE_ADDR_LEN
-
2
;
// 计算未使用的地址的长度
localparam
LINE_SIZE
=
1
<<
LINE_ADDR_LEN
;
// 计算 line 中 word 的数量,即 2^LINE_ADDR_LEN 个word 每 line
localparam
SET_SIZE
=
1
<<
SET_ADDR_LEN
;
// 计算一共有多少组,即 2^SET_ADDR_LEN 个组
reg
[
31
:
0
]
cache_mem
[
SET_SIZE
][
LINE_SIZE
];
// SET_SIZE个line,每个line有LINE_SIZE个word
reg
[
TAG_ADDR_LEN
-
1
:
0
]
cache_tags
[
SET_SIZE
];
// SET_SIZE个TAG
reg
valid
[
SET_SIZE
];
// SET_SIZE个valid(有效位)
reg
dirty
[
SET_SIZE
];
// SET_SIZE个dirty(脏位)
wire
[
2
-
1
:
0
]
word_addr
;
// 将输入地址addr拆分成这5个部分
wire
[
LINE_ADDR_LEN
-
1
:
0
]
line_addr
;
wire
[
SET_ADDR_LEN
-
1
:
0
]
set_addr
;
wire
[
TAG_ADDR_LEN
-
1
:
0
]
tag_addr
;
wire
[
UNUSED_ADDR_LEN
-
1
:
0
]
unused_addr
;
enum
{
IDLE
,
SWAP_OUT
,
SWAP_IN
,
SWAP_IN_OK
}
cache_stat
;
// cache 状态机的状态定义
// IDLE代表就绪,SWAP_OUT代表正在换出,SWAP_IN代表正在换入,SWAP_IN_OK代表换入后进行一周期的写入cache操作。
reg
[
SET_ADDR_LEN
-
1
:
0
]
mem_rd_set_addr
=
0
;
reg
[
TAG_ADDR_LEN
-
1
:
0
]
mem_rd_tag_addr
=
0
;
wire
[
MEM_ADDR_LEN
-
1
:
0
]
mem_rd_addr
=
{
mem_rd_tag_addr
,
mem_rd_set_addr
}
;
reg
[
MEM_ADDR_LEN
-
1
:
0
]
mem_wr_addr
=
0
;
reg
[
31
:
0
]
mem_wr_line
[
LINE_SIZE
];
wire
[
31
:
0
]
mem_rd_line
[
LINE_SIZE
];
wire
mem_gnt
;
// 主存响应读写的握手信号
assign
{
unused_addr
,
tag_addr
,
set_addr
,
line_addr
,
word_addr
}
=
addr
;
// 拆分 32bit ADDR
reg
cache_hit
=
1'b0
;
always
@
(
*
)
begin
// 判断 输入的address 是否在 cache 中命中
if
(
valid
[
set_addr
]
&&
cache_tags
[
set_addr
]
==
tag_addr
)
// 如果 cache line有效,并且tag与输入地址中的tag相等,则命中
cache_hit
=
1'b1
;
else
cache_hit
=
1'b0
;
end
always
@
(
posedge
clk
or
posedge
rst
)
begin
// ?? cache ???
if
(
rst
)
begin
cache_stat
<=
IDLE
;
for
(
integer
i
=
0
;
i
<
SET_SIZE
;
i
++
)
begin
dirty
[
i
]
=
1'b0
;
valid
[
i
]
=
1'b0
;
end
for
(
integer
k
=
0
;
k
<
LINE_SIZE
;
k
++
)
mem_wr_line
[
k
]
<=
0
;
mem_wr_addr
<=
0
;
{
mem_rd_tag_addr
,
mem_rd_set_addr
}
<=
0
;
rd_data
<=
0
;
end
else
begin
case
(
cache_stat
)
IDLE:
begin
if
(
cache_hit
)
begin
if
(
rd_req
)
begin
// 如果cache命中,并且是读请求,
rd_data
<=
cache_mem
[
set_addr
][
line_addr
];
//则直接从cache中取出要读的数据
end
else
if
(
wr_req
)
begin
// 如果cache命中,并且是写请求,
cache_mem
[
set_addr
][
line_addr
]
<=
wr_data
;
// 则直接向cache中写入数据
dirty
[
set_addr
]
<=
1'b1
;
// 写数据的同时置脏位
end
end
else
begin
if
(
wr_req
|
rd_req
)
begin
// 如果 cache 未命中,并且有读写请求,则需要进行换入
if
(
valid
[
set_addr
]
&
dirty
[
set_addr
])
begin
// 如果 要换入的cache line 本来有效,且脏,则需要先将它换出
cache_stat
<=
SWAP_OUT
;
mem_wr_addr
<=
{
cache_tags
[
set_addr
],
set_addr
}
;
mem_wr_line
<=
cache_mem
[
set_addr
];
end
else
begin
// 反之,不需要换出,直接换入
cache_stat
<=
SWAP_IN
;
end
{
mem_rd_tag_addr
,
mem_rd_set_addr
}
<=
{
tag_addr
,
set_addr
}
;
end
end
end
SWAP_OUT:
begin
if
(
mem_gnt
)
begin
// 如果主存握手信号有效,说明换出成功,跳到下一状态
cache_stat
<=
SWAP_IN
;
end
end
SWAP_IN:
begin
if
(
mem_gnt
)
begin
// 如果主存握手信号有效,说明换入成功,跳到下一状态
cache_stat
<=
SWAP_IN_OK
;
end
end
SWAP_IN_OK:
begin
// 上一个周期换入成功,这周期将主存读出的line写入cache,并更新tag,置高valid,置低dirty
for
(
integer
i
=
0
;
i
<
LINE_SIZE
;
i
++
)
cache_mem
[
mem_rd_set_addr
][
i
]
<=
mem_rd_line
[
i
];
cache_tags
[
mem_rd_set_addr
]
<=
mem_rd_tag_addr
;
valid
[
mem_rd_set_addr
]
<=
1'b1
;
dirty
[
mem_rd_set_addr
]
<=
1'b0
;
cache_stat
<=
IDLE
;
// 回到就绪状态
end
endcase
end
end
wire
mem_rd_req
=
(
cache_stat
==
SWAP_IN
);
wire
mem_wr_req
=
(
cache_stat
==
SWAP_OUT
);
wire
[
MEM_ADDR_LEN
-
1
:
0
]
mem_addr
=
mem_rd_req
?
mem_rd_addr
:
(
mem_wr_req
?
mem_wr_addr
:
0
);
assign
miss
=
(
rd_req
|
wr_req
)
&
~
(
cache_hit
&&
cache_stat
==
IDLE
)
;
// 当 有读写请求时,如果cache不处于就绪(IDLE)状态,或者未命中,则miss=1
main_mem
#(
// 主存,每次读写以line 为单位
.
LINE_ADDR_LEN
(
LINE_ADDR_LEN
),
.
ADDR_LEN
(
MEM_ADDR_LEN
)
)
main_mem_instance
(
.
clk
(
clk
),
.
rst
(
rst
),
.
gnt
(
mem_gnt
),
.
addr
(
mem_addr
),
.
rd_req
(
mem_rd_req
),
.
rd_line
(
mem_rd_line
),
.
wr_req
(
mem_wr_req
),
.
wr_line
(
mem_wr_line
)
);
endmodule
lab3/CacheSrcCode/cache_tb.sv
0 → 100644
View file @
007cb530
`timescale
1
ns
/
100
ps
//correct read result:
// 0000000c 00000011 0000000c 00000005 0000000b 00000000 00000008 00000005
module
cache_tb
();
`define
DATA_COUNT
(
8
)
`define
RDWR_COUNT
(
6
*`
DATA_COUNT
)
reg
wr_cycle
[
`RDWR_COUNT
];
reg
rd_cycle
[
`RDWR_COUNT
];
reg
[
31
:
0
]
addr_rom
[
`RDWR_COUNT
];
reg
[
31
:
0
]
wr_data_rom
[
`RDWR_COUNT
];
reg
[
31
:
0
]
validation_data
[
`DATA_COUNT
];
initial
begin
// 8 sequence write cycles
rd_cycle
[
0
]
=
1'b0
;
wr_cycle
[
0
]
=
1'b1
;
addr_rom
[
0
]
=
'h00000000
;
wr_data_rom
[
0
]
=
'h0000001b
;
rd_cycle
[
1
]
=
1'b0
;
wr_cycle
[
1
]
=
1'b1
;
addr_rom
[
1
]
=
'h00000004
;
wr_data_rom
[
1
]
=
'h0000001c
;
rd_cycle
[
2
]
=
1'b0
;
wr_cycle
[
2
]
=
1'b1
;
addr_rom
[
2
]
=
'h00000008
;
wr_data_rom
[
2
]
=
'h00000014
;
rd_cycle
[
3
]
=
1'b0
;
wr_cycle
[
3
]
=
1'b1
;
addr_rom
[
3
]
=
'h0000000c
;
wr_data_rom
[
3
]
=
'h00000005
;
rd_cycle
[
4
]
=
1'b0
;
wr_cycle
[
4
]
=
1'b1
;
addr_rom
[
4
]
=
'h00000010
;
wr_data_rom
[
4
]
=
'h00000016
;
rd_cycle
[
5
]
=
1'b0
;
wr_cycle
[
5
]
=
1'b1
;
addr_rom
[
5
]
=
'h00000014
;
wr_data_rom
[
5
]
=
'h00000002
;
rd_cycle
[
6
]
=
1'b0
;
wr_cycle
[
6
]
=
1'b1
;
addr_rom
[
6
]
=
'h00000018
;
wr_data_rom
[
6
]
=
'h00000008
;
rd_cycle
[
7
]
=
1'b0
;
wr_cycle
[
7
]
=
1'b1
;
addr_rom
[
7
]
=
'h0000001c
;
wr_data_rom
[
7
]
=
'h00000003
;
// 24 random read and write cycles
rd_cycle
[
8
]
=
1'b0
;
wr_cycle
[
8
]
=
1'b1
;
addr_rom
[
8
]
=
'h00000008
;
wr_data_rom
[
8
]
=
'h0000000f
;
rd_cycle
[
9
]
=
1'b0
;
wr_cycle
[
9
]
=
1'b1
;
addr_rom
[
9
]
=
'h00000008
;
wr_data_rom
[
9
]
=
'h0000000c
;
rd_cycle
[
10
]
=
1'b0
;
wr_cycle
[
10
]
=
1'b1
;
addr_rom
[
10
]
=
'h0000001c
;
wr_data_rom
[
10
]
=
'h00000013
;
rd_cycle
[
11
]
=
1'b1
;
wr_cycle
[
11
]
=
1'b0
;
addr_rom
[
11
]
=
'h0000001c
;
wr_data_rom
[
11
]
=
'h00000000
;
rd_cycle
[
12
]
=
1'b1
;
wr_cycle
[
12
]
=
1'b0
;
addr_rom
[
12
]
=
'h0000001c
;
wr_data_rom
[
12
]
=
'h00000000
;
rd_cycle
[
13
]
=
1'b1
;
wr_cycle
[
13
]
=
1'b0
;
addr_rom
[
13
]
=
'h00000008
;
wr_data_rom
[
13
]
=
'h00000000
;
rd_cycle
[
14
]
=
1'b1
;
wr_cycle
[
14
]
=
1'b0
;
addr_rom
[
14
]
=
'h00000008
;
wr_data_rom
[
14
]
=
'h00000000
;
rd_cycle
[
15
]
=
1'b1
;
wr_cycle
[
15
]
=
1'b0
;
addr_rom
[
15
]
=
'h00000000
;
wr_data_rom
[
15
]
=
'h00000000
;
rd_cycle
[
16
]
=
1'b0
;
wr_cycle
[
16
]
=
1'b1
;
addr_rom
[
16
]
=
'h00000018
;
wr_data_rom
[
16
]
=
'h00000008
;
rd_cycle
[
17
]
=
1'b1
;
wr_cycle
[
17
]
=
1'b0
;
addr_rom
[
17
]
=
'h00000010
;
wr_data_rom
[
17
]
=
'h00000000
;
rd_cycle
[
18
]
=
1'b0
;
wr_cycle
[
18
]
=
1'b1
;
addr_rom
[
18
]
=
'h00000000
;
wr_data_rom
[
18
]
=
'h0000001e
;
rd_cycle
[
19
]
=
1'b1
;
wr_cycle
[
19
]
=
1'b0
;
addr_rom
[
19
]
=
'h00000014
;
wr_data_rom
[
19
]
=
'h00000000
;
rd_cycle
[
20
]
=
1'b1
;
wr_cycle
[
20
]
=
1'b0
;
addr_rom
[
20
]
=
'h00000000
;
wr_data_rom
[
20
]
=
'h00000000
;
rd_cycle
[
21
]
=
1'b1
;
wr_cycle
[
21
]
=
1'b0
;
addr_rom
[
21
]
=
'h00000000
;
wr_data_rom
[
21
]
=
'h00000000
;
rd_cycle
[
22
]
=
1'b0
;
wr_cycle
[
22
]
=
1'b1
;
addr_rom
[
22
]
=
'h0000001c
;
wr_data_rom
[
22
]
=
'h00000005
;
rd_cycle
[
23
]
=
1'b1
;
wr_cycle
[
23
]
=
1'b0
;
addr_rom
[
23
]
=
'h00000008
;
wr_data_rom
[
23
]
=
'h00000000
;
rd_cycle
[
24
]
=
1'b0
;
wr_cycle
[
24
]
=
1'b1
;
addr_rom
[
24
]
=
'h00000014
;
wr_data_rom
[
24
]
=
'h00000000
;
rd_cycle
[
25
]
=
1'b1
;
wr_cycle
[
25
]
=
1'b0
;
addr_rom
[
25
]
=
'h00000008
;
wr_data_rom
[
25
]
=
'h00000000
;
rd_cycle
[
26
]
=
1'b0
;
wr_cycle
[
26
]
=
1'b1
;
addr_rom
[
26
]
=
'h00000000
;
wr_data_rom
[
26
]
=
'h0000000c
;
rd_cycle
[
27
]
=
1'b1
;
wr_cycle
[
27
]
=
1'b0
;
addr_rom
[
27
]
=
'h00000010
;
wr_data_rom
[
27
]
=
'h00000000
;
rd_cycle
[
28
]
=
1'b0
;
wr_cycle
[
28
]
=
1'b1
;
addr_rom
[
28
]
=
'h00000010
;
wr_data_rom
[
28
]
=
'h0000000b
;
rd_cycle
[
29
]
=
1'b1
;
wr_cycle
[
29
]
=
1'b0
;
addr_rom
[
29
]
=
'h0000000c
;
wr_data_rom
[
29
]
=
'h00000000
;
rd_cycle
[
30
]
=
1'b0
;
wr_cycle
[
30
]
=
1'b1
;
addr_rom
[
30
]
=
'h00000004
;
wr_data_rom
[
30
]
=
'h00000011
;
rd_cycle
[
31
]
=
1'b1
;
wr_cycle
[
31
]
=
1'b0
;
addr_rom
[
31
]
=
'h0000001c
;
wr_data_rom
[
31
]
=
'h00000000
;
// 8 silence cycles
rd_cycle
[
32
]
=
1'b0
;
wr_cycle
[
32
]
=
1'b0
;
addr_rom
[
32
]
=
'h00000000
;
wr_data_rom
[
32
]
=
'h00000000
;
rd_cycle
[
33
]
=
1'b0
;
wr_cycle
[
33
]
=
1'b0
;
addr_rom
[
33
]
=
'h00000000
;
wr_data_rom
[
33
]
=
'h00000000
;
rd_cycle
[
34
]
=
1'b0
;
wr_cycle
[
34
]
=
1'b0
;
addr_rom
[
34
]
=
'h00000000
;
wr_data_rom
[
34
]
=
'h00000000
;
rd_cycle
[
35
]
=
1'b0
;
wr_cycle
[
35
]
=
1'b0
;
addr_rom
[
35
]
=
'h00000000
;
wr_data_rom
[
35
]
=
'h00000000
;
rd_cycle
[
36
]
=
1'b0
;
wr_cycle
[
36
]
=
1'b0
;
addr_rom
[
36
]
=
'h00000000
;
wr_data_rom
[
36
]
=
'h00000000
;
rd_cycle
[
37
]
=
1'b0
;
wr_cycle
[
37
]
=
1'b0
;
addr_rom
[
37
]
=
'h00000000
;
wr_data_rom
[
37
]
=
'h00000000
;
rd_cycle
[
38
]
=
1'b0
;
wr_cycle
[
38
]
=
1'b0
;
addr_rom
[
38
]
=
'h00000000
;
wr_data_rom
[
38
]
=
'h00000000
;
rd_cycle
[
39
]
=
1'b0
;
wr_cycle
[
39
]
=
1'b0
;
addr_rom
[
39
]
=
'h00000000
;
wr_data_rom
[
39
]
=
'h00000000
;
// 8 sequence read cycles
rd_cycle
[
40
]
=
1'b1
;
wr_cycle
[
40
]
=
1'b0
;
addr_rom
[
40
]
=
'h00000000
;
wr_data_rom
[
40
]
=
'h00000000
;
rd_cycle
[
41
]
=
1'b1
;
wr_cycle
[
41
]
=
1'b0
;
addr_rom
[
41
]
=
'h00000004
;
wr_data_rom
[
41
]
=
'h00000000
;
rd_cycle
[
42
]
=
1'b1
;
wr_cycle
[
42
]
=
1'b0
;
addr_rom
[
42
]
=
'h00000008
;
wr_data_rom
[
42
]
=
'h00000000
;
rd_cycle
[
43
]
=
1'b1
;
wr_cycle
[
43
]
=
1'b0
;
addr_rom
[
43
]
=
'h0000000c
;
wr_data_rom
[
43
]
=
'h00000000
;
rd_cycle
[
44
]
=
1'b1
;
wr_cycle
[
44
]
=
1'b0
;
addr_rom
[
44
]
=
'h00000010
;
wr_data_rom
[
44
]
=
'h00000000
;
rd_cycle
[
45
]
=
1'b1
;
wr_cycle
[
45
]
=
1'b0
;
addr_rom
[
45
]
=
'h00000014
;
wr_data_rom
[
45
]
=
'h00000000
;
rd_cycle
[
46
]
=
1'b1
;
wr_cycle
[
46
]
=
1'b0
;
addr_rom
[
46
]
=
'h00000018
;
wr_data_rom
[
46
]
=
'h00000000
;
rd_cycle
[
47
]
=
1'b1
;
wr_cycle
[
47
]
=
1'b0
;
addr_rom
[
47
]
=
'h0000001c
;
wr_data_rom
[
47
]
=
'h00000000
;
end
initial
begin
validation_data
[
0
]
=
'h0000000c
;
validation_data
[
1
]
=
'h00000011
;
validation_data
[
2
]
=
'h0000000c
;
validation_data
[
3
]
=
'h00000005
;
validation_data
[
4
]
=
'h0000000b
;
validation_data
[
5
]
=
'h00000000
;
validation_data
[
6
]
=
'h00000008
;
validation_data
[
7
]
=
'h00000005
;
end
reg
clk
=
1'b1
,
rst
=
1'b1
;
initial
#
4
rst
=
1'b0
;
always
#
1
clk
=
~
clk
;
wire
miss
;
wire
[
31
:
0
]
rd_data
;
reg
[
31
:
0
]
index
=
0
,
wr_data
=
0
,
addr
=
0
;
reg
rd_req
=
1'b0
,
wr_req
=
1'b0
;
reg
rd_req_ff
=
1'b0
,
miss_ff
=
1'b0
;
reg
[
31
:
0
]
validation_count
=
0
;
always
@
(
posedge
clk
or
posedge
rst
)
if
(
rst
)
begin
rd_req_ff
<=
1'b0
;
miss_ff
<=
1'b0
;
end
else
begin
rd_req_ff
<=
rd_req
;
miss_ff
<=
miss
;
end
always
@
(
posedge
clk
or
posedge
rst
)
if
(
rst
)
begin
validation_count
<=
0
;
end
else
begin
if
(
validation_count
>=
`DATA_COUNT
)
begin
validation_count
<=
'hffffffff
;
end
else
if
(
rd_req_ff
&&
(
index
>
(
4
*
`DATA_COUNT
)))
begin
if
(
~
miss_ff
)
begin
if
(
validation_data
[
validation_count
]
==
rd_data
)
validation_count
<=
validation_count
+
1
;
else
validation_count
<=
0
;
end
end
else
begin
validation_count
<=
0
;
end
end
always
@
(
posedge
clk
or
posedge
rst
)
if
(
rst
)
begin
index
<=
0
;
wr_data
<=
0
;
addr
<=
0
;
rd_req
<=
1'b0
;
wr_req
<=
1'b0
;
end
else
begin
if
(
~
miss
)
begin
if
(
index
<
`RDWR_COUNT
)
begin
if
(
wr_cycle
[
index
])
begin
rd_req
<=
1'b0
;
wr_req
<=
1'b1
;
end
else
if
(
rd_cycle
[
index
])
begin
wr_data
<=
0
;
rd_req
<=
1'b1
;
wr_req
<=
1'b0
;
end
else
begin
wr_data
<=
0
;
rd_req
<=
1'b0
;
wr_req
<=
1'b0
;
end
wr_data
<=
wr_data_rom
[
index
];
addr
<=
addr_rom
[
index
];
index
<=
index
+
1
;
end
else
begin
wr_data
<=
0
;
addr
<=
0
;
rd_req
<=
1'b0
;
wr_req
<=
1'b0
;
end
end
end
cache
#(
.
LINE_ADDR_LEN
(
3
),
.
SET_ADDR_LEN
(
2
),
.
TAG_ADDR_LEN
(
12
),
.
WAY_CNT
(
3
)
)
cache_test_instance
(
.
clk
(
clk
),
.
rst
(
rst
),
.
miss
(
miss
),
.
addr
(
addr
),
.
rd_req
(
rd_req
),
.
rd_data
(
rd_data
),
.
wr_req
(
wr_req
),
.
wr_data
(
wr_data
)
);
endmodule
lab3/CacheSrcCode/generate_cache_tb.py
0 → 100644
View file @
007cb530
# -*- coding:utf-8 -*-
# Python2 or Python3
# Author : WangXuan
#
# 功能: 生成 cache_tb.v , 即针对cache的testbench
#
verilog_head
=
'''
module cache_tb();
`define DATA_COUNT (%d)
`define RDWR_COUNT (6*`DATA_COUNT)
reg wr_cycle [`RDWR_COUNT];
reg rd_cycle [`RDWR_COUNT];
reg [31:0] addr_rom [`RDWR_COUNT];
reg [31:0] wr_data_rom [`RDWR_COUNT];
reg [31:0] validation_data [`DATA_COUNT];
initial begin
'''
verilog_tail
=
'''
end
reg clk = 1'b1, rst = 1'b1;
initial #4 rst = 1'b0;
always #1 clk = ~clk;
wire miss;
wire [31:0] rd_data;
reg [31:0] index = 0, wr_data = 0, addr = 0;
reg rd_req = 1'b0, wr_req = 1'b0;
reg rd_req_ff = 1'b0, miss_ff = 1'b0;
reg [31:0] validation_count = 0;
always @ (posedge clk or posedge rst)
if(rst) begin
rd_req_ff <= 1'b0;
miss_ff <= 1'b0;
end else begin
rd_req_ff <= rd_req;
miss_ff <= miss;
end
always @ (posedge clk or posedge rst)
if(rst) begin
validation_count <= 0;
end else begin
if(validation_count>=`DATA_COUNT) begin
validation_count <= 'hffffffff;
end else if(rd_req_ff && (index>(4*`DATA_COUNT))) begin
if(~miss_ff) begin
if(validation_data[validation_count]==rd_data)
validation_count <= validation_count+1;
else
validation_count <= 0;
end
end else begin
validation_count <= 0;
end
end
always @ (posedge clk or posedge rst)
if(rst) begin
index <= 0;
wr_data <= 0;
addr <= 0;
rd_req <= 1'b0;
wr_req <= 1'b0;
end else begin
if(~miss) begin
if(index<`RDWR_COUNT) begin
if(wr_cycle[index]) begin
rd_req <= 1'b0;
wr_req <= 1'b1;
end else if(rd_cycle[index]) begin
wr_data <= 0;
rd_req <= 1'b1;
wr_req <= 1'b0;
end else begin
wr_data <= 0;
rd_req <= 1'b0;
wr_req <= 1'b0;
end
wr_data <= wr_data_rom[index];
addr <= addr_rom[index];
index <= index + 1;
end else begin
wr_data <= 0;
addr <= 0;
rd_req <= 1'b0;
wr_req <= 1'b0;
end
end
end
cache #(
.LINE_ADDR_LEN ( 3 ),
.SET_ADDR_LEN ( 2 ),
.TAG_ADDR_LEN ( 12 ),
.WAY_CNT ( 3 )
) cache_test_instance (
.clk ( clk ),
.rst ( rst ),
.miss ( miss ),
.addr ( addr ),
.rd_req ( rd_req ),
.rd_data ( rd_data ),
.wr_req ( wr_req ),
.wr_data ( wr_data )
);
endmodule
'''
import
sys
from
random
import
randint
if
len
(
sys
.
argv
)
!=
2
:
print
(
' Usage:
\n
python generate_cache_tb.py [write words]'
)
print
(
' Example:
\n
python generate_cache_tb.py 16'
)
print
(
' Tip: use this command to write to file:
\n
python generate_cache_tb.py 16 > cache_tb.v'
)
else
:
try
:
N
=
int
(
sys
.
argv
[
1
]
)
except
:
print
(
' *** Error: parameter must be integer, not %s'
%
(
sys
.
argv
[
1
],
)
)
sys
.
exit
(
-
1
)
result
=
[]
verilog
=
verilog_head
%
(
N
,)
verilog
+=
" // %d sequence write cycles
\n
"
%
(
N
,)
for
i
in
range
(
N
):
writeval
=
randint
(
0
,
4
*
N
)
result
.
append
(
writeval
)
verilog
+=
" rd_cycle[%5d] = 1'b0; wr_cycle[%5d] = 1'b1; addr_rom[%5d]='h%08x; wr_data_rom[%5d]='h%08x;
\n
"
%
(
i
,
i
,
i
,
i
*
4
,
i
,
writeval
)
verilog
+=
" // %d random read and write cycles
\n
"
%
(
3
*
N
,)
for
i
in
range
(
N
,
4
*
N
):
rd_wr_addr
=
randint
(
0
,
N
-
1
)
if
randint
(
0
,
1
)
==
0
:
writeval
=
randint
(
0
,
4
*
N
)
result
[
rd_wr_addr
]
=
writeval
verilog
+=
" rd_cycle[%5d] = 1'b0; wr_cycle[%5d] = 1'b1; addr_rom[%5d]='h%08x; wr_data_rom[%5d]='h%08x;
\n
"
%
(
i
,
i
,
i
,
rd_wr_addr
*
4
,
i
,
writeval
)
else
:
verilog
+=
" rd_cycle[%5d] = 1'b1; wr_cycle[%5d] = 1'b0; addr_rom[%5d]='h%08x; wr_data_rom[%5d]='h%08x;
\n
"
%
(
i
,
i
,
i
,
rd_wr_addr
*
4
,
i
,
0
)
verilog
+=
" // %d silence cycles
\n
"
%
(
N
,)
for
i
in
range
(
4
*
N
,
5
*
N
):
verilog
+=
" rd_cycle[%5d] = 1'b0; wr_cycle[%5d] = 1'b0; addr_rom[%5d]='h%08x; wr_data_rom[%5d]='h%08x;
\n
"
%
(
i
,
i
,
i
,
0
,
i
,
0
)
verilog
+=
" // %d sequence read cycles
\n
"
%
(
N
,)
for
i
in
range
(
5
*
N
,
6
*
N
):
verilog
+=
" rd_cycle[%5d] = 1'b1; wr_cycle[%5d] = 1'b0; addr_rom[%5d]='h%08x; wr_data_rom[%5d]='h%08x;
\n
"
%
(
i
,
i
,
i
,
(
i
-
5
*
N
)
*
4
,
i
,
0
)
verilog
+=
'end
\n\n
initial begin
\n
'
for
i
,
res
in
enumerate
(
result
):
verilog
+=
" validation_data[%5d] = 'h%08x;
\n
"
%
(
i
,
res
)
verilog
+=
verilog_tail
res_str
=
'`timescale 1ns/100ps
\n
//correct read result:
\n
//'
for
res
in
result
:
res_str
+=
' %08x'
%
(
res
,
)
print
(
res_str
)
print
(
verilog
)
\ No newline at end of file
lab3/CacheSrcCode/main_mem.sv
0 → 100644
View file @
007cb530
module
main_mem
#(
// 每次读取一个line
parameter
LINE_ADDR_LEN
=
3
,
// line内地址长度,决定了每个line具有 2^LINE_ADDR_LEN 个word
parameter
ADDR_LEN
=
8
// 决定了mem中包含 2^ADDR_LEN 个line
)(
input
clk
,
rst
,
output
gnt
,
// read or write grant
input
[
ADDR_LEN
-
1
:
0
]
addr
,
// line的地址
input
rd_req
,
output
reg
[
31
:
0
]
rd_line
[
1
<<
LINE_ADDR_LEN
],
input
wr_req
,
input
[
31
:
0
]
wr_line
[
1
<<
LINE_ADDR_LEN
]
);
localparam
RD_CYCLE
=
50
;
localparam
WR_CYCLE
=
50
;
localparam
LINE_SIZE
=
1
<<
LINE_ADDR_LEN
;
reg
mem_wr_req
=
1'b0
;
reg
[(
ADDR_LEN
+
LINE_ADDR_LEN
)
-
1
:
0
]
mem_addr
=
0
;
reg
[
31
:
0
]
mem_wr_data
=
0
;
wire
[
31
:
0
]
mem_rd_data
;
mem
#(
.
ADDR_LEN
(
ADDR_LEN
+
LINE_ADDR_LEN
)
)
mem_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
addr
(
mem_addr
),
.
rd_data
(
mem_rd_data
),
.
wr_req
(
mem_wr_req
),
.
wr_data
(
mem_wr_data
)
);
reg
[
31
:
0
]
rd_delay
=
0
,
wr_delay
=
0
;
wire
rd_ok
=
(
rd_delay
>=
RD_CYCLE
);
wire
wr_ok
=
(
wr_delay
>=
WR_CYCLE
);
reg
rd_cycle
,
wr_cycle
;
reg
[
ADDR_LEN
-
1
:
0
]
addr_last
=
0
;
reg
[
31
:
0
]
rd_line_latch
[
LINE_SIZE
];
wire
[
LINE_ADDR_LEN
-
1
:
0
]
wr_line_addr
=
wr_delay
-
(
WR_CYCLE
-
LINE_SIZE
);
wire
[
LINE_ADDR_LEN
-
1
:
0
]
rd_line_addr
=
rd_delay
-
1
;
wire
[
LINE_ADDR_LEN
-
1
:
0
]
rd_out_line_addr
=
rd_delay
-
3
;
assign
gnt
=
(
rd_cycle
&
rd_ok
)
|
(
wr_cycle
&
wr_ok
);
always
@
(
posedge
clk
or
posedge
rst
)
if
(
rst
)
addr_last
<=
0
;
else
addr_last
<=
addr
;
always
@
(
*
)
begin
rd_cycle
=
1'b0
;
wr_cycle
=
1'b0
;
if
(
addr_last
==
addr
)
if
(
rd_req
)
rd_cycle
=
1'b1
;
else
if
(
wr_req
)
wr_cycle
=
1'b1
;
end
always
@
(
posedge
clk
or
posedge
rst
)
// ?????
if
(
rst
)
begin
mem_wr_req
=
1'b0
;
mem_addr
=
0
;
mem_wr_data
=
0
;
end
else
begin
mem_wr_req
=
1'b0
;
mem_addr
=
0
;
mem_wr_data
=
0
;
if
(
wr_cycle
)
begin
rd_delay
<=
0
;
if
(
wr_ok
)
begin
wr_delay
<=
0
;
end
else
begin
if
(
wr_delay
>=
(
WR_CYCLE
-
LINE_SIZE
))
begin
mem_wr_req
=
1'b1
;
mem_addr
=
{
addr
,
wr_line_addr
}
;
mem_wr_data
=
wr_line
[
wr_line_addr
];
end
wr_delay
<=
wr_delay
+
1
;
end
end
else
if
(
rd_cycle
)
begin
wr_delay
<=
0
;
if
(
rd_ok
)
begin
rd_line
<=
rd_line_latch
;
end
else
begin
if
(
rd_delay
>=
1
&&
rd_delay
<
1
+
LINE_SIZE
)
begin
mem_addr
=
{
addr
,
rd_line_addr
}
;
end
if
(
rd_delay
>=
3
&&
rd_delay
<
3
+
LINE_SIZE
)
begin
rd_line_latch
[
rd_out_line_addr
]
<=
mem_rd_data
;