Skip to content

Commit 2fe6516

Browse files
committed
Move memories and UART to SOC. Misc changes
1 parent 66d4f7f commit 2fe6516

10 files changed

+151
-85
lines changed

GTKWave/gtkwave.tcl

+34-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,38 @@ set instructions [ gtkwave::setCurrentTranslateFile ./GTKWave/instruction_map.tx
2020
set insts [list "_inst"]
2121
set registers [ gtkwave::setCurrentTranslateFile ./GTKWave/registers.txt ]
2222
set regs [list "_rd" "_rs1" "_rs2"]
23+
array set reg_names [list {0[31:0]} {x0(Zero)} \
24+
{1[31:0]} {x1(RA)} \
25+
{2[31:0]} {x2(SP)} \
26+
{3[31:0]} {x3(GP)} \
27+
{4[31:0]} {x4(TP)} \
28+
{5[31:0]} {x5(t0)} \
29+
{6[31:0]} {x6(t1)} \
30+
{7[31:0]} {x7(t2)} \
31+
{8[31:0]} {x8-(s0/fp)} \
32+
{9[31:0]} {x9(s1)} \
33+
{10[31:0]} {x10(a0)} \
34+
{11[31:0]} {x11(a1)} \
35+
{12[31:0]} {x12(a2)} \
36+
{13[31:0]} {x13(a3)} \
37+
{14[31:0]} {x14(a4)} \
38+
{15[31:0]} {x15(a5)} \
39+
{16[31:0]} {x16(a6)} \
40+
{17[31:0]} {x17(a7)} \
41+
{18[31:0]} {x18(s2)} \
42+
{19[31:0]} {x19(s3)} \
43+
{20[31:0]} {x20(s4)} \
44+
{21[31:0]} {x21(s5)} \
45+
{22[31:0]} {x22(s6)} \
46+
{23[31:0]} {x23(s7)} \
47+
{24[31:0]} {x24(s8)} \
48+
{25[31:0]} {x25(s9)} \
49+
{26[31:0]} {x26(s10)} \
50+
{27[31:0]} {x27(s11)} \
51+
{28[31:0]} {x28(t3)} \
52+
{29[31:0]} {x29(t4)} \
53+
{30[31:0]} {x30(t5)} \
54+
{31[31:0]} {x31(t6)} ]
2355

2456
################################################################################
2557
# Don't touch from here down
@@ -63,6 +95,7 @@ proc add_signals { filter color filterOut} {
6395
global nsigs
6496
global instructions
6597
global registers
98+
global reg_names
6699
global regs
67100
global insts
68101

@@ -101,7 +134,7 @@ proc add_signals { filter color filterOut} {
101134
if {[string first regs_ $v] != -1} {
102135
set name [string range [lsearch -inline [split $v .] {regs_*}] 5 end]
103136
gtkwave::highlightSignalsFromList "$v"
104-
gtkwave::/Edit/Alias_Highlighted_Trace x$name
137+
gtkwave::/Edit/Alias_Highlighted_Trace $reg_names($name)
105138
gtkwave::/Edit/UnHighlight_All
106139

107140
}

src/main/scala/CPUSingleCycle.scala

+16-37
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ class CPUSingleCycle(
1111
bitWidth: Int = 32,
1212
instructionMemorySize: Int = 1 * 1024,
1313
dataMemorySize: Int = 1 * 1024,
14-
memoryFile: String = "",
15-
ramFile: String = "",
1614
numGPIO: Int = 8,
1715
) extends Module {
1816
val io = IO(new Bundle {
19-
val led0 = Output(Bool()) // LED 0 is the heartbeat
20-
val GPIO0External = Analog(numGPIO.W) // GPIO external port
21-
val UART0SerialPort = new UARTSerialPort() // UART0 serial port
17+
val GPIO0External = Analog(numGPIO.W) // GPIO external port
18+
19+
val UART0Port = Flipped(new UARTPort()) // UART0 data port
20+
val instructionMemPort = Flipped(new InstructionMemPort(bitWidth, instructionMemorySize))
21+
val dataMemPort = Flipped(new MemoryPortDual(bitWidth, dataMemorySize))
2222
})
2323

2424
val stall = WireDefault(false.B)
@@ -49,32 +49,13 @@ class CPUSingleCycle(
4949
val decoder = Module(new Decoder(bitWidth))
5050
decoder.io.DecoderPort.op := 0.U
5151

52-
// Instantiate and initialize the Instruction memory
53-
val instructionMemory = Module(new InstructionMemory(bitWidth, instructionMemorySize, memoryFile))
54-
instructionMemory.io.memPort.readAddr := 0.U
55-
56-
// Instantiate and initialize the Data memory
57-
val dataMemory = Module(new DualPortRAM(bitWidth, dataMemorySize, ramFile))
58-
dataMemory.io.dualPort.writeEnable := false.B
59-
dataMemory.io.dualPort.writeData := 0.U
60-
dataMemory.io.dualPort.readAddress := 0.U
61-
dataMemory.io.dualPort.writeAddress := 0.U
62-
dataMemory.io.dualPort.dataSize := 0.U
63-
dataMemory.io.dualPort.writeMask := 0.U
64-
6552
// Instantiate and connect GPIO
6653
val GPIO0 = Module(new GPIO(bitWidth, numGPIO))
6754
GPIO0.io.externalPort <> io.GPIO0External
6855

6956
// Instantiate and connect the Timer
7057
val timer0 = Module(new Timer(bitWidth, cpuFrequency))
7158

72-
// Instantiate and connect the UART
73-
val fifoLength = 128
74-
val rxOverclock = 16
75-
val UART0 = Module(new Uart(fifoLength, rxOverclock))
76-
UART0.io.serialPort <> io.UART0SerialPort
77-
7859
// Instantiate and initialize the Memory IO Manager
7960
val memoryIOManager = Module(new MemoryIOManager(bitWidth, cpuFrequency, dataMemorySize))
8061
memoryIOManager.io.MemoryIOPort.readRequest := false.B
@@ -86,10 +67,10 @@ class CPUSingleCycle(
8667
memoryIOManager.io.MemoryIOPort.writeMask := 0.U
8768

8869
// Connect MMIO to the devices
89-
memoryIOManager.io.DataMemPort <> dataMemory.io.dualPort
9070
memoryIOManager.io.GPIO0Port <> GPIO0.io.GPIOPort
91-
memoryIOManager.io.UART0Port <> UART0.io.dataPort
9271
memoryIOManager.io.Timer0Port <> timer0.io.timerPort
72+
memoryIOManager.io.DataMemPort <> io.dataMemPort
73+
memoryIOManager.io.UART0Port <> io.UART0Port
9374

9475
// --------------- CPU Control --------------- //
9576

@@ -102,10 +83,10 @@ class CPUSingleCycle(
10283
}
10384

10485
// Connect PC output to instruction memory
105-
instructionMemory.io.memPort.readAddr := PC.io.pcPort.PC
86+
io.instructionMemPort.readAddr := PC.io.pcPort.PC
10687

10788
// Connect the instruction memory to the decoder
108-
decoder.io.DecoderPort.op := instructionMemory.io.memPort.readData
89+
decoder.io.DecoderPort.op := io.instructionMemPort.readData
10990

11091
// Connect the decoder output to register bank inputs
11192
registerBank.io.regPort.regwr_addr := decoder.io.DecoderPort.rd
@@ -143,7 +124,7 @@ class CPUSingleCycle(
143124
when(ALU.io.ALUPort.x === 1.U) {
144125
PC.io.pcPort.writeEnable := true.B
145126
PC.io.pcPort.writeAdd := true.B
146-
PC.io.pcPort.dataIn := decoder.io.DecoderPort.imm
127+
PC.io.pcPort.dataIn := decoder.io.DecoderPort.imm.asUInt()
147128
}
148129
}
149130

@@ -161,12 +142,12 @@ class CPUSingleCycle(
161142
when(decoder.io.DecoderPort.inst === JAL) {
162143
// Set PC to jump address
163144
PC.io.pcPort.writeAdd := true.B
164-
PC.io.pcPort.dataIn := decoder.io.DecoderPort.imm
145+
PC.io.pcPort.dataIn := decoder.io.DecoderPort.imm.asUInt()
165146
}
166147
when(decoder.io.DecoderPort.inst === JALR) {
167148
// Set PC to jump address
168149
PC.io.pcPort.dataIn := Cat(
169-
(registerBank.io.regPort.rs1 + decoder.io.DecoderPort.imm.asSInt).asUInt()(31, 1),
150+
(registerBank.io.regPort.rs1 + decoder.io.DecoderPort.imm).asUInt()(31, 1),
170151
0.U,
171152
)
172153
}
@@ -175,18 +156,16 @@ class CPUSingleCycle(
175156
// LUI
176157
when(decoder.io.DecoderPort.inst === LUI) {
177158
registerBank.io.regPort.writeEnable := true.B
178-
registerBank.io.regPort.regwr_data := Cat(decoder.io.DecoderPort.imm(31, 12), Fill(12, 0.U)).asSInt
159+
registerBank.io.regPort.regwr_data := decoder.io.DecoderPort.imm
179160
}
180161

181162
// AUIPC
182163
when(decoder.io.DecoderPort.inst === AUIPC) {
183164
registerBank.io.regPort.writeEnable := true.B
184165
ALU.io.ALUPort.inst := ADD
185166
ALU.io.ALUPort.a := PC.io.pcPort.PC
186-
ALU.io.ALUPort.b := Cat(
187-
decoder.io.DecoderPort.imm(31, 12),
188-
Fill(12, 0.U),
189-
)
167+
ALU.io.ALUPort.b :=
168+
decoder.io.DecoderPort.imm.asUInt()
190169
registerBank.io.regPort.regwr_data := ALU.io.ALUPort.x.asSInt
191170
}
192171

@@ -195,7 +174,7 @@ class CPUSingleCycle(
195174
// Use the ALU to get the resulting address
196175
ALU.io.ALUPort.inst := ADD
197176
ALU.io.ALUPort.a := registerBank.io.regPort.rs1.asUInt
198-
ALU.io.ALUPort.b := decoder.io.DecoderPort.imm
177+
ALU.io.ALUPort.b := decoder.io.DecoderPort.imm.asUInt()
199178

200179
memoryIOManager.io.MemoryIOPort.writeAddr := ALU.io.ALUPort.x
201180
memoryIOManager.io.MemoryIOPort.readAddr := ALU.io.ALUPort.x

src/main/scala/Decoder.scala

+12-11
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class DecoderPort(bitWidth: Int = 32) extends Bundle {
1212
val rd = Output(UInt(5.W)) // Rd is the 5 bit destiny register
1313
val rs1 = Output(UInt(5.W)) // Rs1 is the 5 bit source register 1
1414
val rs2 = Output(UInt(5.W)) // Rs2 is the 5 bit source register 2
15-
val imm = Output(UInt(bitWidth.W)) // Imm is the 32 bit immediate
15+
val imm = Output(SInt(bitWidth.W)) // Imm is the 32 bit immediate
1616
val toALU = Output(Bool()) // ToALU is a flag to indicate if the instruction is to be executed in the ALU
1717
val branch = Output(Bool()) // Branch is a flag to indicate if the instruction should jump and link. Update PC
1818
val use_imm = Output(Bool()) // Use_imm is a flag to indicate if the instruction has an immediate
@@ -97,7 +97,7 @@ class Decoder(bitWidth: Int = 32) extends Module {
9797
io.DecoderPort.rd := 0.U
9898
io.DecoderPort.rs1 := 0.U
9999
io.DecoderPort.rs2 := 0.U
100-
io.DecoderPort.imm := 0.U
100+
io.DecoderPort.imm := 0.S
101101
io.DecoderPort.inst := signals(1)
102102
io.DecoderPort.toALU := signals(2)
103103
io.DecoderPort.branch := signals(3)
@@ -144,14 +144,15 @@ class Decoder(bitWidth: Int = 32) extends Module {
144144
* @return
145145
* the imm value
146146
*/
147-
def ImmGenerator(regType: InstructionType.Type, inst: UInt): UInt = regType match {
148-
case INST_R => 0.U
149-
case INST_I => Cat(Fill(20, inst(31)), inst(31, 20))
150-
case INST_S => Cat(Fill(20, inst(31)), inst(31, 25), inst(11, 7))
151-
case INST_B => Cat(Fill(19, inst(31)), inst(31), inst(7), inst(30, 25), inst(11, 8), 0.U(1.W))
152-
case INST_U => Cat(inst(31, 12), Fill(12, 0.U))
153-
case INST_J => Cat(Fill(11, inst(31)), inst(31), inst(19, 12), inst(20), inst(30, 25), inst(24, 21), 0.U(1.W))
154-
case INST_Z => Cat(Fill(27, 0.U), inst(19, 15)) // for csri
155-
case _ => 0.U
147+
def ImmGenerator(regType: InstructionType.Type, inst: UInt): SInt = regType match {
148+
case INST_R => 0.S
149+
case INST_I => Cat(Fill(20, inst(31)), inst(31, 20)).asSInt()
150+
case INST_S => Cat(Fill(20, inst(31)), inst(31, 25), inst(11, 7)).asSInt()
151+
case INST_B => Cat(Fill(19, inst(31)), inst(31), inst(7), inst(30, 25), inst(11, 8), 0.U(1.W)).asSInt()
152+
case INST_U => Cat(inst(31, 12), Fill(12, 0.U)).asSInt()
153+
case INST_J =>
154+
Cat(Fill(11, inst(31)), inst(31), inst(19, 12), inst(20), inst(30, 25), inst(24, 21), 0.U(1.W)).asSInt()
155+
case INST_Z => Cat(Fill(27, 0.U), inst(19, 15)).asSInt() // for csri
156+
case _ => 0.S
156157
}
157158
}

src/main/scala/InstructionMemory.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import chisel3.experimental.{ChiselAnnotation, annotate}
55
import chisel3.util.experimental.loadMemoryFromFileInline
66
import chisel3.util.log2Ceil
77

8-
class MemoryPortSingle(val bitWidth: Int, val addressSize: Long) extends Bundle {
9-
val readAddr = Input(UInt(log2Ceil(addressSize).W))
8+
class InstructionMemPort(val bitWidth: Int, val sizeBytes: Long) extends Bundle {
9+
val readAddr = Input(UInt(log2Ceil(sizeBytes).W))
1010
val readData = Output(UInt(bitWidth.W))
1111
}
1212

@@ -17,7 +17,7 @@ class InstructionMemory(
1717
) extends Module {
1818
val words = sizeBytes / bitWidth
1919
val io = IO(new Bundle() {
20-
val memPort = new MemoryPortSingle(bitWidth, sizeBytes)
20+
val memPort = new InstructionMemPort(bitWidth, sizeBytes)
2121
})
2222

2323
// This is required to have readmem outside `ifndef SYNTHESIS` and be synthesized by FPGA tools

src/main/scala/SOC.scala

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package chiselv
2+
3+
import chisel3._
4+
import chisel3.experimental._
5+
6+
class SOC(
7+
cpuFrequency: Int,
8+
bitWidth: Int = 32,
9+
instructionMemorySize: Int = 1 * 1024,
10+
dataMemorySize: Int = 1 * 1024,
11+
memoryFile: String = "",
12+
ramFile: String = "",
13+
numGPIO: Int = 8,
14+
) extends Module {
15+
val io = IO(new Bundle {
16+
val led0 = Output(Bool()) // LED 0 is the heartbeat
17+
val GPIO0External = Analog(numGPIO.W) // GPIO external port
18+
val UART0SerialPort = new UARTSerialPort() // UART0 serial port
19+
})
20+
21+
// Heartbeat LED - Keep on if reached an error
22+
val blink = Module(new Blinky(cpuFrequency))
23+
io.led0 := blink.io.led0
24+
25+
// Instantiate and initialize the Instruction memory
26+
val instructionMemory = Module(new InstructionMemory(bitWidth, instructionMemorySize, memoryFile))
27+
instructionMemory.io.memPort.readAddr := 0.U
28+
29+
// Instantiate and initialize the Data memory
30+
val dataMemory = Module(new DualPortRAM(bitWidth, dataMemorySize, ramFile))
31+
dataMemory.io.dualPort.writeEnable := false.B
32+
dataMemory.io.dualPort.writeData := 0.U
33+
dataMemory.io.dualPort.readAddress := 0.U
34+
dataMemory.io.dualPort.writeAddress := 0.U
35+
dataMemory.io.dualPort.dataSize := 0.U
36+
dataMemory.io.dualPort.writeMask := 0.U
37+
38+
// Instantiate and connect the UART
39+
val fifoLength = 128
40+
val rxOverclock = 16
41+
val UART0 = Module(new Uart(fifoLength, rxOverclock))
42+
UART0.io.serialPort <> io.UART0SerialPort
43+
44+
// Instantiate our core
45+
val core = Module(
46+
new CPUSingleCycle(cpuFrequency, bitWidth, instructionMemorySize, dataMemorySize, numGPIO)
47+
)
48+
49+
// Connect the core to the devices
50+
core.io.instructionMemPort <> instructionMemory.io.memPort
51+
core.io.dataMemPort <> dataMemory.io.dualPort
52+
core.io.UART0Port <> UART0.io.dataPort
53+
core.io.GPIO0External <> io.GPIO0External
54+
}

src/main/scala/Toplevel.scala

+7-7
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ class Toplevel(board: String, invReset: Boolean = true, cpuFrequency: Int) exten
2727
val dataMemorySize = 64 * 1024
2828
val numGPIO = 8
2929

30-
val CPU =
30+
val SOC =
3131
Module(
32-
new CPUSingleCycle(
32+
new SOC(
3333
cpuFrequency = cpuFrequency,
3434
bitWidth = bitWidth,
3535
instructionMemorySize = instructionMemorySize,
@@ -39,12 +39,12 @@ class Toplevel(board: String, invReset: Boolean = true, cpuFrequency: Int) exten
3939
numGPIO = numGPIO,
4040
)
4141
)
42-
// }
42+
4343
// Connect IO
44-
io.led0 := CPU.io.led0
45-
io.GPIO0 <> CPU.io.GPIO0External
46-
io.UART0tx := CPU.io.UART0SerialPort.tx
47-
CPU.io.UART0SerialPort.rx := io.UART0rx
44+
io.led0 := SOC.io.led0
45+
io.GPIO0 <> SOC.io.GPIO0External
46+
io.UART0tx := SOC.io.UART0SerialPort.tx
47+
SOC.io.UART0SerialPort.rx := io.UART0rx
4848
}
4949
}
5050

src/test/scala/CPUDemoAppsSpec.scala

+3-4
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,17 @@ class CPUSingleCycleWrapperDemo(
1717
ramFile: String,
1818
numGPIO: Int,
1919
// baudRate: Int,
20-
) extends CPUSingleCycle(
20+
) extends SOC(
2121
cpuFrequency,
2222
bitWidth,
2323
instructionMemorySize,
2424
memorySize,
2525
memoryFile,
2626
ramFile,
2727
numGPIO,
28-
// baudRate,
2928
) {
30-
val registers = expose(registerBank.regs)
31-
val pc = expose(PC.pc)
29+
val registers = expose(core.registerBank.regs)
30+
val pc = expose(core.PC.pc)
3231
}
3332

3433
class CPUDemoAppsSpec extends AnyFlatSpec with ChiselScalatestTester with should.Matchers {

src/test/scala/CPUSingleCycleAppsSpec.scala

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ class CPUSingleCycleWrapperApps(
1414
instructionMemorySize: Int,
1515
memorySize: Int,
1616
memoryFile: String,
17-
) extends CPUSingleCycle(cpuFrequency, bitWidth, instructionMemorySize, memorySize, memoryFile) {
18-
val registers = expose(registerBank.regs)
19-
val memWriteAddr = expose(memoryIOManager.io.MemoryIOPort.writeAddr)
20-
val memWriteData = expose(memoryIOManager.io.MemoryIOPort.writeData)
21-
val memReadAddr = expose(memoryIOManager.io.MemoryIOPort.readAddr)
22-
val memReadData = expose(memoryIOManager.io.MemoryIOPort.readData)
17+
) extends SOC(cpuFrequency, bitWidth, instructionMemorySize, memorySize, memoryFile) {
18+
val registers = expose(core.registerBank.regs)
19+
val memWriteAddr = expose(core.memoryIOManager.io.MemoryIOPort.writeAddr)
20+
val memWriteData = expose(core.memoryIOManager.io.MemoryIOPort.writeData)
21+
val memReadAddr = expose(core.memoryIOManager.io.MemoryIOPort.readAddr)
22+
val memReadData = expose(core.memoryIOManager.io.MemoryIOPort.readData)
2323
}
2424

2525
class CPUSingleCycleAppsSpec extends AnyFlatSpec with ChiselScalatestTester with should.Matchers {

0 commit comments

Comments
 (0)