diff --git a/.gitignore b/.gitignore index 285397f..1f1aa83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ -*.* -* !*/ !/nemu/* !/nexus-am/* diff --git a/git_commit.sh b/git_commit.sh deleted file mode 100755 index 460cfcf..0000000 --- a/git_commit.sh +++ /dev/null @@ -1,55 +0,0 @@ -#/usr/bin/env bash -# -# Environment Variables: -# NEMU_HOME -set -x - -STUID=ysyx_22040000 -STUNAME=李心杨 - -TRACER=tracer-ysyx -GITFLAGS="-q --author=$TRACER --no-verify --allow-empty" - -YSYX_HOME=$NEMU_HOME/.. -WORK_BRANCH=$(git rev-parse --abbrev-ref HEAD) -WORK_INDEX=$YSYX_HOME/.git/index.${WORK_BRANCH} -TRACER_BRANCH=$TRACER - -LOCK_DIR=$YSYX_HOME/.git/ - -git_soft_checkout () { - git checkout --detach -q && git reset --soft $1 -q -- && git checkout $1 -q -- ; -} - -git_commit () { - # create tracer branch if not existent - git branch $TRACER_BRANCH -q 2>/dev/null || true - # backup git index - cp -a .git/index $WORK_INDEX - # switch to tracer branch - git_soft_checkout "$TRACER_BRANCH" - # add files to commit - git add . -A --ignore-errors - # generate commit msg, commit changes in tracer branch - printf "> $1 \n $STUID $STUNAME \n $(uname -a) \n $(uptime)\n" | git commit -F - $GITFLAGS - git_soft_checkout "$WORK_BRANCH" - mv $WORK_INDEX .git/index -} - -git_commit $1 - -# TIMEOUT=2 -# LOCKFILE=$YSYX_HOME/.git/index.lock -# exec {FD}<>$LOCKFILE - -# if ! flock -x -w $TIMEOUT $FD; then -# echo "Failed to obtain a lock within $TIMEOUT seconds" -# echo "Another instance of `basename $0` is probably running." -# exit 1 -# else -# echo "Lock acquired" -# git_commit $1 -# rm -f $WORK_INDEX -# exit 0 -# fi - diff --git a/npc/.gitignore b/npc/.gitignore index 89cb332..fd7efb6 100644 --- a/npc/.gitignore +++ b/npc/.gitignore @@ -1,17 +1,11 @@ -!Makefile -!*.mk -!*.[cSh] -!*.v -!*.cc -!*.cpp -!.gitignore -!README.md build/ +**/project/ +**/target/ *.class *.log .cache/ -.bsp/ +**/.bsp/ .bloop/ .metals/ diff --git a/npc/CMakeLists.txt b/npc/CMakeLists.txt index 925ac2e..ac50117 100644 --- a/npc/CMakeLists.txt +++ b/npc/CMakeLists.txt @@ -1,29 +1,90 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.20) -project(NPC_xin) +project(npc) +set (CMAKE_CXX_STANDARD 11) +cmake_policy(SET CMP0144 NEW) -find_package(verilator) -if (NOT verilator_FOUND) - message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable") -endif() - -if(NOT DEFINED NVBOARD_HOME) - set(NVBOARD_HOME get_filename_component(real_path "../nvboard" REALPATH)) -endif() - -add_library(nvboard STATIC IMPORTED) -set_target_properties(bar PROPERTIES - IMPORTED_LOCATION "${NVBOARD_HOME}/build/nvboard.a" - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/include/libbar" +execute_process( + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "configure npc" + WORKING_DIRECTORY ../ ) -add_executable(Main csrc/main.cpp) -add_executable(Main_nvboard csrc_nvboard/main.cpp) +find_package(SDL2 REQUIRED) +find_package(SDL2_image REQUIRED) -verilate(Main - COVERAGE TRACE - SOURCES build/chisel/Main.sv build/chisel/RegisterFile.sv) +find_package(verilator REQUIRED) -verilate(Main_nvboard - COVERAGE TRACE - SOURCES build/chisel/Main.sv build/chisel/RegisterFile.sv) +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") + +# 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} +) + +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} +) + +add_custom_target( + ChiselBuild + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v +) + +# -- Build NVBoard executable + +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 +) + +add_executable(V${TOPMODULE}_nvboard csrc_nvboard/main.cpp auto_bind.cpp) + +verilate(V${TOPMODULE}_nvboard TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v) + +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) + +install(TARGETS V${TOPMODULE}_nvboard) + +# -- Build Verilator executable and add to test + +add_executable(V${TOPMODULE} csrc/main.cpp) + +verilate(V${TOPMODULE} TRACE COVERAGE THREADS + TOP_MODULE ${TOPMODULE} + PREFIX V${TOPMODULE} + SOURCES ${CMAKE_CURRENT_BINARY_DIR}/vsrc/${TOPMODULE}.v) + +add_dependencies(V${TOPMODULE} ChiselBuild) + +enable_testing() +add_test(NAME V${TOPMODULE} COMMAND V${TOPMODULE}) + +# -- Add build tracking +add_custom_command( + TARGET V${TOPMODULE}_nvboard + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "Build V${TOPMODULE}_nvboard" + WORKING_DIRECTORY ../ +) + +add_custom_command( + TARGET V${TOPMODULE} + COMMAND ${CMAKE_SOURCE_DIR}/../git_commit.sh "Build V${TOPMODULE}" + WORKING_DIRECTORY ../ +) diff --git a/npc/constr/Switch.nxdc b/npc/constr/Switch.nxdc new file mode 100644 index 0000000..11e3e40 --- /dev/null +++ b/npc/constr/Switch.nxdc @@ -0,0 +1,5 @@ +top=Switch + +io_sw_0 (SW0) +io_sw_1 (SW1) +io_out (LD0) diff --git a/npc/build.sbt b/npc/core/build.sbt similarity index 100% rename from npc/build.sbt rename to npc/core/build.sbt diff --git a/npc/core/src/main/scala/Reg.scala b/npc/core/src/main/scala/Reg.scala new file mode 100644 index 0000000..dd5dc4f --- /dev/null +++ b/npc/core/src/main/scala/Reg.scala @@ -0,0 +1,64 @@ +package npc + +import chisel3._ +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 MuxGenerator(width: Int, nInput: Int) extends Module { + require(width >= 0) + require(nInput >= 1) + require(nInput.toBinaryString.map(_ - '0').sum == 1) + + val io = IO(new Bundle { + val in = Input(Vec(nInput, UInt(width.W))) + val sel = Input(UInt(nInput.toBinaryString.reverse.indexOf('1').W)) + val out = Output(UInt(width.W)) + }) + + io.out := io.in(io.sel) +} + +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 Switch extends Module { + val io = IO(new Bundle { + val sw = Input(Vec(2, Bool())) + val out = Output(Bool()) + }) + + io.out := io.sw(0) ^ io.sw(1) +} diff --git a/npc/core/src/test/scala/Reg.scala b/npc/core/src/test/scala/Reg.scala new file mode 100644 index 0000000..e287f48 --- /dev/null +++ b/npc/core/src/test/scala/Reg.scala @@ -0,0 +1,71 @@ +import chisel3._ +import chiseltest._ +import org.scalatest.freespec.AnyFreeSpec + +class RegisterFileSpec extends AnyFreeSpec with ChiselScalatestTester { + "RegisterFile should work" - { + "with 2 read ports" in { + test(new RegisterFile(2)) { c => + def readExpect(addr: Int, value: Int, port: Int = 0): Unit = { + c.io.readAddr(port).poke(addr.U) + c.io.readData(port).expect(value.U) + } + def write(addr: Int, value: Int): Unit = { + c.io.writeEnable.poke(true.B) + c.io.writeData.poke(value.U) + c.io.writeAddr.poke(addr.U) + c.clock.step(1) + c.io.writeEnable.poke(false.B) + } + // everything should be 0 on init + for (i <- 0 until 32) { + readExpect(i, 0, port = 0) + readExpect(i, 0, port = 1) + } + + // write 5 * addr + 3 + for (i <- 0 until 32) { + write(i, 5 * i + 3) + } + + // check that the writes worked + for (i <- 0 until 32) { + readExpect(i, if (i == 0) 0 else 5 * i + 3, port = i % 2) + } + } + } + } +} + +class MuxGeneratorSpec extends AnyFreeSpec with ChiselScalatestTester { + "MuxGenerator should work" - { + "when there are 2 inputs" in { + test(new MuxGenerator(8, 2)) { c => + c.io.in(0).poke(0.U) + c.io.in(1).poke(1.U) + c.io.sel.poke(0.U) + c.io.out.expect(0.U) + c.io.sel.poke(1.U) + c.io.out.expect(1.U) + } + } + "when there are 1024 inputs" in { + test(new MuxGenerator(32, 1024)) { c => + for (i <- 0 until 1024) { + c.io.in(i).poke(i.U) + } + for (i <- 0 until 1024) { + c.io.sel.poke(i.U) + c.io.out.expect(i.U) + } + } + } + } + "MuxGenerator should raise exception" - { + "when nInput is not 2^n" in { + assertThrows[IllegalArgumentException] { + test(new MuxGenerator(8, 3)) { c => } + } + } + } +} diff --git a/npc/csrc/main.cpp b/npc/csrc/main.cpp index f5ce360..9a3f262 100644 --- a/npc/csrc/main.cpp +++ b/npc/csrc/main.cpp @@ -3,14 +3,14 @@ #include #include #include -#include +#include const int MAX_SIM_TIME=100; int main(int argc, char **argv, char **env) { int sim_time = 0; Verilated::commandArgs(argc, argv); - VMain *top = new VMain; + VSwitch *top = new VSwitch; Verilated::traceEverOn(true); VerilatedVcdC *m_trace = new VerilatedVcdC; @@ -18,16 +18,16 @@ int main(int argc, char **argv, char **env) { top->trace(m_trace, 5); m_trace->open("waveform.vcd"); #endif -// for (sim_time = 0; sim_time < MAX_SIM_TIME; sim_time++) { -// CData sw = rand() & 0b11; -// top->sw = sw; -// top->eval(); -// printf("sw0 = %d, sw1 = %d, ledr = %d\n", sw & 0b1, sw >> 1, top->ledr); -// assert(top->ledr == ((sw >> 1) ^ (sw & 0b1)) ); -// #ifdef VERILATOR_TRACE -// m_trace->dump(sim_time); -// #endif -// } + for (sim_time = 0; sim_time < MAX_SIM_TIME; sim_time++) { + top->io_sw_0 = rand() % 2; + top->io_sw_1 = rand() % 2; + top->eval(); + printf("sw0 = %d, sw1 = %d, ledr = %d\n", top->io_sw_0, top->io_sw_1, top->io_out); + assert(top->io_out == (top->io_sw_0 ^ top->io_sw_1)); +#ifdef VERILATOR_TRACE + m_trace->dump(sim_time); +#endif + } #ifdef VERILATOR_TRACE m_trace->close(); #endif diff --git a/npc/csrc_nvboard/main.cpp b/npc/csrc_nvboard/main.cpp index bbb9794..401de4b 100644 --- a/npc/csrc_nvboard/main.cpp +++ b/npc/csrc_nvboard/main.cpp @@ -2,15 +2,16 @@ #include #include #include -#include +#include #include +#include const int MAX_SIM_TIME=100; -void nvboard_bind_all_pins(VMain* top); +void nvboard_bind_all_pins(VSwitch* top); int main(int argc, char **argv, char **env) { - VMain* top = new VMain; + VSwitch *top = new VSwitch; nvboard_bind_all_pins(top); nvboard_init(); diff --git a/npc/flake.lock b/npc/flake.lock index 768b480..8763898 100644 --- a/npc/flake.lock +++ b/npc/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1703013332, - "narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=", + "lastModified": 1704194953, + "narHash": "sha256-RtDKd8Mynhe5CFnVT8s0/0yqtWFMM9LmCzXv/YKxnq4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6", + "rev": "bd645e8668ec6612439a9ee7e71f7eac4099d4f6", "type": "github" }, "original": { @@ -41,11 +41,11 @@ ] }, "locked": { - "lastModified": 1704380403, - "narHash": "sha256-eElBXx8ocUCVg6LuHBUXSfCRKYRZfbwURIXcgL/ciJY=", + "lastModified": 1704450168, + "narHash": "sha256-zOLL35LX83Of64quCyxpyP8rTSO/tgrfHNm52tFo6VU=", "ref": "refs/heads/master", - "rev": "2e7a57373f52999d579dcebb1202dc731d71ef35", - "revCount": 139, + "rev": "beda2a57d946f392d958755c7bb03ac092a20f42", + "revCount": 140, "type": "git", "url": "https://git.xinyang.life/xin/nur.git" }, diff --git a/npc/flake.nix b/npc/flake.nix index 8460afe..24e3790 100644 --- a/npc/flake.nix +++ b/npc/flake.nix @@ -15,31 +15,32 @@ { nur.xin = nur-xin.legacyPackages.${system}; }; in { - devShells.default = pkgs.mkShell { - packages = with pkgs; [ - gtkwave - gdb - bear + devShells.default = with pkgs; mkShell { + packages = [ clang-tools rnix-lsp - sbt - ]; - - nativeBuildInputs = with pkgs; [ - cmake - verilator - scala - nur.xin.nvboard - self.packages.${system}.circt - ]; - - buildInputs = with pkgs; [ + gdb jre ]; - shellHook = '' - export NEMU_HOME=/home/xin/repo/ysyx-workbench/nemu - ''; + inputsFrom = [ self.packages.${system}.default ]; + }; + packages.default = with pkgs; clangStdenv.mkDerivation { + name = "npc"; + version = "0.0.1"; + src = ./.; + nativeBuildInputs = [ + cmake + sbt + nur.xin.nvboard + self.packages.${system}.circt + ]; + buildInputs = [ + verilator + nur.xin.nvboard + ]; + + NEMU_HOME="/home/xin/repo/ysyx-workbench/nemu"; }; # This version (1.43.0) of circt does not exist in nixpkgs diff --git a/npc/vsrc/example.v b/npc/vsrc/example.v deleted file mode 100644 index 4d290d4..0000000 --- a/npc/vsrc/example.v +++ /dev/null @@ -1,6 +0,0 @@ -module top( - input [1:0] sw, - output ledr -); - assign ledr = sw[1] ^ sw[0]; -endmodule \ No newline at end of file