Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenXiangShan
XiangShan
提交
e46a1488
X
XiangShan
项目概览
OpenXiangShan
/
XiangShan
10 个月 前同步成功
通知
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,体验更适合开发者的 AI 搜索 >>
未验证
提交
e46a1488
编写于
3月 01, 2021
作者:
L
ljw
提交者:
GitHub
3月 01, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Sbuffer: remove old version sbuffer (#617)
上级
8a538cf0
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
9 addition
and
495 deletion
+9
-495
src/main/scala/xiangshan/mem/sbuffer/NewSbuffer.scala
src/main/scala/xiangshan/mem/sbuffer/NewSbuffer.scala
+9
-7
src/main/scala/xiangshan/mem/sbuffer/Sbuffer.scala
src/main/scala/xiangshan/mem/sbuffer/Sbuffer.scala
+0
-488
未找到文件。
src/main/scala/xiangshan/mem/sbuffer/NewSbuffer.scala
浏览文件 @
e46a1488
...
...
@@ -6,7 +6,12 @@ import xiangshan._
import
utils._
import
xiangshan.cache._
trait
HasSbufferCst
extends
HasXSParameter
{
class
SbufferFlushBundle
extends
Bundle
{
val
valid
=
Output
(
Bool
())
val
empty
=
Input
(
Bool
())
}
trait
HasSbufferConst
extends
HasXSParameter
{
// use 1h to speedup selection
def
s_invalid
=
(
1
<<
0
).
U
(
4.
W
)
...
...
@@ -32,7 +37,7 @@ trait HasSbufferCst extends HasXSParameter {
val
TagWidth
:
Int
=
PAddrBits
-
OffsetWidth
}
class
SbufferBundle
extends
XSBundle
with
HasSbufferCst
class
SbufferBundle
extends
XSBundle
with
HasSbufferC
on
st
class
SbufferLine
extends
SbufferBundle
{
val
tag
=
UInt
(
TagWidth
.
W
)
...
...
@@ -109,16 +114,13 @@ class SbufferLru(nWay: Int) extends XSModule {
class
NewSbuffer
extends
XSModule
with
HasSbufferCst
{
class
NewSbuffer
extends
XSModule
with
HasSbufferC
on
st
{
val
io
=
IO
(
new
Bundle
()
{
val
in
=
Vec
(
StorePipelineWidth
,
Flipped
(
Decoupled
(
new
DCacheWordReq
)))
//Todo: store logic only support Width == 2 now
val
dcache
=
new
DCacheLineIO
val
forward
=
Vec
(
LoadPipelineWidth
,
Flipped
(
new
LoadForwardQueryIO
))
val
sqempty
=
Input
(
Bool
())
val
flush
=
new
Bundle
{
val
valid
=
Input
(
Bool
())
val
empty
=
Output
(
Bool
())
}
// sbuffer flush
val
flush
=
Flipped
(
new
SbufferFlushBundle
)
})
val
difftestIO
=
IO
(
new
Bundle
()
{
val
sbufferResp
=
Output
(
Bool
())
...
...
src/main/scala/xiangshan/mem/sbuffer/Sbuffer.scala
已删除
100644 → 0
浏览文件 @
8a538cf0
package
xiangshan.mem
import
chisel3._
import
chisel3.util._
import
xiangshan._
import
utils._
import
xiangshan.cache._
import
utils.ParallelAND
import
utils.TrueLRU
class
SbufferUserBundle
extends
XSBundle
{
val
pc
=
UInt
(
VAddrBits
.
W
)
//for debug
}
trait
HasSBufferConst
extends
HasXSParameter
{
val
sBufferIndexWidth
:
Int
=
log2Up
(
StoreBufferSize
)
// a.k.a. index of cache line
// paddr = tag + offset
val
tagWidth
:
Int
=
PAddrBits
-
log2Up
(
CacheLineSize
/
8
)
val
offsetWidth
:
Int
=
log2Up
(
CacheLineSize
/
8
)
val
cacheMaskWidth
:
Int
=
CacheLineSize
/
8
val
instMaskWidth
:
Int
=
XLEN
/
8
}
class
SBufferCacheLine
extends
XSBundle
with
HasSBufferConst
{
val
valid
=
Bool
()
val
tag
=
UInt
(
tagWidth
.
W
)
val
data
=
Vec
(
cacheMaskWidth
,
UInt
(
8.
W
))
// UInt(CacheLineSize.W)
val
mask
=
Vec
(
cacheMaskWidth
,
Bool
())
}
class
UpdateInfo
extends
XSBundle
with
HasSBufferConst
{
val
idx
:
UInt
=
UInt
(
sBufferIndexWidth
.
W
)
// cache index effected by this store req
val
newTag
:
UInt
=
UInt
(
tagWidth
.
W
)
val
newMask
:
Vec
[
Bool
]
=
Vec
(
cacheMaskWidth
,
Bool
())
val
newData
:
Vec
[
UInt
]
=
Vec
(
cacheMaskWidth
,
UInt
(
8.
W
))
val
isForward
:
Bool
=
Bool
()
// this req has same tag as some former req
val
isUpdated
:
Bool
=
Bool
()
val
isInserted
:
Bool
=
Bool
()
val
isIgnored
:
Bool
=
Bool
()
}
class
SbufferFlushBundle
extends
Bundle
{
val
valid
=
Output
(
Bool
())
val
empty
=
Input
(
Bool
())
}
// Store buffer for XiangShan Out of Order LSU
class
Sbuffer
extends
XSModule
with
HasSBufferConst
{
val
io
=
IO
(
new
Bundle
()
{
val
in
=
Vec
(
StorePipelineWidth
,
Flipped
(
Decoupled
(
new
DCacheWordReq
)))
val
dcache
=
new
DCacheLineIO
val
forward
=
Vec
(
LoadPipelineWidth
,
Flipped
(
new
LoadForwardQueryIO
))
val
flush
=
new
Bundle
{
val
valid
=
Input
(
Bool
())
val
empty
=
Output
(
Bool
())
}
// sbuffer flush
})
val
cache
:
Vec
[
SBufferCacheLine
]
=
RegInit
(
VecInit
(
Seq
.
fill
(
StoreBufferSize
)(
0.
U
.
asTypeOf
(
new
SBufferCacheLine
))))
val
updateInfo
=
WireInit
(
VecInit
(
Seq
.
fill
(
StorePipelineWidth
)(
0.
U
.
asTypeOf
(
new
UpdateInfo
))))
updateInfo
:=
DontCare
val
lru
=
new
TrueLRU
(
StoreBufferSize
)
def
getTag
(
pa
:
UInt
)
:
UInt
=
pa
(
PAddrBits
-
1
,
PAddrBits
-
tagWidth
)
def
getAddr
(
tag
:
UInt
)
:
UInt
=
Cat
(
tag
,
0.
U
((
PAddrBits
-
tagWidth
).
W
))
def
getByteOffset
(
pa
:
UInt
)
:
UInt
=
Cat
(
pa
(
offsetWidth
-
1
,
log2Up
(
8
)),
Fill
(
3
,
0.
U
))
// check if cacheIdx is modified by former request in this cycle
def
busy
(
cacheIdx
:
UInt
,
max
:
Int
)
:
Bool
=
{
if
(
max
==
0
)
false
.
B
else
ParallelOR
((
0
until
max
).
map
(
i
=>
updateInfo
(
i
).
idx
===
cacheIdx
&&
io
.
in
(
i
).
valid
)).
asBool
()
}
val
lru_accessed
=
WireInit
(
VecInit
(
Seq
.
fill
(
StorePipelineWidth
)(
false
.
B
)))
// Get retired store from lsq
//--------------------------------------------------------------------------------------------------------------------
for
(
storeIdx
<-
0
until
StorePipelineWidth
)
{
io
.
in
(
storeIdx
).
ready
:=
false
.
B
// when there is empty line or target address already in this buffer, assert true
// otherwise, assert false
// when d-cache write port is valid, write back the oldest line to d-cache
updateInfo
(
storeIdx
).
isForward
:=
false
.
B
updateInfo
(
storeIdx
).
isUpdated
:=
false
.
B
updateInfo
(
storeIdx
).
isInserted
:=
false
.
B
updateInfo
(
storeIdx
).
isIgnored
:=
false
.
B
// 0. compare with former requests
for
(
formerIdx
<-
0
until
storeIdx
)
{
// i: former request
when
((
getTag
(
io
.
in
(
storeIdx
).
bits
.
addr
)
===
updateInfo
(
formerIdx
).
newTag
)
&&
(
updateInfo
(
formerIdx
).
isUpdated
||
updateInfo
(
formerIdx
).
isInserted
)
&&
io
.
in
(
storeIdx
).
valid
&&
io
.
in
(
formerIdx
).
valid
)
{
updateInfo
(
storeIdx
).
isForward
:=
true
.
B
updateInfo
(
formerIdx
).
isIgnored
:=
true
.
B
updateInfo
(
storeIdx
).
idx
:=
updateInfo
(
formerIdx
).
idx
XSDebug
(
"req#%d writes same line with req#%d\n"
,
storeIdx
.
U
,
formerIdx
.
U
)
updateInfo
(
storeIdx
).
isInserted
:=
updateInfo
(
formerIdx
).
isInserted
updateInfo
(
storeIdx
).
isUpdated
:=
updateInfo
(
formerIdx
).
isUpdated
updateInfo
(
storeIdx
).
newTag
:=
updateInfo
(
formerIdx
).
newTag
// update mask and data
(
0
until
cacheMaskWidth
).
foreach
(
i
=>
{
when
(
i
.
U
<
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
).
asUInt
()
||
i
.
U
>
(
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
)
|
7.
U
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
updateInfo
(
formerIdx
).
newMask
(
i
)
updateInfo
(
storeIdx
).
newData
(
i
)
:=
updateInfo
(
formerIdx
).
newData
(
i
)
}
otherwise
{
when
(
io
.
in
(
storeIdx
).
bits
.
mask
.
asBools
()(
i
%
8
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
true
.
B
updateInfo
(
storeIdx
).
newData
(
i
)
:=
io
.
in
(
storeIdx
).
bits
.
data
(
8
*
(
i
%
8
+
1
)
-
1
,
8
*
(
i
%
8
))
}
.
otherwise
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
updateInfo
(
formerIdx
).
newMask
(
i
)
updateInfo
(
storeIdx
).
newData
(
i
)
:=
updateInfo
(
formerIdx
).
newData
(
i
)
}
}
})
}
}
// 1. search for existing lines
for
(
bufIdx
<-
0
until
StoreBufferSize
)
{
when
(!
updateInfo
(
storeIdx
).
isForward
&&
(
getTag
(
io
.
in
(
storeIdx
).
bits
.
addr
)
===
cache
(
bufIdx
).
tag
)
&&
cache
(
bufIdx
).
valid
&&
io
.
in
(
storeIdx
).
valid
)
{
// mark this line as UPDATE
updateInfo
(
storeIdx
).
isUpdated
:=
true
.
B
updateInfo
(
storeIdx
).
idx
:=
bufIdx
.
U
updateInfo
(
storeIdx
).
newTag
:=
getTag
(
io
.
in
(
storeIdx
).
bits
.
addr
)
// update mask and data
(
0
until
cacheMaskWidth
).
foreach
(
i
=>
{
when
(
i
.
U
<
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
).
asUInt
()
||
i
.
U
>
(
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
)
|
7.
U
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
cache
(
bufIdx
).
mask
(
i
)
updateInfo
(
storeIdx
).
newData
(
i
)
:=
cache
(
bufIdx
).
data
(
i
)
}
otherwise
{
when
(
io
.
in
(
storeIdx
).
bits
.
mask
.
asBools
()(
i
%
8
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
true
.
B
updateInfo
(
storeIdx
).
newData
(
i
)
:=
io
.
in
(
storeIdx
).
bits
.
data
(
8
*
(
i
%
8
+
1
)
-
1
,
8
*
(
i
%
8
))
}
.
otherwise
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
cache
(
bufIdx
).
mask
(
i
)
updateInfo
(
storeIdx
).
newData
(
i
)
:=
cache
(
bufIdx
).
data
(
i
)
}
}
})
}
}
// 2. not found target address in existing lines, try to insert a new line
val
freeVec
=
WireInit
(
VecInit
((
0
until
StoreBufferSize
).
map
(
i
=>
cache
(
i
).
valid
||
busy
(
i
.
U
,
storeIdx
))))
val
hasFree
=
!
ParallelAND
(
freeVec
)
val
nextFree
=
PriorityEncoder
(
freeVec
.
map
(
i
=>
!
i
))
// XSInfo("hasFree: %d, nextFreeIdx: %d\n", hasFree, nextFree)
when
(!
updateInfo
(
storeIdx
).
isForward
&&
!
updateInfo
(
storeIdx
).
isUpdated
&&
hasFree
&&
io
.
in
(
storeIdx
).
valid
)
{
updateInfo
(
storeIdx
).
isInserted
:=
true
.
B
updateInfo
(
storeIdx
).
idx
:=
nextFree
updateInfo
(
storeIdx
).
newTag
:=
getTag
(
io
.
in
(
storeIdx
).
bits
.
addr
)
// set mask and data
(
0
until
cacheMaskWidth
).
foreach
(
i
=>
{
when
(
i
.
U
<
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
).
asUInt
()
||
i
.
U
>
(
getByteOffset
(
io
.
in
(
storeIdx
).
bits
.
addr
)
|
7.
U
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
false
.
B
updateInfo
(
storeIdx
).
newData
(
i
)
:=
0.
U
}
otherwise
{
when
(
io
.
in
(
storeIdx
).
bits
.
mask
.
asBools
()(
i
%
8
))
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
true
.
B
updateInfo
(
storeIdx
).
newData
(
i
)
:=
io
.
in
(
storeIdx
).
bits
.
data
(
8
*
(
i
%
8
+
1
)
-
1
,
8
*
(
i
%
8
))
// XSInfo("[%d] write data %x\n", i.U, io.in(storeIdx).bits.data(8 * (i % 8 + 1) - 1, 8 * (i % 8)))
}
.
otherwise
{
updateInfo
(
storeIdx
).
newMask
(
i
)
:=
false
.
B
updateInfo
(
storeIdx
).
newData
(
i
)
:=
0.
U
}
}
})
}
// 3. not enough space for this query
when
(!
updateInfo
(
storeIdx
).
isForward
&&
!
updateInfo
(
storeIdx
).
isUpdated
&&
!
updateInfo
(
storeIdx
).
isInserted
)
{
updateInfo
(
storeIdx
).
isIgnored
:=
true
.
B
}
XSInfo
(
updateInfo
(
storeIdx
).
isUpdated
&&
updateInfo
(
storeIdx
).
isInserted
,
"Error: one line is both updated and inserted!\n"
)
if
(
storeIdx
>
0
)
io
.
in
(
storeIdx
).
ready
:=
io
.
in
(
storeIdx
-
1
).
ready
&&
(
updateInfo
(
storeIdx
).
isUpdated
||
updateInfo
(
storeIdx
).
isInserted
)
else
io
.
in
(
storeIdx
).
ready
:=
updateInfo
(
storeIdx
).
isUpdated
||
updateInfo
(
storeIdx
).
isInserted
when
(
io
.
in
(
storeIdx
).
fire
()){
when
(
updateInfo
(
storeIdx
).
isIgnored
)
{
XSInfo
(
"Ignore req#%d with paddr %x, mask %x, data %x\n"
,
storeIdx
.
U
,
io
.
in
(
storeIdx
).
bits
.
addr
,
io
.
in
(
storeIdx
).
bits
.
mask
,
io
.
in
(
storeIdx
).
bits
.
data
)
// Update
// ----------------------------------------
}
.
elsewhen
(
updateInfo
(
storeIdx
).
isUpdated
)
{
// clear lruCnt
// cache(updateInfo(storeIdx).idx).lruCnt := 0.U
lru
.
access
(
updateInfo
(
storeIdx
).
idx
)
lru_accessed
(
storeIdx
)
:=
true
.
B
// update mask and data
// cache(updateInfo(storeIdx).idx).data := updateInfo(storeIdx).newData
cache
(
updateInfo
(
storeIdx
).
idx
).
data
.
zipWithIndex
.
foreach
{
case
(
int
,
i
)
=>
int
:=
updateInfo
(
storeIdx
).
newData
(
i
)
}
// cache(updateInfo(storeIdx).idx).mask := updateInfo(storeIdx).newMask
cache
(
updateInfo
(
storeIdx
).
idx
).
mask
.
zipWithIndex
.
foreach
{
case
(
int
,
i
)
=>
int
:=
updateInfo
(
storeIdx
).
newMask
(
i
)
}
XSInfo
(
"Update line#%d with tag %x, mask %x, data %x\n"
,
updateInfo
(
storeIdx
).
idx
,
cache
(
updateInfo
(
storeIdx
).
idx
).
tag
,
io
.
in
(
storeIdx
).
bits
.
mask
,
io
.
in
(
storeIdx
).
bits
.
data
)
// Insert
// ----------------------------------------
}
.
elsewhen
(
updateInfo
(
storeIdx
).
isInserted
)
{
// clear lruCnt
// cache(updateInfo(storeIdx).idx).lruCnt := 0.U
lru
.
access
(
updateInfo
(
storeIdx
).
idx
)
lru_accessed
(
storeIdx
)
:=
true
.
B
// set valid
cache
(
updateInfo
(
storeIdx
).
idx
).
valid
:=
true
.
B
// set tag
cache
(
updateInfo
(
storeIdx
).
idx
).
tag
:=
updateInfo
(
storeIdx
).
newTag
// update mask and data
// cache(updateInfo(storeIdx).idx).data := updateInfo(storeIdx).newData
// cache(updateInfo(storeIdx).idx).mask := updateInfo(storeIdx).newMask
cache
(
updateInfo
(
storeIdx
).
idx
).
data
.
zipWithIndex
.
foreach
{
case
(
int
,
i
)
=>
int
:=
updateInfo
(
storeIdx
).
newData
(
i
)
}
cache
(
updateInfo
(
storeIdx
).
idx
).
mask
.
zipWithIndex
.
foreach
{
case
(
int
,
i
)
=>
int
:=
updateInfo
(
storeIdx
).
newMask
(
i
)
}
XSInfo
(
"Insert into line#%d with tag %x, mask: %x, data: %x, pa: %x\n"
,
updateInfo
(
storeIdx
).
idx
,
getTag
(
io
.
in
(
storeIdx
).
bits
.
addr
),
io
.
in
(
storeIdx
).
bits
.
mask
,
io
.
in
(
storeIdx
).
bits
.
data
,
io
.
in
(
storeIdx
).
bits
.
addr
)
}
// ignore UNCHANGED & EVICTED state
}
}
// Write back to d-cache
//--------------------------------------------------------------------------------------------------------------------
val
WriteBackPortCount
=
2
val
FlushPort
=
0
// flush has higher priority
val
EvictionPort
=
1
val
wb_arb
=
Module
(
new
Arbiter
(
UInt
(),
WriteBackPortCount
))
val
wb_resp
=
WireInit
(
false
.
B
)
val
waitingCacheLine
:
SBufferCacheLine
=
RegInit
(
0.
U
.
asTypeOf
(
new
SBufferCacheLine
))
// LRU eviction
//-------------------------------------------------
val
validCnt
:
UInt
=
Wire
(
UInt
((
sBufferIndexWidth
+
1
).
W
))
validCnt
:=
PopCount
((
0
until
StoreBufferSize
).
map
(
i
=>
cache
(
i
).
valid
))
XSInfo
(
"[ %d ] lines valid this cycle\n"
,
validCnt
)
val
oldestLineIdx
:
UInt
=
Wire
(
UInt
(
sBufferIndexWidth
.
W
))
oldestLineIdx
:=
lru
.
way
XSInfo
(
"Least recently used #[ %d ] line\n"
,
oldestLineIdx
)
// eviction state machine
val
e_wb_req
::
e_wb_resp
::
Nil
=
Enum
(
2
)
val
eviction_state
=
RegInit
(
e_wb_req
)
wb_arb
.
io
.
in
(
EvictionPort
).
valid
:=
false
.
B
wb_arb
.
io
.
in
(
EvictionPort
).
bits
:=
DontCare
when
(
eviction_state
===
e_wb_req
)
{
wb_arb
.
io
.
in
(
EvictionPort
).
valid
:=
validCnt
===
StoreBufferSize
.
U
&&
!
waitingCacheLine
.
valid
wb_arb
.
io
.
in
(
EvictionPort
).
bits
:=
oldestLineIdx
when
(
wb_arb
.
io
.
in
(
EvictionPort
).
fire
())
{
eviction_state
:=
e_wb_resp
}
}
val
lru_miss
=
WireInit
(
false
.
B
)
when
(
eviction_state
===
e_wb_resp
)
{
when
(
wb_resp
)
{
lru
.
miss
lru_miss
:=
true
.
B
eviction_state
:=
e_wb_req
}
}
// Sbuffer flush
//-------------------------------------------------
// flush state machine
val
f_idle
::
f_req
::
f_wait_resp
::
Nil
=
Enum
(
3
)
val
f_state
=
RegInit
(
f_idle
)
val
flush
=
io
.
flush
// empty means there are no valid cache line in sbuffer
// but there may exist cache line being flushed to dcache and not finished
val
empty
=
validCnt
===
0.
U
// sbuffer is flushed empty only when:
// 1. there no valid line in sbuffer and
// 2. cache line waiting to be flushed are flushed out
flush
.
empty
:=
empty
&&
!
waitingCacheLine
.
valid
wb_arb
.
io
.
in
(
FlushPort
).
valid
:=
f_state
===
f_req
wb_arb
.
io
.
in
(
FlushPort
).
bits
:=
PriorityEncoder
((
0
until
StoreBufferSize
).
map
(
i
=>
cache
(
i
).
valid
))
// we only expect flush signal in f_idle state
assert
(!(
flush
.
valid
&&
f_state
=/=
f_idle
))
switch
(
f_state
)
{
is
(
f_idle
)
{
when
(
flush
.
valid
&&
!
empty
)
{
f_state
:=
f_req
}
}
is
(
f_req
)
{
assert
(!
empty
,
"when flush, should not be empty"
)
when
(
wb_arb
.
io
.
in
(
FlushPort
).
fire
())
{
f_state
:=
f_wait_resp
}
}
is
(
f_wait_resp
)
{
when
(
wb_resp
)
{
when
(
empty
)
{
f_state
:=
f_idle
}
.
otherwise
{
f_state
:=
f_req
}
}
}
}
XSDebug
(
flush
.
valid
,
p
"Reveive flush. f_state:${f_state}\n"
)
XSDebug
(
f_state
=/=
f_idle
||
flush
.
valid
,
p
"f_state:${f_state} idx:${wb_arb.io.in(FlushPort).bits} In(${wb_arb.io.in(FlushPort).valid} ${wb_arb.io.in(FlushPort).ready}) wb_resp:${wb_resp}\n"
)
// write back unit
// ---------------------------------------------------------------
val
s_invalid
::
s_dcache_req
::
s_dcache_resp
::
Nil
=
Enum
(
3
)
val
state
=
RegInit
(
s_invalid
)
val
wb_idx
=
Reg
(
UInt
())
val
dcacheData
=
Wire
(
UInt
(
io
.
dcache
.
req
.
bits
.
data
.
getWidth
.
W
))
val
dcacheMask
=
Wire
(
UInt
(
io
.
dcache
.
req
.
bits
.
mask
.
getWidth
.
W
))
dcacheData
:=
DontCare
dcacheMask
:=
DontCare
io
.
dcache
.
req
.
valid
:=
false
.
B
//needWriteToCache
io
.
dcache
.
req
.
bits
.
addr
:=
DontCare
io
.
dcache
.
req
.
bits
.
data
:=
dcacheData
io
.
dcache
.
req
.
bits
.
mask
:=
dcacheMask
io
.
dcache
.
req
.
bits
.
cmd
:=
MemoryOpConstants
.
M_XWR
io
.
dcache
.
req
.
bits
.
id
:=
DontCare
// NOT USED
io
.
dcache
.
resp
.
ready
:=
false
.
B
wb_arb
.
io
.
out
.
ready
:=
false
.
B
// wbu state machine
when
(
state
===
s_invalid
)
{
wb_arb
.
io
.
out
.
ready
:=
true
.
B
when
(
wb_arb
.
io
.
out
.
fire
())
{
assert
(
cache
(
wb_arb
.
io
.
out
.
bits
).
valid
)
wb_idx
:=
wb_arb
.
io
.
out
.
bits
state
:=
s_dcache_req
}
}
when
(
state
===
s_dcache_req
)
{
// assert valid and send data + mask + addr(ends with 000b) to d-cache
io
.
dcache
.
req
.
valid
:=
true
.
B
io
.
dcache
.
req
.
bits
.
addr
:=
getAddr
(
cache
(
wb_idx
).
tag
)
// prepare write data and write mask
// first, we get data from cache
dcacheData
:=
cache
(
wb_idx
).
data
.
asUInt
()
dcacheMask
:=
cache
(
wb_idx
).
mask
.
asUInt
()
// then, we tried to merge any updates
for
(
i
<-
0
until
StorePipelineWidth
)
{
// get data from updateInfo
when
(
updateInfo
(
i
).
idx
===
wb_idx
&&
updateInfo
(
i
).
isUpdated
&&
io
.
in
(
i
).
valid
)
{
dcacheData
:=
updateInfo
(
i
).
newData
.
asUInt
()
dcacheMask
:=
updateInfo
(
i
).
newMask
.
asUInt
()
}
}
when
(
io
.
dcache
.
req
.
fire
())
{
// save current req
waitingCacheLine
:=
cache
(
wb_idx
)
waitingCacheLine
.
data
:=
dcacheData
.
asTypeOf
(
Vec
(
cacheMaskWidth
,
UInt
(
8.
W
)))
waitingCacheLine
.
mask
:=
dcacheMask
.
asTypeOf
(
Vec
(
cacheMaskWidth
,
Bool
()))
waitingCacheLine
.
valid
:=
true
.
B
cache
(
wb_idx
).
valid
:=
false
.
B
state
:=
s_dcache_resp
assert
(
cache
(
wb_idx
).
valid
,
"sbuffer cache line not valid\n"
)
XSInfo
(
"send req to dcache %x\n"
,
wb_idx
)
XSDebug
(
"[New D-Cache Req] idx: %d, addr: %x, mask: %x, data: %x\n"
,
wb_idx
,
io
.
dcache
.
req
.
bits
.
addr
,
dcacheMask
.
asUInt
(),
dcacheData
.
asUInt
())
}
}
when
(
state
===
s_dcache_resp
)
{
io
.
dcache
.
resp
.
ready
:=
true
.
B
when
(
io
.
dcache
.
resp
.
fire
())
{
waitingCacheLine
.
valid
:=
false
.
B
wb_resp
:=
true
.
B
state
:=
s_invalid
XSInfo
(
"recv resp from dcache. wb tag %x mask %x data %x\n"
,
waitingCacheLine
.
tag
,
waitingCacheLine
.
mask
.
asUInt
(),
waitingCacheLine
.
data
.
asUInt
())
}
// the inflight req
XSDebug
(
"[Pending Write Back] tag: %x, mask: %x, data: %x\n"
,
waitingCacheLine
.
tag
,
waitingCacheLine
.
mask
.
asUInt
(),
waitingCacheLine
.
data
.
asUInt
())
}
// loadForwardQuery
//--------------------------------------------------------------------------------------------------------------------
(
0
until
LoadPipelineWidth
).
map
(
loadIdx
=>
{
io
.
forward
(
loadIdx
).
forwardMask
:=
VecInit
(
List
.
fill
(
instMaskWidth
)(
false
.
B
))
io
.
forward
(
loadIdx
).
forwardData
:=
DontCare
when
(
getTag
(
io
.
forward
(
loadIdx
).
paddr
)
===
waitingCacheLine
.
tag
&&
waitingCacheLine
.
valid
)
{
(
0
until
XLEN
/
8
).
foreach
(
i
=>
{
when
(
waitingCacheLine
.
mask
(
i
.
U
+
getByteOffset
(
io
.
forward
(
loadIdx
).
paddr
))
&&
io
.
forward
(
loadIdx
).
mask
(
i
))
{
io
.
forward
(
loadIdx
).
forwardData
(
i
)
:=
waitingCacheLine
.
data
(
i
.
U
+
getByteOffset
(
io
.
forward
(
loadIdx
).
paddr
))
io
.
forward
(
loadIdx
).
forwardMask
(
i
)
:=
true
.
B
}
})
}
// data in StoreBuffer should have higer priority than waitingCacheLine
for
(
sBufIdx
<-
0
until
StoreBufferSize
)
{
when
(
getTag
(
io
.
forward
(
loadIdx
).
paddr
)
===
cache
(
sBufIdx
).
tag
&&
cache
(
sBufIdx
).
valid
)
{
// send data with mask in this line
// this mask is not 'mask for cache line' and we need to check low bits of paddr
// to get certain part of one line
// P.S. data in io.in will be manipulated by lsq
(
0
until
XLEN
/
8
).
foreach
(
i
=>
{
when
(
cache
(
sBufIdx
).
mask
(
i
.
U
+
getByteOffset
(
io
.
forward
(
loadIdx
).
paddr
))
&&
io
.
forward
(
loadIdx
).
mask
(
i
))
{
io
.
forward
(
loadIdx
).
forwardData
(
i
)
:=
cache
(
sBufIdx
).
data
(
i
.
U
+
getByteOffset
(
io
.
forward
(
loadIdx
).
paddr
))
io
.
forward
(
loadIdx
).
forwardMask
(
i
)
:=
true
.
B
}
})
when
(
io
.
forward
(
loadIdx
).
valid
)
{
XSDebug
(
"[ForwardReq] paddr: %x mask: %x pc: %x\n"
,
io
.
forward
(
loadIdx
).
paddr
,
io
.
forward
(
loadIdx
).
mask
,
io
.
forward
(
loadIdx
).
pc
)
XSDebug
(
"[Forwarding] forward-data: %x forward-mask: %x\n"
,
io
.
forward
(
loadIdx
).
forwardData
.
asUInt
(),
io
.
forward
(
loadIdx
).
forwardMask
.
asUInt
())
}
}
}
})
// additional logs
XSInfo
(
io
.
in
(
0
).
fire
(),
"ensbuffer addr 0x%x wdata 0x%x\n"
,
io
.
in
(
0
).
bits
.
addr
,
io
.
in
(
0
).
bits
.
data
)
XSInfo
(
io
.
in
(
1
).
fire
(),
"ensbuffer addr 0x%x wdata 0x%x\n"
,
io
.
in
(
1
).
bits
.
addr
,
io
.
in
(
1
).
bits
.
data
)
XSInfo
(
io
.
dcache
.
req
.
fire
(),
"desbuffer addr 0x%x wdata 0x%x\n"
,
io
.
dcache
.
req
.
bits
.
addr
,
io
.
dcache
.
req
.
bits
.
data
)
// output cache line
cache
.
zipWithIndex
.
foreach
{
case
(
line
,
i
)
=>
{
XSDebug
(
line
.
valid
,
"[#%d line] Tag: %x, data: %x, mask: %x\n"
,
i
.
U
,
line
.
tag
,
line
.
data
.
asUInt
(),
line
.
mask
.
asUInt
())
}}
XSPerf
(
"waitResp"
,
waitingCacheLine
.
valid
)
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录