diff --git a/git_commit.sh b/git_commit.sh index 7526608..8d25178 100755 --- a/git_commit.sh +++ b/git_commit.sh @@ -4,7 +4,7 @@ STUID=ysyx_22040000 STUNAME=李心杨 TRACER=tracer-ysyx -GITFLAGS="-q --author=$TRACER --no-verify --allow-empty" +GITFLAGS="-q --author=$TRACER --no-verify --allow-empty --no-gpg-sign" WORK_BRANCH=$(git rev-parse --abbrev-ref HEAD) WORK_INDEX=.git/index.${WORK_BRANCH} diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index b4621bb..ef78ddd 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -17,74 +17,85 @@ find_package(verilator REQUIRED) find_library(NVBOARD_LIBRARY NAMES nvboard) find_path(NVBOARD_INCLUDE_DIR NAMES nvboard.h) -set(TOPMODULE "Switch") -set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core") -set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}") -file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") -file(GLOB_RECURSE SCALA_CORE_TEST_SOURCES "${SCALA_CORE}/src/test/scala/*.scala") +set(TOPMODULES "Switch" "Keyboard") -# Configure time verilog source generation for verilator -execute_process( - COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" - WORKING_DIRECTORY ${SCALA_CORE} -) +foreach(TOPMODULE IN LISTS TOPMODULES) + + # FIXME: all scala source file are tracked here, cause all files to rebuild + # after a source update. + set(SCALA_CORE "${CMAKE_CURRENT_SOURCE_DIR}/core") + set(CHISEL_MODULE_CLASS "${CMAKE_PROJECT_NAME}.${TOPMODULE}") + file(GLOB_RECURSE SCALA_CORE_SOURCES "${SCALA_CORE}/src/main/scala/*.scala") + file(GLOB_RECURSE SCALA_CORE_TEST_SOURCES "${SCALA_CORE}/src/test/scala/*.scala") -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v - COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" - WORKING_DIRECTORY ${SCALA_CORE} - DEPENDS ${SCALA_CORE_SOURCES} -) + # Configure time verilog source generation for verilator + execute_process( + COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" + WORKING_DIRECTORY ${SCALA_CORE} + ) -add_custom_target( - ChiselBuild - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v -) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v + COMMAND sbt "runMain circt.stage.ChiselMain --target-dir ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc --module ${CHISEL_MODULE_CLASS} --target verilog" + WORKING_DIRECTORY ${SCALA_CORE} + DEPENDS ${SCALA_CORE_SOURCES} + ) -# -- Build NVBoard executable + add_custom_target( + ChiselBuild_${TOPMODULE} + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v + ) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/auto_bind.cpp - COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ${CMAKE_CURRENT_BINARY_DIR}/auto_bind.cpp - DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc -) + # -- Build NVBoard executable -add_executable(V${TOPMODULE}_nvboard csrc_nvboard/main.cpp auto_bind.cpp) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp + COMMAND auto_pin_bind ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp + DEPENDS ${CMAKE_SOURCE_DIR}/constr/${TOPMODULE}.nxdc + ) -verilate(V${TOPMODULE}_nvboard TRACE COVERAGE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v) + unset(SOURCES) + file(GLOB_RECURSE SOURCES csrc_nvboard/${TOPMODULE}/*.cpp) + add_executable(V${TOPMODULE}_nvboard ${SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/auto_bind.cpp) -add_dependencies(V${TOPMODULE}_nvboard ChiselBuild) -target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}) -target_link_libraries(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 SDL2_image::SDL2_image) + verilate(V${TOPMODULE}_nvboard TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) -install(TARGETS V${TOPMODULE}_nvboard) + add_dependencies(V${TOPMODULE}_nvboard ChiselBuild_${TOPMODULE}) + target_include_directories(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}) + target_link_libraries(V${TOPMODULE}_nvboard PRIVATE ${NVBOARD_LIBRARY} SDL2::SDL2 SDL2_image::SDL2_image) -# -- Build Verilator executable and add to test + install(TARGETS V${TOPMODULE}_nvboard) -add_executable(V${TOPMODULE} csrc/main.cpp) + # -- Build Verilator executable and add to test -verilate(V${TOPMODULE} TRACE COVERAGE THREADS - TOP_MODULE ${TOPMODULE} - PREFIX V${TOPMODULE} - SOURCES ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v) + unset(SOURCES) + file(GLOB_RECURSE SOURCES csrc/${TOPMODULE}/*.cpp) + add_executable(V${TOPMODULE} ${SOURCES}) -add_dependencies(V${TOPMODULE} ChiselBuild) + verilate(V${TOPMODULE} TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${TOPMODULE}/vsrc/${TOPMODULE}.v) -enable_testing() -add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) + add_dependencies(V${TOPMODULE} ChiselBuild_${TOPMODULE}) -# -- Add build tracking -add_custom_command( - TARGET V${TOPMODULE}_nvboard PRE_BUILD - COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}_nvboard" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. -) + enable_testing() + add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) -add_custom_command( - TARGET V${TOPMODULE} PRE_BUILD - COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}" - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. -) + # -- Add build tracking + add_custom_command( + TARGET V${TOPMODULE}_nvboard PRE_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}_nvboard" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. + ) + + add_custom_command( + TARGET V${TOPMODULE} PRE_BUILD + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "build_${CMAKE_PROJECT_NAME}_V${TOPMODULE}" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/.. + ) + +endforeach() diff --git a/npc/constr/Keyboard.nxdc b/npc/constr/Keyboard.nxdc new file mode 100644 index 0000000..e615b2c --- /dev/null +++ b/npc/constr/Keyboard.nxdc @@ -0,0 +1,12 @@ +top=Keyboard + +io_ps2_clk PS2_CLK +io_ps2_data PS2_DAT +io_segs_0 (SEG0A, SEG0B, SEG0C, SEG0D, SEG0E, SEG0F, SEG0G, DEC0P) +io_segs_1 (SEG1A, SEG1B, SEG1C, SEG1D, SEG1E, SEG1F, SEG1G, DEC1P) +io_segs_2 (SEG2A, SEG2B, SEG2C, SEG2D, SEG2E, SEG2F, SEG2G, DEC2P) +io_segs_3 (SEG3A, SEG3B, SEG3C, SEG3D, SEG3E, SEG3F, SEG3G, DEC3P) +io_segs_4 (SEG4A, SEG4B, SEG4C, SEG4D, SEG4E, SEG4F, SEG4G, DEC4P) +io_segs_5 (SEG5A, SEG5B, SEG5C, SEG5D, SEG5E, SEG5F, SEG5G, DEC5P) +io_segs_6 (SEG6A, SEG6B, SEG6C, SEG6D, SEG6E, SEG6F, SEG6G, DEC6P) +io_segs_7 (SEG7A, SEG7B, SEG7C, SEG7D, SEG7E, SEG7F, SEG7G, DEC7P) diff --git a/npc/core/src/main/scala/ALU.scala b/npc/core/src/main/scala/ALU.scala new file mode 100644 index 0000000..65ade3e --- /dev/null +++ b/npc/core/src/main/scala/ALU.scala @@ -0,0 +1,34 @@ +package npc.util + +import chisel3._ +import chisel3.util._ + +class ALUGenerator(width: Int) extends Module { + require(width >= 0) + val io = IO(new Bundle { + val a = Input(UInt(width.W)) + val b = Input(UInt(width.W)) + val op = Input(UInt(4.W)) + val out = Output(UInt(width.W)) + }) + + val adder_b = (Fill(width, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub + val add = io.a + adder_b + val and = io.a & io.b + val not = ~io.a + val or = io.a | io.b + val xor = io.a ^ io.b + val slt = io.a < io.b + val eq = io.a === io.b + + io.out := MuxLookup(io.op, 0.U)(Seq( + 0.U -> add, + 1.U -> add, // add with b reversed + 2.U -> not, + 3.U -> and, + 4.U -> or, + 5.U -> xor, + 6.U -> slt, + 7.U -> eq, + )) +} diff --git a/npc/core/src/main/scala/Keyboard.scala b/npc/core/src/main/scala/Keyboard.scala new file mode 100644 index 0000000..ddc512c --- /dev/null +++ b/npc/core/src/main/scala/Keyboard.scala @@ -0,0 +1,55 @@ +package npc.util + +import chisel3._ +import chisel3.util.{Counter, Decoupled, Queue, Reverse, MuxLookup} + +class PS2Port extends Bundle { + val clk = Input(Bool()) + val data = Input(UInt(1.W)) +} + +object PS2Port { + def apply(): PS2Port = { + new PS2Port + } +} + +class KeyboardController extends Module { + val io = IO(new Bundle { + val ps2 = PS2Port() + val out = Decoupled(UInt(8.W)) + }) + // valid only on the clock negedge of ps2_clk + val ps2_clk_valid = RegNext(io.ps2.clk, false.B) & ~io.ps2.clk + val cycle_counter = Counter(11) + val concated_data = RegInit(0.U(8.W)) + + val queue_in = Wire(Flipped(Decoupled(UInt(8.W)))) + val queue = Queue(queue_in, entries = 8) + val received = RegInit(Bool(), false.B) + val pushed = RegNext(queue_in.valid && queue_in.ready, false.B) + queue_in.valid := false.B + queue_in.bits := Reverse(concated_data) + io.out <> queue + + when(cycle_counter.value === 0.U) { + concated_data := 0.U + received := false.B + } + + when(ps2_clk_valid) { + when(cycle_counter.value < 9.U && cycle_counter.value >= 1.U) { + concated_data := (concated_data << 1) | io.ps2.data + }.elsewhen(cycle_counter.value === 9.U) { + received := true.B + } + cycle_counter.inc() + } + + when(!pushed && received) { + queue_in.valid := true.B + }.elsewhen(pushed && received) { + queue_in.valid := false.B + received := false.B + } +} diff --git a/npc/core/src/main/scala/Main.scala b/npc/core/src/main/scala/Main.scala index 4e427f2..5644090 100644 --- a/npc/core/src/main/scala/Main.scala +++ b/npc/core/src/main/scala/Main.scala @@ -4,113 +4,6 @@ import chisel3._ import chisel3.util.{MuxLookup, Fill, Decoupled, Counter, Queue, Reverse} import chisel3.stage.ChiselOption -class RegisterFile(readPorts: Int) extends Module { - require(readPorts >= 0) - val io = IO(new Bundle { - val writeEnable = Input(Bool()) - val writeAddr = Input(UInt(5.W)) - val writeData = Input(UInt(32.W)) - val readAddr = Input(Vec(readPorts, UInt(5.W))) - val readData = Output(Vec(readPorts, UInt(32.W))) - }) - - val regFile = RegInit(VecInit(Seq.fill(32)(0.U(32.W)))) - for (i <- 1 until 32) { - regFile(i) := regFile(i) - } - regFile(io.writeAddr) := Mux(io.writeEnable, io.writeData, regFile(io.writeAddr)) - regFile(0) := 0.U - - for (i <- 0 until readPorts) { - io.readData(i) := regFile(io.readAddr(i)) - } -} - -class ALUGenerator(width: Int) extends Module { - require(width >= 0) - val io = IO(new Bundle { - val a = Input(UInt(width.W)) - val b = Input(UInt(width.W)) - val op = Input(UInt(4.W)) - val out = Output(UInt(width.W)) - }) - - val adder_b = (Fill(width, io.op(0)) ^ io.b) + io.op(0) // take (-b) if sub - val add = io.a + adder_b - val and = io.a & io.b - val not = ~io.a - val or = io.a | io.b - val xor = io.a ^ io.b - val slt = io.a < io.b - val eq = io.a === io.b - - io.out := MuxLookup(io.op, 0.U)(Seq( - 0.U -> add, - 1.U -> add, // add with b reversed - 2.U -> not, - 3.U -> and, - 4.U -> or, - 5.U -> xor, - 6.U -> slt, - 7.U -> eq, - )) -} - -class Test extends Module { - val io = IO(new Bundle { - val in = Input(UInt(32.W)) - val out = Output(UInt(32.W)) - }) - - val regFile = Module(new RegisterFile(2)) - regFile.io.writeEnable := true.B - regFile.io.writeAddr := 1.U - regFile.io.writeData := io.in - regFile.io.readAddr(0) := 0.U - regFile.io.readAddr(1) := 1.U - io.out := regFile.io.readData(1) -} - -class KeyboardController extends Module { - val io = IO(new Bundle { - val ps2_clk = Input(Bool()) - val ps2_data = Input(UInt(1.W)) - val out = Decoupled(UInt(8.W)) - }) - val queue_io = Wire(Flipped(Decoupled(UInt(8.W)))) - queue_io.valid := true.B - queue_io.bits := 0.B - val queue = Queue(queue_io, entries = 8) - io.out <> queue - - // valid only on the clock negedge of ps2_clk - val ps2_clk_valid = RegNext(io.ps2_clk, false.B) & ~io.ps2_clk - val cycle_counter = Counter(11) - val concated_data = RegInit(0.U(8.W)) - val is_receiving = RegInit(Bool(), false.B) - - when(io.ps2_clk && io.ps2_data === 1.U) { - // Start receiving data - is_receiving := true.B - } - - when(is_receiving && ps2_clk_valid) { - cycle_counter.inc() - when(cycle_counter.value < 9.U && cycle_counter.value > 0.U) { - concated_data := (concated_data << 1) | io.ps2_data - } - when(cycle_counter.value === 10.U) { - is_receiving := false.B - } - } - - when(is_receiving) { - queue_io.noenq() - }.otherwise{ - queue_io.enq(Reverse(concated_data)) - } -} - class Switch extends Module { val io = IO(new Bundle { val sw = Input(Vec(2, Bool())) @@ -119,3 +12,22 @@ class Switch extends Module { io.out := io.sw(0) ^ io.sw(1) } + +import npc.util.{PS2Port, KeyboardController, SegGenerator} + +class Keyboard extends Module { + val io = IO(new Bundle { + val ps2 = PS2Port() + val segs = Output(Vec(8, UInt(8.W))) + }) + + val seg_handler = Module(new SegGenerator(seg_count = 8)) + val keyboard_controller = Module(new KeyboardController) + + seg_handler.io.keycode <> keyboard_controller.io.out + + keyboard_controller.io.ps2 := io.ps2 + io.segs := seg_handler.io.segs +} + +class SegHandler extends SegGenerator(8) { } diff --git a/npc/core/src/main/scala/RegisterFile.scala b/npc/core/src/main/scala/RegisterFile.scala new file mode 100644 index 0000000..fbf8a94 --- /dev/null +++ b/npc/core/src/main/scala/RegisterFile.scala @@ -0,0 +1,25 @@ +package npc.util + +import chisel3._ + +class RegisterFile(readPorts: Int) extends Module { + require(readPorts >= 0) + val io = IO(new Bundle { + val writeEnable = Input(Bool()) + val writeAddr = Input(UInt(5.W)) + val writeData = Input(UInt(32.W)) + val readAddr = Input(Vec(readPorts, UInt(5.W))) + val readData = Output(Vec(readPorts, UInt(32.W))) + }) + + val regFile = RegInit(VecInit(Seq.fill(32)(0.U(32.W)))) + for (i <- 1 until 32) { + regFile(i) := regFile(i) + } + regFile(io.writeAddr) := Mux(io.writeEnable, io.writeData, regFile(io.writeAddr)) + regFile(0) := 0.U + + for (i <- 0 until readPorts) { + io.readData(i) := regFile(io.readAddr(i)) + } +} diff --git a/npc/core/src/main/scala/SegGenerator.scala b/npc/core/src/main/scala/SegGenerator.scala new file mode 100644 index 0000000..4a5efaf --- /dev/null +++ b/npc/core/src/main/scala/SegGenerator.scala @@ -0,0 +1,48 @@ +package npc.util + +import chisel3._ +import chisel3.util._ +import chisel3.util.log2Ceil + +class SegGenerator(seg_count: Int) extends Module { + val io = IO(new Bundle { + val keycode = Flipped(Decoupled(UInt(8.W))) + val segs = Output(Vec(seg_count, UInt(8.W))) + }) + io.keycode.ready := false.B + when(io.keycode.valid) { + io.keycode.ready := true.B + } + + val seg_regs = RegInit(VecInit(Seq.fill(seg_count)(0.U(8.W)))) + val last_keycode = RegInit(0.U(8.W)) + val digit_to_seg = ((0 until 16).map(_.U)).zip(Seq( + "b00000011".U, "b10011111".U, "b00100101".U, "b00001101".U, + "b10011001".U, "b01001001".U, "b01000001".U, "b00011111".U, + "b00000001".U, "b00001001".U, "b00010001".U, "b11000001".U, + "b01100011".U, "b10000101".U, "b01100001".U, "b01110001".U, + )) + + val keycode_to_ascii = Seq( + 0x1C.U, 0x32.U, 0x21.U, 0x23.U, 0x24.U, 0x2B.U, + 0x34.U, 0x33.U, 0x43.U, 0x3B.U, 0x42.U, 0x4B.U, + 0x3A.U, 0x31.U, 0x44.U, 0x4D.U, 0x15.U, 0x2D.U, + 0x1B.U, 0x2C.U, 0x3C.U, 0x2A.U, 0x1D.U, 0x22.U, + 0x35.U, 0x1A.U, 0x45.U, 0x16.U, 0x1E.U, 0x26.U, + 0x25.U, 0x2E.U, 0x36.U, 0x3D.U, 0x3E.U, 0x46.U, + ).zip(((0x41 to 0x5A) ++ (0x30 to 0x39)).map(_.U)) + + val keycode = RegEnable(io.keycode.bits, io.keycode.ready && io.keycode.valid) + val keycode_digits = VecInit(keycode(3,0)) ++ VecInit(keycode(7,4)) + val keycode_seg = keycode_digits.map(MuxLookup(_, 0xFF.U)(digit_to_seg)) + val ascii = MuxLookup(keycode, 0.U)(keycode_to_ascii) + val ascii_digits = VecInit(ascii(3,0)) ++ VecInit(ascii(6,4)) + val ascii_seg = ascii_digits.map(MuxLookup(_, 0xFF.U)(digit_to_seg)) + val (counter, _) = Counter(io.keycode.valid && io.keycode.ready && io.keycode.bits =/= keycode, 0xFF) + val count_digits = VecInit(counter(3,0)) ++ VecInit(counter(7,4)) + val count_seg = count_digits.map(MuxLookup(_, 0xFF.U)(digit_to_seg)) + + seg_regs := keycode_seg ++ ascii_seg ++ count_seg ++ Seq(0xFF.U, 0xFF.U) + + io.segs := seg_regs +} diff --git a/npc/core/src/test/scala/Keyboard.scala b/npc/core/src/test/scala/Keyboard.scala new file mode 100644 index 0000000..24723cc --- /dev/null +++ b/npc/core/src/test/scala/Keyboard.scala @@ -0,0 +1,72 @@ +package npc.keyboard + +import chisel3._ +import chiseltest._ +import org.scalatest.freespec.AnyFreeSpec +import chiseltest.simulator.WriteVcdAnnotation + +import npc.util._ + +class KeyboardControllerSpec extends AnyFreeSpec with ChiselScalatestTester { + def transfer(keycode: Int, clock: Clock, ps2: PS2Port) : Unit = { + require(keycode >= 0 && keycode < 0xFF) + var cycle = 0 + var keycode_remain = keycode << 1 // Shift 1 to do nothing at cycle 0 + var keycode_collect = 0 + + ps2.data.poke(1) + ps2.clk.poke(true) + clock.step(1) + for (cycle <- 0 until 9) { + val last_digit = keycode_remain & 1 + ps2.clk.poke(true) + ps2.data.poke(last_digit) + clock.step(32) + keycode_collect = keycode_collect | (last_digit << cycle) + keycode_remain = keycode_remain >> 1 + ps2.clk.poke(false) + clock.step(32) + } + for (_ <- 9 until 11) { + ps2.clk.poke(true) + clock.step(32) + ps2.clk.poke(false) + clock.step(32) + } + assert(keycode_collect >> 1 == keycode) + clock.step(32) + } + "Simple test" in { + test(new KeyboardController).withAnnotations(Seq(WriteVcdAnnotation)) { c => + val data = Array(0xE4, 0xD4, 0xC4, 0xA9) + data.foreach(d => { + transfer(d, c.clock, c.io.ps2) + c.io.out.valid.expect(1.U) + c.io.out.bits.expect(d) + c.io.out.ready.poke(1) + c.clock.step(1) + c.io.out.ready.poke(0) + }) + data.foreach(d => { + transfer(d, c.clock, c.io.ps2) + }) + data.foreach(d => { + c.io.out.valid.expect(1.U) + c.io.out.bits.expect(d) + c.io.out.ready.poke(1) + c.clock.step(1) + c.io.out.ready.poke(0) + }) + } + } +} + +class SegSpec extends AnyFreeSpec with ChiselScalatestTester { + "try out vec" in { + test(new SegGenerator(8)) {c => + c.io.keycode.bits.poke(0xAC) + c.clock.step(1) + println(s"out: ${c.io.segs(0).peek().litValue}") + } + } +} diff --git a/npc/core/src/test/scala/Main.scala b/npc/core/src/test/scala/Main.scala index 9b0cec4..c9c093e 100644 --- a/npc/core/src/test/scala/Main.scala +++ b/npc/core/src/test/scala/Main.scala @@ -3,9 +3,10 @@ package npc import chisel3._ import chiseltest._ import org.scalatest.freespec.AnyFreeSpec -import chiseltest.simulator.ChiselBridge import chiseltest.simulator.WriteVcdAnnotation +import npc.util._ + class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester { "RegisterFile should work" - { "with 2 read ports" in { @@ -102,46 +103,3 @@ class ALUGeneratorSpec extends AnyFreeSpec with ChiselScalatestTester { } } } - -class KeyboardControllerSpec extends AnyFreeSpec with ChiselScalatestTester { - def transfer(keycode: Int, c: KeyboardController) : Unit = { - require(keycode >= 0 && keycode < 0xFF) - var cycle = 0 - var ps2_clk = true - var keycode_remain = keycode << 1 // Shift 1 to do nothing at cycle 1 - var keycode_collect = 0 - - c.io.ps2_clk.poke(ps2_clk) - c.io.ps2_data.poke(1) - for (cycle <- 0 until 9) { - c.io.ps2_clk.poke(true) - c.clock.step(32) - val last_digit = keycode_remain & 1 - c.io.ps2_data.poke(last_digit) - keycode_collect = keycode_collect | (last_digit << cycle) - keycode_remain = keycode_remain >> 1 - c.io.ps2_clk.poke(false) - c.clock.step(32) - } - for (_ <- 9 until 11) { - c.io.ps2_clk.poke(true) - c.clock.step(32) - c.io.ps2_clk.poke(ps2_clk) - ps2_clk = !ps2_clk - c.io.ps2_clk.poke(false) - c.clock.step(32) - } - assert(keycode_collect >> 1 == keycode) - c.io.out.ready.poke(1) - c.clock.step(32) - c.io.out.bits.expect(keycode) - } - "Simple test" in { - test(new KeyboardController).withAnnotations(Seq(WriteVcdAnnotation)) { c => - transfer(0xE4, c) - transfer(0xE4, c) - transfer(0xE4, c) - transfer(0xE4, c) - } - } -} diff --git a/npc/csrc/Keyboard/main.cpp b/npc/csrc/Keyboard/main.cpp new file mode 100644 index 0000000..4728202 --- /dev/null +++ b/npc/csrc/Keyboard/main.cpp @@ -0,0 +1,12 @@ +#include +#include +#include +#include +#include + +int main(int argc, char **argv, char **env) { + int sim_time = 0; + Verilated::commandArgs(argc, argv); + + exit(EXIT_SUCCESS); +} diff --git a/npc/csrc/main.cpp b/npc/csrc/Switch/main.cpp similarity index 100% rename from npc/csrc/main.cpp rename to npc/csrc/Switch/main.cpp diff --git a/npc/csrc_nvboard/Keyboard/main.cpp b/npc/csrc_nvboard/Keyboard/main.cpp new file mode 100644 index 0000000..8f5ea74 --- /dev/null +++ b/npc/csrc_nvboard/Keyboard/main.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include + +#ifndef VERILATOR_TOPMODULE +#define VERILATOR_TOPMODULE VKeyboard +#endif + +#define CLASS_SYSTEM_HEADER_NAME(name) CLASS_SYSTEM_HEADER_NAME_IMPL(name) +#define CLASS_SYSTEM_HEADER_NAME_IMPL(name) +#include CLASS_SYSTEM_HEADER_NAME(VERILATOR_TOPMODULE) +#undef CLASS_SYSTEM_HEADER_NAME +#undef CLASS_SYSTEM_HEADER_NAME_IMPL + +int keycode = 0; + +template void cycle(VERILATOR_TOPMODULE *top, F &&f) { + top->clock = 0; + top->eval(); + top->clock = 1; + top->eval(); + f(); +} + +void nvboard_bind_all_pins(VERILATOR_TOPMODULE *top); + +static void single_cycle(VERILATOR_TOPMODULE *top) { + top->clock = 0; + top->eval(); + top->clock = 1; + top->eval(); +} + +static void reset(VERILATOR_TOPMODULE *top, int n) { + top->reset = 1; + while (n-- > 0) + single_cycle(top); + top->reset = 0; +} + +int main(int argc, char **argv, char **env) { + VERILATOR_TOPMODULE *top = new VERILATOR_TOPMODULE; + + nvboard_bind_all_pins(top); + nvboard_init(); + reset(top, 10); + while (true) { + nvboard_update(); + cycle(top, [&] { + if (keycode != top->io_ps2_data){ + keycode = top->io_ps2_data; + printf("%d\n", keycode); + } + }); + } + delete top; +} \ No newline at end of file diff --git a/npc/csrc_nvboard/main.cpp b/npc/csrc_nvboard/Switch/main.cpp similarity index 100% rename from npc/csrc_nvboard/main.cpp rename to npc/csrc_nvboard/Switch/main.cpp