add mini-yatcpu

This commit is contained in:
TOKISAKIX\21168
2023-12-12 11:03:06 +08:00
parent fb1bf9d3f4
commit 73df6caf1c
133 changed files with 29085 additions and 4 deletions

View File

@@ -0,0 +1,25 @@
package riscv
import board.z710.Top
import riscv.{Parameters, TestAnnotations}
import chisel3._
import chisel3.util.{is, switch}
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import board.z710.Top
class SayGoodbyeTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Board simulation"
it should "say goodbye " in {
test(new Top("say_goodbye.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
for (i <- 1 to 50000) {
c.clock.step(5)
c.io.rx.poke((i % 2).U) // poke some useless value, since rx not yet used
}
}
}
}

View File

@@ -0,0 +1,164 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv
import bus.{AXI4LiteMaster, AXI4LiteMasterBundle, AXI4LiteSlave, AXI4LiteSlaveBundle}
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import peripheral.{Memory, ROMLoader}
class TimerTest extends AnyFlatSpec with ChiselScalatestTester {
class TestTimerLimit extends Module {
val io = IO(new Bundle {
val limit = Output(UInt())
val bundle = new AXI4LiteMasterBundle(Parameters.AddrBits, Parameters.DataBits)
})
val timer = Module(new peripheral.Timer)
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
io.limit := timer.io.debug_limit
master.io.bundle <> io.bundle
timer.io.channels <> master.io.channels
}
behavior of "Timer"
it should "read and write the limit" in {
test(new TestTimerLimit).withAnnotations(TestAnnotations.annos) {
c =>
c.io.bundle.read.poke(false.B)
c.io.bundle.write.poke(true.B)
c.io.bundle.address.poke(0x4.U)
c.io.bundle.write_data.poke(0x990315.U)
c.clock.step()
c.io.bundle.busy.expect(true.B)
c.io.bundle.write.poke(false.B)
c.io.bundle.address.poke(0x0.U)
c.io.bundle.write_data.poke(0.U)
c.clock.step(8)
c.io.bundle.busy.expect(false.B)
c.io.bundle.write_valid.expect(true.B)
c.io.limit.expect(0x990315.U)
c.io.bundle.read.poke(true.B)
c.io.bundle.address.poke(0x4.U)
c.clock.step()
c.io.bundle.busy.expect(true.B)
c.clock.step(6)
c.io.bundle.busy.expect(false.B)
c.io.bundle.read_valid.expect(true.B)
c.io.bundle.read_data.expect(0x990315.U)
}
}
}
class MemoryTest extends AnyFlatSpec with ChiselScalatestTester {
class MemoryTest extends Module {
val io = IO(new Bundle {
val bundle = new AXI4LiteMasterBundle(Parameters.AddrBits, Parameters.DataBits)
val write_strobe = Input(UInt(4.W))
})
val memory = Module(new Memory(4096))
val master = Module(new AXI4LiteMaster(Parameters.AddrBits, Parameters.DataBits))
master.io.bundle <> io.bundle
master.io.bundle.write_strobe := VecInit(io.write_strobe.asBools)
master.io.channels <> memory.io.channels
memory.io.debug_read_address := 0.U
}
behavior of "Memory"
it should "perform read and write" in {
test(new MemoryTest).withAnnotations(TestAnnotations.annos) { c =>
c.io.bundle.read.poke(false.B)
c.io.bundle.write.poke(true.B)
c.io.write_strobe.poke(0xF.U)
c.io.bundle.address.poke(0x4.U)
c.io.bundle.write_data.poke(0xDEADBEEFL.U)
c.clock.step()
c.io.bundle.busy.expect(true.B)
c.io.bundle.write.poke(false.B)
c.io.bundle.address.poke(0x0.U)
c.io.bundle.write_data.poke(0.U)
c.clock.step(8)
c.io.bundle.busy.expect(false.B)
c.io.bundle.write_valid.expect(true.B)
c.io.bundle.read.poke(true.B)
c.io.bundle.address.poke(0x4.U)
c.clock.step()
c.io.bundle.busy.expect(true.B)
c.clock.step(6)
c.io.bundle.busy.expect(false.B)
c.io.bundle.read_valid.expect(true.B)
c.io.bundle.read_data.expect(0xDEADBEEFL.U)
}
}
}
class ROMLoaderTest extends AnyFlatSpec with ChiselScalatestTester {
class ROMLoaderTest extends Module {
val io = IO(new Bundle {
val rom_address = Output(UInt(32.W))
val rom_data = Input(UInt(32.W))
val load_start = Input(Bool())
val load_address = Input(UInt(32.W))
val load_finished = Output(Bool())
val bundle = new AXI4LiteSlaveBundle(32, 32)
})
val rom_loader = Module(new ROMLoader(2))
rom_loader.io.rom_data := io.rom_data
rom_loader.io.load_start := io.load_start
rom_loader.io.load_address := io.load_address
io.load_finished := rom_loader.io.load_finished
io.rom_address := rom_loader.io.rom_address
val slave = Module(new AXI4LiteSlave(Parameters.AddrBits, Parameters.DataBits))
slave.io.bundle <> io.bundle
slave.io.channels <> rom_loader.io.channels
slave.io.bundle.read_data := 0.U
}
behavior of "ROMLoader"
it should "load program" in {
test(new ROMLoaderTest).withAnnotations(TestAnnotations.annos) { c =>
c.io.load_address.poke(0x100.U)
c.io.load_start.poke(true.B)
c.clock.step()
c.io.load_start.poke(false.B)
c.io.rom_address.expect(0x0.U)
c.clock.step(8)
c.io.bundle.write.expect(true.B)
c.io.bundle.address.expect(0x100.U)
c.clock.step(4)
c.io.rom_address.expect(0x1.U)
c.clock.step(7)
c.io.rom_address.expect(0x1.U)
c.io.bundle.write.expect(true.B)
c.io.bundle.address.expect(0x104.U)
c.clock.step()
c.io.rom_address.expect(0x1.U)
c.clock.step(3)
c.io.load_finished.expect(true.B)
}
}
}

View File

@@ -0,0 +1,52 @@
// Copyright 2022 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv
import chiseltest.{VerilatorBackendAnnotation, WriteVcdAnnotation}
import firrtl.AnnotationSeq
import java.nio.file.{Files, Paths}
object VerilatorEnabler {
val annos: AnnotationSeq = if (sys.env.contains("Path")) {
if (sys.env.getOrElse("Path", "").split(";").exists(path => {
Files.exists(Paths.get(path, "verilator"))
})) {
Seq(VerilatorBackendAnnotation)
} else {
Seq()
}
} else {
if (sys.env.getOrElse("PATH", "").split(":").exists(path => {
Files.exists(Paths.get(path, "verilator"))
})) {
Seq(VerilatorBackendAnnotation)
} else {
Seq()
}
}
}
object WriteVcdEnabler {
val annos: AnnotationSeq = if (sys.env.contains("WRITE_VCD")) {
Seq(WriteVcdAnnotation)
} else {
Seq()
}
}
object TestAnnotations {
val annos = VerilatorEnabler.annos ++ WriteVcdEnabler.annos
}

View File

@@ -0,0 +1,184 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.fivestage
import board.basys3.BootStates
import bus.BusSwitch
import chisel3._
import chisel3.util.{is, switch}
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import peripheral.{DummySlave, Memory, ROMLoader}
import riscv.core.fivestage.{CPU, ProgramCounter}
import riscv.{Parameters, TestAnnotations}
import java.nio.{ByteBuffer, ByteOrder}
class TestInstructionROM(asmBin: String) extends Module {
val io = IO(new Bundle {
val address = Input(UInt(32.W))
val data = Output(UInt(32.W))
})
val (insts, capacity) = loadAsmBinary(asmBin)
val mem = RegInit(insts)
io.data := mem(io.address)
def loadAsmBinary(filename: String) = {
val inputStream = getClass.getClassLoader.getResourceAsStream(filename)
var instructions = new Array[BigInt](0)
val arr = new Array[Byte](4)
while (inputStream.read(arr) == 4) {
val instBuf = ByteBuffer.wrap(arr)
instBuf.order(ByteOrder.LITTLE_ENDIAN)
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
instructions = instructions :+ inst
}
(VecInit((instructions.map(inst => inst.U(32.W))).toIndexedSeq), instructions.length)
}
}
class TestTopModule(exeFilename: String) extends Module {
val io = IO(new Bundle {
val mem_debug_read_address = Input(UInt(Parameters.AddrWidth))
val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_debug_read_data = Output(UInt(Parameters.DataWidth))
val mem_debug_read_data = Output(UInt(Parameters.DataWidth))
val interrupt = Input(UInt(Parameters.InterruptFlagWidth))
val boot_state = Output(UInt())
})
val boot_state = RegInit(BootStates.Init)
io.boot_state := boot_state.asUInt
val instruction_rom = Module(new TestInstructionROM(exeFilename))
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
val mem = Module(new Memory(8192))
val cpu = Module(new CPU)
val timer = Module(new peripheral.Timer)
val bus_switch = Module(new BusSwitch)
val dummy = Module(new DummySlave)
bus_switch.io.master <> cpu.io.axi4_channels
bus_switch.io.address := cpu.io.bus_address
for (i <- 0 until Parameters.SlaveDeviceCount) {
bus_switch.io.slaves(i) <> dummy.io.channels
}
rom_loader.io.load_address := ProgramCounter.EntryAddress
rom_loader.io.rom_data := instruction_rom.io.data
rom_loader.io.load_start := false.B
instruction_rom.io.address := rom_loader.io.rom_address
cpu.io.stall_flag_bus := true.B
cpu.io.instruction_valid := false.B
bus_switch.io.slaves(0) <> mem.io.channels
rom_loader.io.channels <> dummy.io.channels
switch(boot_state) {
is(BootStates.Init) {
rom_loader.io.load_start := true.B
boot_state := BootStates.Loading
rom_loader.io.channels <> mem.io.channels
}
is(BootStates.Loading) {
rom_loader.io.load_start := false.B
rom_loader.io.channels <> mem.io.channels
when(rom_loader.io.load_finished) {
boot_state := BootStates.Finished
}
}
is(BootStates.Finished) {
rom_loader.io.load_start := false.B
cpu.io.stall_flag_bus := false.B
cpu.io.instruction_valid := true.B
}
}
bus_switch.io.slaves(4) <> timer.io.channels
mem.io.debug_read_address := io.mem_debug_read_address
cpu.io.debug_read_address := io.regs_debug_read_address
io.regs_debug_read_data := cpu.io.debug_read_data
io.mem_debug_read_data := mem.io.debug_read_data
cpu.io.interrupt_flag := io.interrupt
}
class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Five Stage CPU"
it should "calculate recursively fibonacci(10)" in {
test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 100) {
c.clock.step(1000)
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.mem_debug_read_address.poke(4.U)
c.clock.step()
c.io.mem_debug_read_data.expect(55.U)
}
}
}
class QuicksortTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Five Stage CPU"
it should "quicksort 10 numbers" in {
test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 50) {
c.clock.step(1000)
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
for (i <- 1 to 10) {
c.io.mem_debug_read_address.poke((4 * i).U)
c.clock.step()
c.io.mem_debug_read_data.expect((i - 1).U)
}
}
}
}
class MMIOTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Five Stage CPU"
it should "read and write timer register" in {
test(new TestTopModule("mmio.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 1000) {
c.clock.step()
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.regs_debug_read_address.poke(5.U)
c.io.regs_debug_read_data.expect(100000000.U)
c.io.regs_debug_read_address.poke(6.U)
c.io.regs_debug_read_data.expect(0xBEEF.U)
}
}
}
class ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Five Stage CPU"
it should "store and load single byte" in {
test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 500) {
c.clock.step()
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.regs_debug_read_address.poke(5.U)
c.io.regs_debug_read_data.expect(0xDEADBEEFL.U)
c.io.regs_debug_read_address.poke(6.U)
c.io.regs_debug_read_data.expect(0xEF.U)
c.io.regs_debug_read_address.poke(1.U)
c.io.regs_debug_read_data.expect(0x15EF.U)
}
}
}

View File

@@ -0,0 +1,68 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.fivestage
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import riscv.TestAnnotations
import riscv.core.fivestage.RegisterFile
class RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Register File of Five-stage CPU"
it should "read the written content" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.write_enable.poke(true.B)
c.io.write_address.poke(1.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(1.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
}
}
it should "x0 always be zero" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.write_enable.poke(true.B)
c.io.write_address.poke(0.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(0.U)
c.io.read_data1.expect(0.U)
}
}
it should "read the writing content" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0.U)
c.io.write_enable.poke(true.B)
c.io.write_address.poke(2.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
}
}
}

View File

@@ -0,0 +1,185 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.threestage
import board.basys3.BootStates
import bus.BusSwitch
import chisel3._
import chisel3.util.{is, switch}
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import peripheral.{DummySlave, Memory, ROMLoader}
import riscv.core.threestage.{CPU, ProgramCounter}
import riscv.{Parameters, TestAnnotations}
import java.nio.{ByteBuffer, ByteOrder}
class TestInstructionROM(asmBin: String) extends Module {
val io = IO(new Bundle {
val address = Input(UInt(32.W))
val data = Output(UInt(32.W))
})
val (insts, capacity) = loadAsmBinary(asmBin)
val mem = RegInit(insts)
io.data := mem(io.address)
def loadAsmBinary(filename: String) = {
val inputStream = getClass.getClassLoader.getResourceAsStream(filename)
var instructions = new Array[BigInt](0)
val arr = new Array[Byte](4)
while (inputStream.read(arr) == 4) {
val instBuf = ByteBuffer.wrap(arr)
instBuf.order(ByteOrder.LITTLE_ENDIAN)
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
instructions = instructions :+ inst
}
(VecInit((instructions.map(inst => inst.U(32.W))).toIndexedSeq), instructions.length)
}
}
class TestTopModule(exeFilename: String) extends Module {
val io = IO(new Bundle {
val mem_debug_read_address = Input(UInt(Parameters.AddrWidth))
val regs_debug_read_address = Input(UInt(Parameters.PhysicalRegisterAddrWidth))
val regs_debug_read_data = Output(UInt(Parameters.DataWidth))
val mem_debug_read_data = Output(UInt(Parameters.DataWidth))
val interrupt = Input(UInt(Parameters.InterruptFlagWidth))
val boot_state = Output(UInt())
})
val boot_state = RegInit(BootStates.Init)
io.boot_state := boot_state.asUInt
val instruction_rom = Module(new TestInstructionROM(exeFilename))
val rom_loader = Module(new ROMLoader(instruction_rom.capacity))
val mem = Module(new Memory(8192))
val cpu = Module(new CPU)
val timer = Module(new peripheral.Timer)
val bus_switch = Module(new BusSwitch)
val dummy = Module(new DummySlave)
bus_switch.io.master <> cpu.io.axi4_channels
bus_switch.io.address := cpu.io.bus_address
for (i <- 0 until Parameters.SlaveDeviceCount) {
bus_switch.io.slaves(i) <> dummy.io.channels
}
rom_loader.io.load_address := ProgramCounter.EntryAddress
rom_loader.io.rom_data := instruction_rom.io.data
rom_loader.io.load_start := false.B
instruction_rom.io.address := rom_loader.io.rom_address
cpu.io.stall_flag_bus := true.B
cpu.io.instruction_valid := false.B
bus_switch.io.slaves(0) <> mem.io.channels
rom_loader.io.channels <> dummy.io.channels
switch(boot_state) {
is(BootStates.Init) {
rom_loader.io.load_start := true.B
boot_state := BootStates.Loading
rom_loader.io.channels <> mem.io.channels
}
is(BootStates.Loading) {
rom_loader.io.load_start := false.B
rom_loader.io.channels <> mem.io.channels
when(rom_loader.io.load_finished) {
boot_state := BootStates.Finished
}
}
is(BootStates.Finished) {
rom_loader.io.load_start := false.B
cpu.io.stall_flag_bus := false.B
cpu.io.instruction_valid := true.B
}
}
bus_switch.io.slaves(4) <> timer.io.channels
mem.io.debug_read_address := io.mem_debug_read_address
cpu.io.debug_read_address := io.regs_debug_read_address
io.regs_debug_read_data := cpu.io.debug_read_data
io.mem_debug_read_data := mem.io.debug_read_data
cpu.io.interrupt_flag := io.interrupt
}
class FibonacciTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "CPU"
it should "calculate recursively fibonacci(10)" in {
test(new TestTopModule("fibonacci.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 50) {
c.clock.step(1000)
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.mem_debug_read_address.poke(4.U)
c.clock.step()
c.io.mem_debug_read_data.expect(55.U)
}
}
}
class QuicksortTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "CPU"
it should "quicksort 10 numbers" in {
test(new TestTopModule("quicksort.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 50) {
c.clock.step(1000)
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
for (i <- 1 to 10) {
c.io.mem_debug_read_address.poke((4 * i).U)
c.clock.step()
c.io.mem_debug_read_data.expect((i - 1).U)
}
}
}
}
class MMIOTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "CPU"
it should "read and write timer register" in {
test(new TestTopModule("mmio.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 200) {
c.clock.step()
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.regs_debug_read_address.poke(5.U)
c.io.regs_debug_read_data.expect(100000000.U)
c.io.regs_debug_read_address.poke(6.U)
c.io.regs_debug_read_data.expect(0xBEEF.U)
}
}
}
class ByteAccessTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "CPU"
it should "store and load single byte" in {
test(new TestTopModule("sb.asmbin")).withAnnotations(TestAnnotations.annos) { c =>
c.io.interrupt.poke(0.U)
for (i <- 1 to 500) {
c.clock.step()
c.io.mem_debug_read_address.poke((i * 4).U) // Avoid timeout
}
c.io.regs_debug_read_address.poke(5.U)
c.io.regs_debug_read_data.expect(0xDEADBEEFL.U)
c.io.regs_debug_read_address.poke(6.U)
c.io.regs_debug_read_data.expect(0xEF.U)
c.io.regs_debug_read_address.poke(1.U)
c.io.regs_debug_read_data.expect(0x15EF.U)
}
}
}

View File

@@ -0,0 +1,68 @@
// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package riscv.threestage
import chisel3._
import chiseltest._
import org.scalatest.flatspec.AnyFlatSpec
import riscv.TestAnnotations
import riscv.core.threestage.RegisterFile
class RegisterFileTest extends AnyFlatSpec with ChiselScalatestTester {
behavior of "Register File"
it should "read the written content" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.write_enable.poke(true.B)
c.io.write_address.poke(1.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(1.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
}
}
it should "x0 always be zero" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.write_enable.poke(true.B)
c.io.write_address.poke(0.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(0.U)
c.io.read_data1.expect(0.U)
}
}
it should "read the writing content" in {
test(new RegisterFile).withAnnotations(TestAnnotations.annos) { c =>
timescope {
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0.U)
c.io.write_enable.poke(true.B)
c.io.write_address.poke(2.U)
c.io.write_data.poke(0xDEADBEEFL.U)
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
c.clock.step()
}
c.io.read_address1.poke(2.U)
c.io.read_data1.expect(0xDEADBEEFL.U)
}
}
}