Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenXiangShan
XiangShan
提交
3cd542e6
X
XiangShan
项目概览
OpenXiangShan
/
XiangShan
大约 1 年 前同步成功
通知
1183
Star
3914
Fork
526
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
X
XiangShan
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3cd542e6
编写于
8月 06, 2020
作者:
A
Allen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added ldu and stu.
上级
228d8adf
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
853 addition
and
67 deletion
+853
-67
src/main/scala/xiangshan/mem/Mem.scala
src/main/scala/xiangshan/mem/Mem.scala
+2
-2
src/main/scala/xiangshan/mem/cache/dcache.scala
src/main/scala/xiangshan/mem/cache/dcache.scala
+95
-65
src/main/scala/xiangshan/mem/cache/ldu.scala
src/main/scala/xiangshan/mem/cache/ldu.scala
+163
-0
src/main/scala/xiangshan/mem/cache/missQueue.scala
src/main/scala/xiangshan/mem/cache/missQueue.scala
+443
-0
src/main/scala/xiangshan/mem/cache/stu.scala
src/main/scala/xiangshan/mem/cache/stu.scala
+150
-0
未找到文件。
src/main/scala/xiangshan/mem/Mem.scala
浏览文件 @
3cd542e6
...
...
@@ -95,6 +95,6 @@ class DCacheResp extends MemBundle
class
LSUDMemIO
extends
MemBundle
{
val
req
=
new
DecoupledIO
(
Vec
(
memWidth
,
Valid
(
new
DCacheReq
))
)
val
resp
=
Flipped
(
Vec
(
memWidth
,
new
ValidIO
(
new
DCacheResp
)
))
val
req
=
new
DecoupledIO
(
new
DCacheReq
)
val
resp
=
Flipped
(
new
ValidIO
(
new
DCacheResp
))
}
src/main/scala/xiangshan/mem/cache/dcache.scala
浏览文件 @
3cd542e6
...
...
@@ -107,67 +107,16 @@ class L1MetaWriteReq extends L1MetaReadReq {
}
class
L1DataReadReq
extends
DCacheBundle
{
// you can choose which beat to read to save power
val
rmask
=
Bits
(
refillCycles
.
W
))
val
way_en
=
Bits
(
nWays
.
W
)
val
addr
=
Bits
(
untagBits
.
W
)
}
// Now, we can write a cache-block in a single cycle
class
L1DataWriteReq
extends
L1DataReadReq
{
val
wmask
=
Bits
(
rowWords
.
W
)
val
data
=
Bits
(
encRowBits
.
W
)
}
class
L1MetadataArray
[
T
<:
L1Metadata
](
onReset
:
()
=>
T
)
extends
DCacheModule
{
val
rstVal
=
onReset
()
val
io
=
IO
(
new
Bundle
{
val
read
=
Flipped
(
Decoupled
(
new
L1MetaReadReq
))
val
write
=
Flipped
(
Decoupled
(
new
L1MetaWriteReq
))
val
resp
=
Output
(
Vec
(
nWays
,
rstVal
.
cloneType
))
})
val
rst_cnt
=
RegInit
(
0.
U
(
log2Up
(
nSets
+
1
).
W
))
val
rst
=
rst_cnt
<
nSets
.
U
val
waddr
=
Mux
(
rst
,
rst_cnt
,
io
.
write
.
bits
.
idx
)
val
wdata
=
Mux
(
rst
,
rstVal
,
io
.
write
.
bits
.
data
).
asUInt
val
wmask
=
Mux
(
rst
||
(
nWays
==
1
).
B
,
(-
1
).
asSInt
,
io
.
write
.
bits
.
way_en
.
asSInt
).
asBools
val
rmask
=
Mux
(
rst
||
(
nWays
==
1
).
B
,
(-
1
).
asSInt
,
io
.
read
.
bits
.
way_en
.
asSInt
).
asBools
when
(
rst
)
{
rst_cnt
:=
rst_cnt
+
1.
U
}
val
metabits
=
rstVal
.
getWidth
val
tag_array
=
SyncReadMem
(
nSets
,
Vec
(
nWays
,
UInt
(
metabits
.
W
)))
val
wen
=
rst
||
io
.
write
.
valid
when
(
wen
)
{
tag_array
.
write
(
waddr
,
VecInit
(
Array
.
fill
(
nWays
)(
wdata
)),
wmask
)
}
io
.
resp
:=
tag_array
.
read
(
io
.
read
.
bits
.
idx
,
io
.
read
.
fire
()).
map
(
_
.
asTypeOf
(
rstVal
))
io
.
read
.
ready
:=
!
wen
// so really this could be a 6T RAM
io
.
write
.
ready
:=
!
rst
def
dumpRead
()
=
{
when
(
io
.
read
.
fire
())
{
XSDebug
(
"MetaArray Read: idx: %d way_en: %x tag: %x\n"
,
io
.
read
.
bits
.
idx
,
io
.
read
.
bits
.
way_en
,
io
.
read
.
bits
.
tag
)
}
}
def
dumpWrite
()
=
{
when
(
io
.
write
.
fire
())
{
XSDebug
(
"MetaArray Write: idx: %d way_en: %x tag: %x new_tag: %x new_coh: %x\n"
,
io
.
write
.
bits
.
idx
,
io
.
write
.
bits
.
way_en
,
io
.
write
.
bits
.
tag
,
io
.
write
.
bits
.
data
.
tag
,
io
.
write
.
bits
.
data
.
coh
.
state
)
}
}
def
dumpResp
()
=
{
(
0
until
nWays
)
map
{
i
=>
XSDebug
(
s
"MetaArray Resp: way: $i tag: %x coh: %x\n"
,
io
.
resp
(
i
).
tag
,
io
.
resp
(
i
).
coh
.
state
)
}
}
def
dump
()
=
{
dumpRead
dumpWrite
dumpResp
}
val
wmask
=
Vec
(
refillCycles
,
Bits
(
rowWords
.
W
))
val
data
=
Vec
(
refillCycles
,
Bits
(
encRowBits
.
W
))
}
// argument general L1 DCache bundles with memWidth
...
...
@@ -184,7 +133,7 @@ abstract class AbstractDataArray extends DCacheModule {
val
io
=
IO
(
new
DCacheBundle
{
val
read
=
Input
(
Vec
(
memWidth
,
Valid
(
new
L1DataReadReq
)))
val
write
=
Input
(
Valid
(
new
L1DataWriteReq
))
val
resp
=
Output
(
Vec
(
memWidth
,
Vec
(
nWays
,
Bits
(
encRowBits
.
W
))))
val
resp
=
Output
(
Vec
(
memWidth
,
Vec
(
nWays
,
Vec
(
refillCycles
,
Bits
(
encRowBits
.
W
)
))))
val
nacks
=
Output
(
Vec
(
memWidth
,
Bool
()))
})
...
...
@@ -234,17 +183,19 @@ abstract class AbstractDataArray extends DCacheModule {
class
DuplicatedDataArray
extends
AbstractDataArray
{
val
waddr
=
io
.
write
.
bits
.
addr
>>
row
OffBits
val
waddr
=
io
.
write
.
bits
.
addr
>>
block
OffBits
for
(
j
<-
0
until
memWidth
)
{
val
raddr
=
io
.
read
(
j
).
bits
.
addr
>>
rowOffBits
val
raddr
=
io
.
read
(
j
).
bits
.
addr
>>
blockOffBits
for
(
w
<-
0
until
nWays
)
{
val
array
=
SyncReadMem
(
nSets
*
refillCycles
,
Vec
(
rowWords
,
Bits
(
encDataBits
.
W
)))
when
(
io
.
write
.
bits
.
way_en
(
w
)
&&
io
.
write
.
valid
)
{
val
data
=
VecInit
((
0
until
rowWords
)
map
(
i
=>
io
.
write
.
bits
.
data
(
encDataBits
*(
i
+
1
)-
1
,
encDataBits
*
i
)))
array
.
write
(
waddr
,
data
,
io
.
write
.
bits
.
wmask
.
asBools
)
for
(
r
<-
0
until
refillCycles
)
{
val
array
=
SyncReadMem
(
nSets
,
Vec
(
rowWords
,
Bits
(
encDataBits
.
W
)))
when
(
io
.
write
.
bits
.
way_en
(
w
)
&&
io
.
write
.
valid
)
{
val
data
=
VecInit
((
0
until
rowWords
)
map
(
i
=>
io
.
write
.
bits
.
data
(
encDataBits
*(
i
+
1
)-
1
,
encDataBits
*
i
)))
array
.
write
(
waddr
,
data
,
io
.
write
.
bits
.
wmask
(
r
).
asBools
)
}
io
.
resp
(
j
)(
w
)(
r
)
:=
RegNext
(
array
.
read
(
raddr
,
io
.
read
(
j
).
bits
.
way_en
(
w
)
&&
io
.
read
(
j
).
bits
.
rmask
(
r
)
&&
io
.
read
(
j
).
valid
).
asUInt
)
}
io
.
resp
(
j
)(
w
)
:=
RegNext
(
array
.
read
(
raddr
,
io
.
read
(
j
).
bits
.
way_en
(
w
)
&&
io
.
read
(
j
).
valid
).
asUInt
)
}
io
.
nacks
(
j
)
:=
false
.
B
}
...
...
@@ -323,6 +274,85 @@ class BankedDataArray extends AbstractDataArray {
io
.
nacks
:=
s2_nacks
}
class
L1MetadataArray
[
T
<:
L1Metadata
](
onReset
:
()
=>
T
)
extends
DCacheModule
{
val
rstVal
=
onReset
()
val
io
=
IO
(
new
Bundle
{
val
read
=
Flipped
(
Decoupled
(
new
L1MetaReadReq
))
val
write
=
Flipped
(
Decoupled
(
new
L1MetaWriteReq
))
val
resp
=
Output
(
Vec
(
nWays
,
rstVal
.
cloneType
))
})
val
rst_cnt
=
RegInit
(
0.
U
(
log2Up
(
nSets
+
1
).
W
))
val
rst
=
rst_cnt
<
nSets
.
U
val
waddr
=
Mux
(
rst
,
rst_cnt
,
io
.
write
.
bits
.
idx
)
val
wdata
=
Mux
(
rst
,
rstVal
,
io
.
write
.
bits
.
data
).
asUInt
val
wmask
=
Mux
(
rst
||
(
nWays
==
1
).
B
,
(-
1
).
asSInt
,
io
.
write
.
bits
.
way_en
.
asSInt
).
asBools
val
rmask
=
Mux
(
rst
||
(
nWays
==
1
).
B
,
(-
1
).
asSInt
,
io
.
read
.
bits
.
way_en
.
asSInt
).
asBools
when
(
rst
)
{
rst_cnt
:=
rst_cnt
+
1.
U
}
val
metabits
=
rstVal
.
getWidth
val
tag_array
=
SyncReadMem
(
nSets
,
Vec
(
nWays
,
UInt
(
metabits
.
W
)))
val
wen
=
rst
||
io
.
write
.
valid
when
(
wen
)
{
tag_array
.
write
(
waddr
,
VecInit
(
Array
.
fill
(
nWays
)(
wdata
)),
wmask
)
}
io
.
resp
:=
tag_array
.
read
(
io
.
read
.
bits
.
idx
,
io
.
read
.
fire
()).
map
(
_
.
asTypeOf
(
rstVal
))
io
.
read
.
ready
:=
!
wen
// so really this could be a 6T RAM
io
.
write
.
ready
:=
!
rst
def
dumpRead
()
=
{
when
(
io
.
read
.
fire
())
{
XSDebug
(
"MetaArray Read: idx: %d way_en: %x tag: %x\n"
,
io
.
read
.
bits
.
idx
,
io
.
read
.
bits
.
way_en
,
io
.
read
.
bits
.
tag
)
}
}
def
dumpWrite
()
=
{
when
(
io
.
write
.
fire
())
{
XSDebug
(
"MetaArray Write: idx: %d way_en: %x tag: %x new_tag: %x new_coh: %x\n"
,
io
.
write
.
bits
.
idx
,
io
.
write
.
bits
.
way_en
,
io
.
write
.
bits
.
tag
,
io
.
write
.
bits
.
data
.
tag
,
io
.
write
.
bits
.
data
.
coh
.
state
)
}
}
def
dumpResp
()
=
{
(
0
until
nWays
)
map
{
i
=>
XSDebug
(
s
"MetaArray Resp: way: $i tag: %x coh: %x\n"
,
io
.
resp
(
i
).
tag
,
io
.
resp
(
i
).
coh
.
state
)
}
}
def
dump
()
=
{
dumpRead
dumpWrite
dumpResp
}
}
class
DuplicatedMetaArray
extends
DCacheModule
{
val
io
=
IO
(
new
DCacheBundle
{
val
read
=
Input
(
Vec
(
memWidth
,
Valid
(
new
L1MetaReadReq
)))
val
write
=
Input
(
Valid
(
new
L1MetaWriteReq
))
val
resp
=
Output
(
Vec
(
memWidth
,
Vec
(
nWays
,
Vec
(
refillCycles
,
Bits
(
encRowBits
.
W
)))))
val
nacks
=
Output
(
Vec
(
memWidth
,
Bool
()))
})
def
onReset
=
L1Metadata
(
0.
U
,
ClientMetadata
.
onReset
)
val
meta
=
Seq
.
fill
(
memWidth
)
{
Module
(
new
L1MetadataArray
(
onReset
_
))
}
for
(
w
<-
0
until
memWidth
)
{
meta
(
w
).
io
.
write
<>
io
.
write
meta
(
w
).
io
.
read
<>
io
.
read
(
w
)
meta
(
w
).
io
.
resp
<>
io
.
resp
(
w
)
}
def
dump
()
=
{
(
0
until
memWidth
)
map
{
w
=>
XSDebug
(
s
"MetaArray $w\n"
)
meta
(
w
).
dump
}
}
}
class
DCache
extends
DCacheModule
...
...
src/main/scala/xiangshan/mem/cache/ldu.scala
0 → 100644
浏览文件 @
3cd542e6
package
xiangshan.mem.cache
import
chisel3._
import
chisel3.util._
import
chisel3.util.experimental.BoringUtils
import
xiangshan.mem.
{
DCacheReq
,
DCacheResp
,
LSUDMemIO
}
import
xiangshan.utils.XSDebug
import
bus.tilelink._
import
_root_.utils.
{
Code
,
RandomReplacement
,
Transpose
}
import
xiangshan.mem.MemoryOpConstants
class
LoadPipe
extends
DCacheModule
{
val
io
=
IO
(
new
DCacheBundle
{
val
lsu
=
Flipped
(
new
LSUDMemIO
)
val
data_read
=
Output
(
Valid
(
new
L1DataReadReq
))
val
data_resp
=
Output
(
Vec
(
nWays
,
Vec
(
refillCycles
,
Bits
(
encRowBits
.
W
))))
val
meta_read
=
Decoupled
(
new
L1MetaReadReq
)
val
meta_resp
=
Output
(
Vec
(
nWays
,
rstVal
.
cloneType
))
})
// LSU requests
io
.
lsu
.
req
.
ready
:=
io
.
meta_read
.
ready
&&
io
.
data_read
.
ready
io
.
meta_read
.
bits
.
valid
:=
io
.
lsu
.
req
.
valid
io
.
data_read
.
bits
.
valid
:=
io
.
lsu
.
req
.
valid
val
meta_read
=
io
.
meta_read
.
bits
val
data_read
=
io
.
data_read
.
bits
for
(
w
<-
0
until
memWidth
)
{
// Tag read for new requests
meta_read
.
idx
:=
io
.
lsu
.
req
.
bits
(
w
).
bits
.
addr
>>
blockOffBits
meta_read
.
way_en
:=
~
0.
U
(
nWays
.
W
)
meta_read
.
tag
:=
DontCare
// Data read for new requests
data_read
.
addr
:=
io
.
lsu
.
req
.
bits
(
w
).
bits
.
addr
data_read
.
way_en
:=
~
0.
U
(
nWays
.
W
)
}
// Pipeline
// stage 0
val
s0_valid
=
io
.
lsu
.
req
.
fire
()
val
s0_req
=
io
.
lsu
.
req
.
bits
assert
(!(
s0_valid
&&
s0_req
.
cmd
=/=
MemoryOpConstants
.
M_XRD
),
"LoadPipe only accepts load req"
)
dump_pipeline_reqs
(
"LoadPipe s0"
,
s0_valid
,
s0_req
,
s0_type
)
// stage 1
val
s1_req
=
RegNext
(
s0_req
)
val
s1_valid
=
RegNext
(
s0_valid
,
init
=
false
.
B
)
val
s1_addr
=
s1_req
.
addr
val
s1_nack
=
false
.
B
dump_pipeline_reqs
(
"LoadPipe s1"
,
s1_valid
,
s1_req
,
s1_type
)
// tag check
def
wayMap
[
T
<:
Data
](
f
:
Int
=>
T
)
=
VecInit
((
0
until
nWays
).
map
(
f
))
val
s1_tag_eq_way
=
wayMap
((
w
:
Int
)
=>
meta_resp
(
w
).
tag
===
(
s1_addr
>>
untagBits
)).
asUInt
val
s1_tag_match_way
=
wayMap
((
w
:
Int
)
=>
s1_tag_eq_way
(
i
)(
w
)
&&
meta
(
i
).
io
.
resp
(
w
).
coh
.
isValid
()).
asUInt
// stage 2
val
s2_req
=
RegNext
(
s1_req
)
val
s2_valid
=
RegNext
(
s1_valid
(
w
),
init
=
false
.
B
))
dump_pipeline_reqs
(
"LoadPipe s2"
,
s2_valid
,
s2_req
,
s2_type
)
val
s2_tag_match_way
=
RegNext
(
s1_tag_match_way
)
val
s2_tag_match
=
s2_tag_match_way
.
orR
val
s2_hit_state
=
Mux1H
(
s2_tag_match_way
(
i
),
wayMap
((
w
:
Int
)
=>
RegNext
(
meta_resp
(
w
).
coh
)))
val
s2_has_permission
=
s2_hit_state
.
onAccess
(
s2_req
.
cmd
).
_1
val
s2_new_hit_state
=
s2_hit_state
.
onAccess
(
s2_req
.
cmd
).
_3
// we not only need permissions
// we also require that state does not change on hit
// thus we require new_hit_state === old_hit_state
//
// If state changes on hit,
// we should treat it as not hit, and let mshr deal with it,
// since we can not write meta data on the main pipeline.
// It's possible that we had permission but state changes on hit:
// eg: write to exclusive but clean block
val
s2_hit
=
s2_tag_match
&&
s2_has_permission
&&
s2_hit_state
===
s2_new_hit_state
&&
!
mshrs
.
io
.
block_hit
val
s2_nack
=
Wire
(
Bool
())
val
s2_data
=
Wire
(
Vec
(
nWays
,
UInt
(
encRowBits
.
W
)))
for
(
w
<-
0
until
nWays
)
{
s2_data
(
w
)
:=
data_resp
(
w
)
}
val
s2_data_muxed
=
Mux1H
(
s2_tag_match_way
,
s2_data
)
// the index of word in a row, in case rowBits != wordBits
val
s2_word_idx
=
if
(
rowWords
==
1
)
0.
U
else
s2_req
.
addr
(
log2Up
(
rowWords
*
wordBytes
)-
1
,
log2Up
(
wordBytes
))
val
s2_nack_hit
=
RegNext
(
s1_nack
)
// Can't allocate MSHR for same set currently being written back
// the same set is busy
val
s2_nack_set_busy
=
s2_valid
&&
mshrs
.
io
.
block_hit
// Bank conflict on data arrays
val
s2_nack_data
=
data_resp
.
nacks
s2_nack
:=
s2_nack_hit
||
s2_nack_set_busy
||
s2_nack_data
dump_pipeline_valids
(
"LoadPipe s2"
,
"s2_hit"
,
s2_hit
)
dump_pipeline_valids
(
"LoadPipe s2"
,
"s2_nack"
,
s2_nack
)
dump_pipeline_valids
(
"LoadPipe s2"
,
"s2_nack_hit"
,
s2_nack_hit
)
dump_pipeline_valids
(
"LoadPipe s2"
,
"s2_nack_set_busy"
,
s2_nack_set_busy
)
// load data gen
val
s2_data_word
=
s2_data_muxed
>>
Cat
(
s2_word_idx
,
0.
U
(
log2Ceil
(
wordBits
).
W
))
val
resp
=
Wire
(
Valid
(
new
DCacheResp
))
for
(
w
<-
0
until
memWidth
)
{
resp
.
valid
:=
s2_valid
resp
.
bits
.
data
:=
s2_data_word
resp
.
bits
.
meta
:=
s2_req
.
meta
resp
.
bits
.
nack
:=
s2_nack
}
io
.
lsu
.
resp
(
w
)
<>
resp
(
w
)
when
(
resp
.
valid
)
{
XSDebug
(
s
"DCache resp: data: %x meta: %d nack: %b\n"
,
resp
.
data
,
resp
.
meta
,
resp
.
nack
)
}
// -------
// Debug logging functions
def
dump_pipeline_reqs
(
pipeline_stage_name
:
String
,
valid
:
Vec
[
Bool
],
reqs
:
Vec
[
DCacheReq
],
req_type
:
UInt
)
=
{
val
anyValid
=
valid
.
reduce
(
_
||
_
)
when
(
anyValid
)
{
(
0
until
memWidth
)
map
{
w
=>
when
(
valid
(
w
))
{
XSDebug
(
s
"$pipeline_stage_name\n"
)
XSDebug
(
"channel %d: valid: %b \n"
,
w
.
U
,
valid
(
w
))
when
(
req_type
===
t_replay
)
{
XSDebug
(
"req_type: replay "
)
}
.
elsewhen
(
req_type
===
t_lsu
)
{
XSDebug
(
"req_type: lsu "
)
}
.
otherwise
{
XSDebug
(
"req_type: unknown "
)
}
XSDebug
(
"cmd: %x addr: %x data: %x mask: %x meta: %x\n"
,
reqs
(
w
).
cmd
,
reqs
(
w
).
addr
,
reqs
(
w
).
data
,
reqs
(
w
).
mask
,
reqs
(
w
).
meta
)
}
}
}
}
def
dump_pipeline_valids
(
pipeline_stage_name
:
String
,
signal_name
:
String
,
valid
:
Vec
[
Bool
])
=
{
val
anyValid
=
valid
.
reduce
(
_
||
_
)
when
(
anyValid
)
{
(
0
until
memWidth
)
map
{
w
=>
when
(
valid
(
w
))
{
XSDebug
(
s
"$pipeline_stage_name channel %d: $signal_name\n"
,
w
.
U
)
}
}
}
}
}
src/main/scala/xiangshan/mem/cache/missQueue.scala
0 → 100644
浏览文件 @
3cd542e6
//******************************************************************************
// Ported from Rocket-Chip
// See LICENSE.Berkeley and LICENSE.SiFive in Rocket-Chip for license details.
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
package
xiangshan.mem.cache
import
chisel3._
import
chisel3.util._
import
xiangshan.mem.DCacheReq
import
xiangshan.utils.XSDebug
import
bus.tilelink._
class
DCacheReqInternal
extends
DCacheReq
with
HasDCacheParameters
{
// miss info
val
tag_match
=
Bool
()
val
old_meta
=
new
L1Metadata
val
way_en
=
UInt
(
nWays
.
W
)
val
sdq_id
=
UInt
(
log2Up
(
cfg
.
nSDQ
).
W
)
}
class
MSHR
extends
DCacheModule
{
val
io
=
IO
(
new
Bundle
{
val
id
=
Input
(
UInt
())
val
req_pri_val
=
Input
(
Bool
())
val
req_pri_rdy
=
Output
(
Bool
())
val
req
=
Input
(
new
DCacheReqInternal
)
val
idx
=
Output
(
Valid
(
UInt
()))
val
way
=
Output
(
Valid
(
UInt
()))
val
tag
=
Output
(
Valid
(
UInt
()))
val
mem_acquire
=
Decoupled
(
new
TLBundleA
(
cfg
.
busParams
))
val
mem_grant
=
Flipped
(
Decoupled
(
new
TLBundleD
(
cfg
.
busParams
)))
val
mem_finish
=
Decoupled
(
new
TLBundleE
(
cfg
.
busParams
))
val
refill
=
Decoupled
(
new
L1DataWriteReq
)
val
meta_write
=
Decoupled
(
new
L1MetaWriteReq
)
val
wb_req
=
Decoupled
(
new
WritebackReq
)
val
wb_resp
=
Input
(
Bool
())
// Replays go through the cache pipeline again
val
replay
=
Decoupled
(
new
DCacheReqInternal
)
})
// TODO: Optimize this. We don't want to mess with cache during speculation
// s_refill_req : Make a request for a new cache line
// s_refill_resp : Store the refill response into our buffer
// s_drain_rpq_loads : Drain out loads from the rpq
// : If miss was misspeculated, go to s_invalid
// s_wb_req : Write back the evicted cache line
// s_wb_resp : Finish writing back the evicted cache line
// s_meta_write_req : Write the metadata for new cache lne
// s_meta_write_resp :
val
s_invalid
::
s_refill_req
::
s_refill_resp
::
s_wb_req
::
s_wb_resp
::
s_drain_rpq
::
s_meta_write_req
::
s_mem_finish
::
Nil
=
Enum
(
8
)
val
state
=
RegInit
(
s_invalid
)
val
req
=
Reg
(
new
DCacheReqInternal
)
val
req_idx
=
req
.
addr
(
untagBits
-
1
,
blockOffBits
)
val
req_tag
=
req
.
addr
>>
untagBits
val
req_block_addr
=
(
req
.
addr
>>
blockOffBits
)
<<
blockOffBits
val
new_coh
=
RegInit
(
ClientMetadata
.
onReset
)
val
(
_
,
shrink_param
,
coh_on_clear
)
=
req
.
old_meta
.
coh
.
onCacheControl
(
M_FLUSH
)
val
grow_param
=
new_coh
.
onAccess
(
req
.
cmd
).
_2
val
coh_on_grant
=
new_coh
.
onGrant
(
req
.
cmd
,
io
.
mem_grant
.
bits
.
param
)
val
(
_
,
_
,
refill_done
,
refill_address_inc
)
=
TLUtilities
.
addr_inc
(
io
.
mem_grant
)
val
rpq
=
Module
(
new
Queue
(
new
DCacheReqInternal
,
cfg
.
nRPQ
))
rpq
.
io
.
enq
.
valid
:=
io
.
req_pri_val
&&
io
.
req_pri_rdy
rpq
.
io
.
enq
.
bits
:=
io
.
req
rpq
.
io
.
deq
.
ready
:=
false
.
B
val
grantack
=
Reg
(
Valid
(
new
TLBundleE
(
cfg
.
busParams
)))
val
refill_ctr
=
Reg
(
UInt
(
log2Up
(
cacheDataBeats
).
W
))
io
.
idx
.
valid
:=
state
=/=
s_invalid
io
.
tag
.
valid
:=
state
=/=
s_invalid
io
.
way
.
valid
:=
state
=/=
s_invalid
io
.
idx
.
bits
:=
req_idx
io
.
tag
.
bits
:=
req_tag
io
.
way
.
bits
:=
req
.
way_en
XSDebug
(
"mshr: %d state: %d idx_valid: %b\n"
,
io
.
id
,
state
,
io
.
idx
.
valid
)
// assign default values to output signals
io
.
req_pri_rdy
:=
false
.
B
io
.
mem_acquire
.
valid
:=
false
.
B
io
.
mem_acquire
.
bits
:=
DontCare
io
.
mem_grant
.
ready
:=
false
.
B
io
.
mem_finish
.
valid
:=
false
.
B
io
.
mem_finish
.
bits
:=
DontCare
io
.
refill
.
valid
:=
false
.
B
io
.
refill
.
bits
:=
DontCare
io
.
meta_write
.
valid
:=
false
.
B
io
.
meta_write
.
bits
:=
DontCare
io
.
wb_req
.
valid
:=
false
.
B
io
.
wb_req
.
bits
:=
DontCare
io
.
replay
.
valid
:=
false
.
B
io
.
replay
.
bits
:=
DontCare
def
handle_pri_req
(
old_state
:
UInt
)
:
UInt
=
{
val
new_state
=
WireInit
(
old_state
)
grantack
.
valid
:=
false
.
B
refill_ctr
:=
0.
U
assert
(
rpq
.
io
.
enq
.
ready
)
req
:=
io
.
req
val
old_coh
=
io
.
req
.
old_meta
.
coh
val
needs_wb
=
old_coh
.
onCacheControl
(
M_FLUSH
).
_1
// does the line we are evicting need to be written back
when
(
io
.
req
.
tag_match
)
{
val
(
is_hit
,
_
,
coh_on_hit
)
=
old_coh
.
onAccess
(
io
.
req
.
cmd
)
when
(
is_hit
)
{
// set dirty bit
assert
(
isWrite
(
io
.
req
.
cmd
))
new_coh
:=
coh_on_hit
new_state
:=
s_drain_rpq
}
.
otherwise
{
// upgrade permissions
new_coh
:=
old_coh
new_state
:=
s_refill_req
}
}
.
otherwise
{
// refill and writeback if necessary
new_coh
:=
ClientMetadata
.
onReset
when
(
needs_wb
)
{
new_state
:=
s_wb_req
}
.
otherwise
{
new_state
:=
s_refill_req
}
}
new_state
}
// --------------------------------------------
// s_invalid: receive requests
when
(
state
===
s_invalid
)
{
io
.
req_pri_rdy
:=
true
.
B
when
(
io
.
req_pri_val
&&
io
.
req_pri_rdy
)
{
state
:=
handle_pri_req
(
state
)
}
}
// --------------------------------------------
// write back
when
(
state
===
s_wb_req
)
{
io
.
wb_req
.
valid
:=
true
.
B
io
.
wb_req
.
bits
.
tag
:=
req
.
old_meta
.
tag
io
.
wb_req
.
bits
.
idx
:=
req_idx
io
.
wb_req
.
bits
.
param
:=
shrink_param
io
.
wb_req
.
bits
.
way_en
:=
req
.
way_en
io
.
wb_req
.
bits
.
source
:=
io
.
id
io
.
wb_req
.
bits
.
voluntary
:=
true
.
B
when
(
io
.
wb_req
.
fire
())
{
state
:=
s_wb_resp
}
}
when
(
state
===
s_wb_resp
)
{
when
(
io
.
wb_resp
)
{
state
:=
s_refill_req
}
}
// --------------------------------------------
// refill
when
(
state
===
s_refill_req
)
{
io
.
mem_acquire
.
valid
:=
true
.
B
// TODO: Use AcquirePerm if just doing permissions acquire
io
.
mem_acquire
.
bits
:=
TLMasterUtilities
.
AcquireBlock
(
params
=
cfg
.
busParams
,
fromSource
=
io
.
id
,
toAddress
=
Cat
(
req_tag
,
req_idx
)
<<
blockOffBits
,
lgSize
=
(
log2Up
(
cfg
.
blockBytes
)).
U
,
growPermissions
=
grow_param
).
_2
when
(
io
.
mem_acquire
.
fire
())
{
state
:=
s_refill_resp
}
}
when
(
state
===
s_refill_resp
)
{
when
(
TLUtilities
.
hasData
(
io
.
mem_grant
.
bits
))
{
io
.
mem_grant
.
ready
:=
io
.
refill
.
ready
io
.
refill
.
valid
:=
io
.
mem_grant
.
valid
io
.
refill
.
bits
.
addr
:=
req_block_addr
|
(
refill_ctr
<<
rowOffBits
)
io
.
refill
.
bits
.
way_en
:=
req
.
way_en
io
.
refill
.
bits
.
wmask
:=
~(
0.
U
(
rowWords
.
W
))
io
.
refill
.
bits
.
data
:=
io
.
mem_grant
.
bits
.
data
when
(
io
.
refill
.
fire
())
{
refill_ctr
:=
refill_ctr
+
1.
U
when
(
refill_ctr
===
(
cacheDataBeats
-
1
).
U
)
{
assert
(
refill_done
,
"refill not done!"
)
}
}
}
.
otherwise
{
io
.
mem_grant
.
ready
:=
true
.
B
}
when
(
refill_done
)
{
grantack
.
valid
:=
TLUtilities
.
isRequest
(
io
.
mem_grant
.
bits
)
grantack
.
bits
:=
TLMasterUtilities
.
GrantAck
(
io
.
mem_grant
.
bits
)
state
:=
s_mem_finish
new_coh
:=
coh_on_grant
}
}
when
(
state
===
s_mem_finish
)
{
io
.
mem_finish
.
valid
:=
grantack
.
valid
io
.
mem_finish
.
bits
:=
grantack
.
bits
when
(
io
.
mem_finish
.
fire
())
{
grantack
.
valid
:=
false
.
B
state
:=
s_drain_rpq
}
}
// --------------------------------------------
// meta write
when
(
state
===
s_meta_write_req
)
{
io
.
meta_write
.
valid
:=
true
.
B
io
.
meta_write
.
bits
.
idx
:=
req_idx
io
.
meta_write
.
bits
.
data
.
coh
:=
new_coh
io
.
meta_write
.
bits
.
data
.
tag
:=
req_tag
io
.
meta_write
.
bits
.
way_en
:=
req
.
way_en
when
(
io
.
meta_write
.
fire
())
{
state
:=
s_invalid
}
}
// --------------------------------------------
// replay
when
(
state
===
s_drain_rpq
)
{
io
.
replay
<>
rpq
.
io
.
deq
io
.
replay
.
bits
.
way_en
:=
req
.
way_en
io
.
replay
.
bits
.
addr
:=
Cat
(
req_tag
,
req_idx
,
rpq
.
io
.
deq
.
bits
.
addr
(
blockOffBits
-
1
,
0
))
when
(
io
.
replay
.
fire
()
&&
isWrite
(
rpq
.
io
.
deq
.
bits
.
cmd
))
{
// Set dirty bit
val
(
is_hit
,
_
,
coh_on_hit
)
=
new_coh
.
onAccess
(
rpq
.
io
.
deq
.
bits
.
cmd
)
assert
(
is_hit
,
"We still don't have permissions for this store"
)
new_coh
:=
coh_on_hit
}
when
(
rpq
.
io
.
count
===
0.
U
)
{
state
:=
s_meta_write_req
}
}
}
class
MSHRFile
extends
DCacheModule
{
val
io
=
IO
(
new
Bundle
{
val
req
=
Flipped
(
Vec
(
memWidth
,
Decoupled
(
new
DCacheReqInternal
)))
// Req from s2 of DCache pipe
val
block_hit
=
Output
(
Vec
(
memWidth
,
Bool
()))
val
mem_acquire
=
Decoupled
(
new
TLBundleA
(
cfg
.
busParams
))
val
mem_grant
=
Flipped
(
Decoupled
(
new
TLBundleD
(
cfg
.
busParams
)))
val
mem_finish
=
Decoupled
(
new
TLBundleE
(
cfg
.
busParams
))
val
refill
=
Decoupled
(
new
L1DataWriteReq
)
val
meta_write
=
Decoupled
(
new
L1MetaWriteReq
)
val
replay
=
Decoupled
(
new
DCacheReqInternal
)
val
wb_req
=
Decoupled
(
new
WritebackReq
)
val
wb_resp
=
Input
(
Bool
())
})
val
req_idx
=
OHToUInt
(
io
.
req
.
map
(
_
.
valid
))
val
req
=
io
.
req
(
req_idx
)
for
(
w
<-
0
until
memWidth
)
io
.
req
(
w
).
ready
:=
false
.
B
val
cacheable
=
true
.
B
// --------------------
// The MSHR SDQ
val
sdq_val
=
RegInit
(
0.
U
(
cfg
.
nSDQ
.
W
))
val
sdq_alloc_id
=
PriorityEncoder
(~
sdq_val
(
cfg
.
nSDQ
-
1
,
0
))
val
sdq_rdy
=
!
sdq_val
.
andR
val
sdq_enq
=
req
.
fire
()
&&
cacheable
&&
isWrite
(
req
.
bits
.
cmd
)
val
sdq
=
Mem
(
cfg
.
nSDQ
,
UInt
(
wordBits
.
W
))
when
(
sdq_enq
)
{
sdq
(
sdq_alloc_id
)
:=
req
.
bits
.
data
}
// --------------------
// The LineBuffer Data
def
widthMap
[
T
<:
Data
](
f
:
Int
=>
T
)
=
VecInit
((
0
until
memWidth
).
map
(
f
))
val
idx_matches
=
Wire
(
Vec
(
memWidth
,
Vec
(
cfg
.
nMSHRs
,
Bool
())))
val
tag_matches
=
Wire
(
Vec
(
memWidth
,
Vec
(
cfg
.
nMSHRs
,
Bool
())))
val
way_matches
=
Wire
(
Vec
(
memWidth
,
Vec
(
cfg
.
nMSHRs
,
Bool
())))
val
tag_match
=
widthMap
(
w
=>
Mux1H
(
idx_matches
(
w
),
tag_matches
(
w
)))
val
idx_match
=
widthMap
(
w
=>
idx_matches
(
w
).
reduce
(
_
||
_
))
val
way_match
=
widthMap
(
w
=>
Mux1H
(
idx_matches
(
w
),
way_matches
(
w
)))
val
wb_tag_list
=
Wire
(
Vec
(
cfg
.
nMSHRs
,
UInt
(
tagBits
.
W
)))
val
meta_write_arb
=
Module
(
new
Arbiter
(
new
L1MetaWriteReq
,
cfg
.
nMSHRs
))
val
wb_req_arb
=
Module
(
new
Arbiter
(
new
WritebackReq
,
cfg
.
nMSHRs
))
val
replay_arb
=
Module
(
new
Arbiter
(
new
DCacheReqInternal
,
cfg
.
nMSHRs
))
val
refill_arb
=
Module
(
new
Arbiter
(
new
L1DataWriteReq
,
cfg
.
nMSHRs
))
io
.
mem_grant
.
ready
:=
false
.
B
val
mshr_alloc_idx
=
Wire
(
UInt
())
val
pri_rdy
=
WireInit
(
false
.
B
)
val
pri_val
=
req
.
valid
&&
sdq_rdy
&&
cacheable
&&
!
idx_match
(
req_idx
)
val
mshrs
=
(
0
until
cfg
.
nMSHRs
)
map
{
i
=>
val
mshr
=
Module
(
new
MSHR
)
mshr
.
io
.
id
:=
i
.
U
(
log2Up
(
cfg
.
nMSHRs
).
W
)
for
(
w
<-
0
until
memWidth
)
{
idx_matches
(
w
)(
i
)
:=
mshr
.
io
.
idx
.
valid
&&
mshr
.
io
.
idx
.
bits
===
io
.
req
(
w
).
bits
.
addr
(
untagBits
-
1
,
blockOffBits
)
tag_matches
(
w
)(
i
)
:=
mshr
.
io
.
tag
.
valid
&&
mshr
.
io
.
tag
.
bits
===
io
.
req
(
w
).
bits
.
addr
>>
untagBits
way_matches
(
w
)(
i
)
:=
mshr
.
io
.
way
.
valid
&&
mshr
.
io
.
way
.
bits
===
io
.
req
(
w
).
bits
.
way_en
when
(
idx_matches
(
w
)(
i
))
{
XSDebug
(
s
"mshr: $i channel: $w idx_match\n"
)
}
when
(
tag_matches
(
w
)(
i
))
{
XSDebug
(
s
"mshr: $i channel: $w tag_match\n"
)
}
when
(
way_matches
(
w
)(
i
))
{
XSDebug
(
s
"mshr: $i channel: $w way_match\n"
)
}
}
wb_tag_list
(
i
)
:=
mshr
.
io
.
wb_req
.
bits
.
tag
mshr
.
io
.
req_pri_val
:=
(
i
.
U
===
mshr_alloc_idx
)
&&
pri_val
when
(
i
.
U
===
mshr_alloc_idx
)
{
pri_rdy
:=
mshr
.
io
.
req_pri_rdy
}
mshr
.
io
.
req
:=
req
.
bits
mshr
.
io
.
req
.
sdq_id
:=
sdq_alloc_id
mshr
.
io
.
wb_resp
:=
io
.
wb_resp
meta_write_arb
.
io
.
in
(
i
)
<>
mshr
.
io
.
meta_write
wb_req_arb
.
io
.
in
(
i
)
<>
mshr
.
io
.
wb_req
replay_arb
.
io
.
in
(
i
)
<>
mshr
.
io
.
replay
refill_arb
.
io
.
in
(
i
)
<>
mshr
.
io
.
refill
mshr
.
io
.
mem_grant
.
valid
:=
false
.
B
mshr
.
io
.
mem_grant
.
bits
:=
DontCare
when
(
io
.
mem_grant
.
bits
.
source
===
i
.
U
)
{
mshr
.
io
.
mem_grant
<>
io
.
mem_grant
}
mshr
}
mshr_alloc_idx
:=
RegNext
(
PriorityEncoder
(
mshrs
.
map
(
m
=>
m
.
io
.
req_pri_rdy
)))
io
.
meta_write
<>
meta_write_arb
.
io
.
out
io
.
wb_req
<>
wb_req_arb
.
io
.
out
TLArbiter
.
lowestFromSeq
(
io
.
mem_acquire
,
mshrs
.
map
(
_
.
io
.
mem_acquire
))
TLArbiter
.
lowestFromSeq
(
io
.
mem_finish
,
mshrs
.
map
(
_
.
io
.
mem_finish
))
val
mmio_rdy
=
true
.
B
for
(
w
<-
0
until
memWidth
)
{
io
.
req
(
w
).
ready
:=
(
w
.
U
===
req_idx
)
&&
Mux
(!
cacheable
,
mmio_rdy
,
sdq_rdy
&&
pri_rdy
)
io
.
block_hit
(
w
)
:=
idx_match
(
w
)
}
io
.
refill
<>
refill_arb
.
io
.
out
val
free_sdq
=
io
.
replay
.
fire
()
&&
isWrite
(
io
.
replay
.
bits
.
cmd
)
io
.
replay
<>
replay_arb
.
io
.
out
io
.
replay
.
bits
.
data
:=
sdq
(
replay_arb
.
io
.
out
.
bits
.
sdq_id
)
when
(
io
.
replay
.
valid
||
sdq_enq
)
{
sdq_val
:=
sdq_val
&
~(
UIntToOH
(
replay_arb
.
io
.
out
.
bits
.
sdq_id
)
&
Fill
(
cfg
.
nSDQ
,
free_sdq
))
|
PriorityEncoderOH
(~
sdq_val
(
cfg
.
nSDQ
-
1
,
0
))
&
Fill
(
cfg
.
nSDQ
,
sdq_enq
)
}
// print all input/output requests for debug purpose
// print req
XSDebug
(
req
.
fire
(),
"req cmd: %x addr: %x data: %x mask: %x meta: %x tag_match: %b old_coh: %d old_tag: %x way_en: %x\n"
,
req
.
bits
.
cmd
,
req
.
bits
.
addr
,
req
.
bits
.
data
,
req
.
bits
.
mask
,
req
.
bits
.
meta
,
req
.
bits
.
tag_match
,
req
.
bits
.
old_meta
.
coh
.
state
,
req
.
bits
.
old_meta
.
tag
,
req
.
bits
.
way_en
)
// block hit
(
0
until
memWidth
)
map
{
w
=>
XSDebug
(
io
.
block_hit
(
w
),
"channel %d req block hit\n"
,
w
.
U
)
}
// print refill
XSDebug
(
io
.
refill
.
fire
(),
"refill addr %x data: %x wmask: %x way_en: %x\n"
,
io
.
refill
.
bits
.
addr
,
io
.
refill
.
bits
.
data
,
io
.
refill
.
bits
.
wmask
,
io
.
refill
.
bits
.
way_en
)
// print meta_write
XSDebug
(
io
.
meta_write
.
fire
(),
"meta_write idx %x way_en: %x old_tag: %x new_coh: %d new_tag: %x\n"
,
io
.
meta_write
.
bits
.
idx
,
io
.
meta_write
.
bits
.
way_en
,
io
.
meta_write
.
bits
.
data
.
coh
.
state
,
io
.
meta_write
.
bits
.
data
.
tag
,
io
.
meta_write
.
bits
.
tag
)
// print replay
XSDebug
(
io
.
replay
.
fire
(),
"replay cmd: %x addr: %x data: %x mask: %x meta: %x tag_match: %b old_coh: %d old_tag: %x way_en: %x\n"
,
io
.
replay
.
bits
.
cmd
,
io
.
replay
.
bits
.
addr
,
io
.
replay
.
bits
.
data
,
io
.
replay
.
bits
.
mask
,
io
.
replay
.
bits
.
meta
,
io
.
replay
.
bits
.
tag_match
,
io
.
replay
.
bits
.
old_meta
.
coh
.
state
,
io
.
replay
.
bits
.
old_meta
.
tag
,
io
.
replay
.
bits
.
way_en
)
// print wb_req
XSDebug
(
io
.
wb_req
.
fire
(),
"wb_req idx %x tag: %x source: %d param: %x way_en: %x voluntary: %b\n"
,
io
.
wb_req
.
bits
.
idx
,
io
.
wb_req
.
bits
.
tag
,
io
.
wb_req
.
bits
.
source
,
io
.
wb_req
.
bits
.
param
,
io
.
wb_req
.
bits
.
way_en
,
io
.
wb_req
.
bits
.
voluntary
)
// print tilelink messages
/*
XSDebug.exec(io.mem_acquire.fire(), io.mem_acquire.bits.dump)
XSDebug.exec(io.mem_grant.fire(), io.mem_grant.bits.dump)
XSDebug.exec(io.mem_finish.fire(), io.mem_finish.bits.dump)
*/
}
src/main/scala/xiangshan/mem/cache/stu.scala
0 → 100644
浏览文件 @
3cd542e6
package
xiangshan.mem.cache
import
chisel3._
import
chisel3.util._
import
chisel3.util.experimental.BoringUtils
import
xiangshan.mem.
{
DCacheReq
,
DCacheResp
,
LSUDMemIO
}
import
xiangshan.utils.XSDebug
import
bus.tilelink._
import
_root_.utils.
{
Code
,
RandomReplacement
,
Transpose
}
import
xiangshan.mem.MemoryOpConstants
class
StorePipe
extends
DCacheModule
{
val
io
=
IO
(
new
DCacheBundle
{
val
lsu
=
Flipped
(
new
LSUDMemIO
)
val
data_write
=
Output
(
Valid
(
new
L1DataWriteReq
))
val
data_resp
=
Output
(
Vec
(
nWays
,
Vec
(
refillCycles
,
Bits
(
encRowBits
.
W
))))
val
meta_read
=
Decoupled
(
new
L1MetaReadReq
)
val
meta_resp
=
Output
(
Vec
(
nWays
,
rstVal
.
cloneType
))
})
// LSU requests
io
.
lsu
.
req
.
ready
:=
io
.
meta_read
.
ready
io
.
meta_read
.
bits
.
valid
:=
io
.
lsu
.
req
.
valid
val
meta_read
=
io
.
meta_read
.
bits
val
data_read
=
io
.
data_read
.
bits
for
(
w
<-
0
until
memWidth
)
{
// Tag read for new requests
meta_read
.
idx
:=
io
.
lsu
.
req
.
bits
(
w
).
bits
.
addr
>>
blockOffBits
meta_read
.
way_en
:=
~
0.
U
(
nWays
.
W
)
meta_read
.
tag
:=
DontCare
}
// Pipeline
// stage 0
val
s0_valid
=
io
.
lsu
.
req
.
fire
()
val
s0_req
=
io
.
lsu
.
req
.
bits
assert
(!(
s0_valid
&&
s0_req
.
cmd
=/=
MemoryOpConstants
.
M_XWR
),
"StorePipe only accepts store req"
)
dump_pipeline_reqs
(
"StorePipe s0"
,
s0_valid
,
s0_req
,
s0_type
)
// stage 1
val
s1_req
=
RegNext
(
s0_req
)
val
s1_valid
=
RegNext
(
s0_valid
,
init
=
false
.
B
)
val
s1_addr
=
s1_req
.
addr
val
s1_nack
=
false
.
B
dump_pipeline_reqs
(
"StorePipe s1"
,
s1_valid
,
s1_req
,
s1_type
)
// tag check
def
wayMap
[
T
<:
Data
](
f
:
Int
=>
T
)
=
VecInit
((
0
until
nWays
).
map
(
f
))
val
s1_tag_eq_way
=
wayMap
((
w
:
Int
)
=>
meta_resp
(
w
).
tag
===
(
s1_addr
>>
untagBits
)).
asUInt
val
s1_tag_match_way
=
wayMap
((
w
:
Int
)
=>
s1_tag_eq_way
(
i
)(
w
)
&&
meta
(
i
).
io
.
resp
(
w
).
coh
.
isValid
()).
asUInt
// stage 2
val
s2_req
=
RegNext
(
s1_req
)
val
s2_valid
=
RegNext
(
s1_valid
(
w
),
init
=
false
.
B
))
dump_pipeline_reqs
(
"StorePipe s2"
,
s2_valid
,
s2_req
,
s2_type
)
val
s2_tag_match_way
=
RegNext
(
s1_tag_match_way
)
val
s2_tag_match
=
s2_tag_match_way
.
orR
val
s2_hit_state
=
Mux1H
(
s2_tag_match_way
(
i
),
wayMap
((
w
:
Int
)
=>
RegNext
(
meta_resp
(
w
).
coh
)))
val
s2_has_permission
=
s2_hit_state
.
onAccess
(
s2_req
.
cmd
).
_1
val
s2_new_hit_state
=
s2_hit_state
.
onAccess
(
s2_req
.
cmd
).
_3
// we not only need permissions
// we also require that state does not change on hit
// thus we require new_hit_state === old_hit_state
//
// If state changes on hit,
// we should treat it as not hit, and let mshr deal with it,
// since we can not write meta data on the main pipeline.
// It's possible that we had permission but state changes on hit:
// eg: write to exclusive but clean block
val
s2_hit
=
s2_tag_match
&&
s2_has_permission
&&
s2_hit_state
===
s2_new_hit_state
&&
!
mshrs
.
io
.
block_hit
val
s2_nack
=
Wire
(
Bool
())
val
s2_nack_hit
=
RegNext
(
s1_nack
)
// Can't allocate MSHR for same set currently being written back
// the same set is busy
val
s2_nack_set_busy
=
s2_valid
&&
mshrs
.
io
.
block_hit
s2_nack
:=
s2_nack_hit
||
s2_nack_set_busy
// write dcache if hit
io
.
meta_write
.
valid
:=
s2_valid
&&
s2_hit
io
.
meta_write
.
bits
:=
s2_req
dump_pipeline_valids
(
"StorePipe s2"
,
"s2_hit"
,
s2_hit
)
dump_pipeline_valids
(
"StorePipe s2"
,
"s2_nack"
,
s2_nack
)
dump_pipeline_valids
(
"StorePipe s2"
,
"s2_nack_hit"
,
s2_nack_hit
)
dump_pipeline_valids
(
"StorePipe s2"
,
"s2_nack_set_busy"
,
s2_nack_set_busy
)
val
resp
=
Wire
(
Valid
(
new
DCacheResp
))
for
(
w
<-
0
until
memWidth
)
{
resp
.
valid
:=
s2_valid
resp
.
bits
.
data
:=
DontCare
resp
.
bits
.
meta
:=
s2_req
.
meta
resp
.
bits
.
nack
:=
s2_nack
}
io
.
lsu
.
resp
(
w
)
<>
resp
(
w
)
when
(
resp
.
valid
)
{
XSDebug
(
s
"StorePipe resp: meta: %d nack: %b\n"
,
resp
.
meta
,
resp
.
nack
)
}
// -------
// Debug logging functions
def
dump_pipeline_reqs
(
pipeline_stage_name
:
String
,
valid
:
Vec
[
Bool
],
reqs
:
Vec
[
DCacheReq
],
req_type
:
UInt
)
=
{
val
anyValid
=
valid
.
reduce
(
_
||
_
)
when
(
anyValid
)
{
(
0
until
memWidth
)
map
{
w
=>
when
(
valid
(
w
))
{
XSDebug
(
s
"$pipeline_stage_name\n"
)
XSDebug
(
"channel %d: valid: %b \n"
,
w
.
U
,
valid
(
w
))
when
(
req_type
===
t_replay
)
{
XSDebug
(
"req_type: replay "
)
}
.
elsewhen
(
req_type
===
t_lsu
)
{
XSDebug
(
"req_type: lsu "
)
}
.
otherwise
{
XSDebug
(
"req_type: unknown "
)
}
XSDebug
(
"cmd: %x addr: %x data: %x mask: %x meta: %x\n"
,
reqs
(
w
).
cmd
,
reqs
(
w
).
addr
,
reqs
(
w
).
data
,
reqs
(
w
).
mask
,
reqs
(
w
).
meta
)
}
}
}
}
def
dump_pipeline_valids
(
pipeline_stage_name
:
String
,
signal_name
:
String
,
valid
:
Vec
[
Bool
])
=
{
val
anyValid
=
valid
.
reduce
(
_
||
_
)
when
(
anyValid
)
{
(
0
until
memWidth
)
map
{
w
=>
when
(
valid
(
w
))
{
XSDebug
(
s
"$pipeline_stage_name channel %d: $signal_name\n"
,
w
.
U
)
}
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录