Skip to content

Commit

Permalink
Fix memory code order for Wildcat
Browse files Browse the repository at this point in the history
  • Loading branch information
schoeberl committed Jan 28, 2025
1 parent d7c7f02 commit fdb5823
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 47 deletions.
38 changes: 23 additions & 15 deletions chisel-book.tex
Original file line number Diff line number Diff line change
Expand Up @@ -7275,7 +7275,9 @@ \subsection{Instruction Decode and Register File Read}
immediate value is extracted from the instruction. All those values are part of the
decoded output.
Finally, Listing~\ref{lst:wildcat:mem:address} shows the address computation for memory
Listing~\ref{lst:wildcat:mem:address} shows the address computation for memory
load or store instructions. The address (\code{memAdress}) is computed by using the value of
register \code{rs1} and adding the immediate field (\code{dec.Out.imm}).
However, the code is slightly more complicated, as we need to implement forwarding.
Expand All @@ -7289,11 +7291,18 @@ \subsection{Instruction Decode and Register File Read}
\longlist{code/wildcat_mem_address.txt}{Address computation, including forwarding if needed.}{lst:wildcat:mem:address}
Listing~\ref{lst:wildcat:mem} shows the memory access part in decode.
As the input registers of the memory are part of the execution stage, the memory address
and the store operation are computed in the decode stage.
\longlist{code/wildcat_memory.txt}{Memory access in decode.}{lst:wildcat:mem}
\subsection{Execute and Memory Access}
\subsection{Execute and Memory Read}
The third pipeline stage is responsible for either executing either an ALU operation, execute
a control instruction (branch or jump), or perform a memory operation.
a control instruction (branch or jump), or perform a memory load.
Listing~\ref{lst:wildcat:exe} shows part of the execution stage. Depending on the instruction
type, either the value of a register \code{v2} or the immediate value \code{decOut.imm}
is used as the second operand for an ALU instruction. The ALU is defined in a Scala function,
Expand All @@ -7302,15 +7311,16 @@ \subsection{Execute and Memory Access}
\longlist{code/wildcat_execute.txt}{ALU operation in the execution stage.}{lst:wildcat:exe}
Listing~\ref{lst:wildcat:alu} shows part of the function that implements the ALU operations.
For the operation constants, we use a Scala \code{Enumeration}, as shown
We use a Scala \code{Enumeration} to define as ALU operations, as shown
in Listing~\ref{lst:wildcat:alu:enum}. As with the other constants, they are shared between the
ISA simulator and the pipeline implementation. Therefore, they need to be converted
to Chisel constants. The listing is incomplete so as not to consume too much space.
to Chisel constants.
\longlist{code/wildcat_alu_enum.txt}{The ALU operation enumeration.}{lst:wildcat:alu:enum}
Listing~\ref{lst:wildcat:alu} shows the function that implements the ALU operations.
\longlist{code/wildcat_alu.txt}{The ALU function.}{lst:wildcat:alu}
\longlist{code/wildcat_alu_enum.txt}{The ALU operation enumeration.}{lst:wildcat:alu:enum}
Listing~\ref{lst:wildcat:branch} shows the logic for branch execution.
The branch target is computed by adding the immediate value of the branch instruction
Expand All @@ -7321,17 +7331,15 @@ \subsection{Execute and Memory Access}
\longlist{code/wildcat_branch.txt}{Branch execution}{lst:wildcat:branch}
Listing~\ref{lst:wildcat:mem} shows the memory access.
The load operation is performed in the execution stage. The function \code{selectLoadData}
selects depending on the instruction and the lower 2 bits of the address which part of the
read data is used.
As the input registers of the memory are part of the execution stage, the memory address
and the store operation is computed in the decode stage.
The memory read operation is performed in the execution stage.
Listing~\ref{lst:wildcat:mem:read} shows the multiplexer for the load instruction.
The function \code{selectLoadData} selects, depending on the instruction and
the lower 2 bits of the address, which part of the read data is used.
\longlist{code/wildcat_memory_read.txt}{Memory load.}{lst:wildcat:mem:read}
\todo{This should be moved to the decode part, also in the source code.}
\longlist{code/wildcat_memory.txt}{Memory access}{lst:wildcat:mem}
\section{Summary and Exercise}
Expand Down
3 changes: 1 addition & 2 deletions src/main/scala/wildcat/pipeline/Functions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,6 @@ object Functions {
is(SLL.id.U) {
res := a << b(4, 0)
}
// and more cases
//- end
is(SRL.id.U) {
res := a >> b(4, 0)
}
Expand All @@ -259,6 +257,7 @@ object Functions {
}
res
}
//- end

def selectLoadData(data: UInt, func3: UInt, memLow: UInt): UInt = {
val res = Wire(UInt(32.W))
Expand Down
66 changes: 36 additions & 30 deletions src/main/scala/wildcat/pipeline/ThreeCats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import wildcat.pipeline.Functions._
*
* 0. PC generation
* 1. Fetch
* 2. Decode, register read
* 3. Execute, memory access
* 2. Decode, register read, memory address computation and write
* 3. Execute, memory read
*
* Author: Martin Schoeberl ([email protected])
*
Expand All @@ -27,10 +27,18 @@ class ThreeCats() extends Wildcat() {
val doBranch = WireDefault(false.B)
val branchTarget = WireDefault(0.U)

// Forwarding data and register
val exFwd = new Bundle() {
val valid = Bool()
val wbDest = UInt(5.W)
val wbData = UInt(32.W)
}
val exFwdReg = RegInit(0.U.asTypeOf(exFwd))

//- start wildcat_fetch
// PC generation
val pcReg = RegInit(-4.S(32.W).asUInt)
// val pcReg = RegInit(-4.S(32.W).asUInt)
val pcReg = RegInit(0.S(32.W).asUInt)
val pcNext = WireDefault(Mux(doBranch, branchTarget, pcReg + 4.U))
pcReg := pcNext
io.imem.address := pcNext
Expand All @@ -43,7 +51,7 @@ class ThreeCats() extends Wildcat() {
}
//- end

// Decode and register read
// Decode, register read, and memory access
val pcRegReg = RegNext(pcReg)
//- start wildcat_decode
val instrReg = RegInit(0x00000033.U) // nop on reset
Expand Down Expand Up @@ -78,27 +86,35 @@ class ThreeCats() extends Wildcat() {
decEx.rs2Val := rs2Val
decEx.func3 := instrReg(14, 12)

// Execute
val decExReg = RegInit(0.U.asTypeOf(decEx))
decExReg := decEx

// Forwarding register
val exFwd = new Bundle() {
val valid = Bool()
val wbDest = UInt(5.W)
val wbData = UInt(32.W)
}
val exFwdReg = RegInit(0.U.asTypeOf(exFwd))

//- start wildcat_mem_address
// Forwarding to memory
val address = Mux(wrEna && (wbDest =/= 0.U) && wbDest === decEx.rs1, wbData, rs1Val)
val data = Mux(wrEna && (wbDest =/= 0.U) && wbDest === decEx.rs2, wbData, rs2Val)

val memAddress = (address.asSInt + decOut.imm).asUInt
//- end
decEx.memLow := memAddress(1, 0)
//- end

//- start wildcat_memory
io.dmem.rdAddress := memAddress
io.dmem.rdEnable := false.B
io.dmem.wrAddress := memAddress
io.dmem.wrData := data
io.dmem.wrEnable := VecInit(Seq.fill(4)(false.B))
when(decOut.isLoad && !doBranch) {
io.dmem.rdEnable := true.B
}
when(decOut.isStore && !doBranch) {
val (wrd, wre) = getWriteData(data, decEx.func3, memAddress(1, 0))
io.dmem.wrData := wrd
io.dmem.wrEnable := wre
}
//- end


// Execute
val decExReg = RegInit(0.U.asTypeOf(decEx))
decExReg := decEx

// Forwarding
val v1 = Mux(exFwdReg.valid && exFwdReg.wbDest === decExReg.rs1, exFwdReg.wbData, decExReg.rs1Val)
Expand Down Expand Up @@ -131,24 +147,14 @@ class ThreeCats() extends Wildcat() {
//- end
wrEna := decExReg.valid && decExReg.decOut.rfWrite

// Memory access
//- start wildcat_memory
io.dmem.rdAddress := memAddress
io.dmem.rdEnable := false.B
io.dmem.wrAddress := memAddress
io.dmem.wrData := data
io.dmem.wrEnable := VecInit(Seq.fill(4)(false.B))
// Memory read access
//- start wildcat_memory_read
when(decExReg.decOut.isLoad && !doBranch) {
res := selectLoadData(io.dmem.rdData, decExReg.func3, decExReg.memLow)
io.dmem.rdEnable := true.B
}
when(decOut.isStore && !doBranch) {
val (wrd, wre) = getWriteData(data, decEx.func3, memAddress(1, 0))
io.dmem.wrData := wrd
io.dmem.wrEnable := wre
}
//- end


// Forwarding register values to ALU
exFwdReg.valid := wrEna && (wbDest =/= 0.U)
exFwdReg.wbDest := wbDest
Expand Down

0 comments on commit fdb5823

Please sign in to comment.